diff --git a/Cargo.lock b/Cargo.lock index a00150a..413061d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,7 +5,107 @@ version = 4 [[package]] name = "ariadne" version = "0.1.0" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "machoke" version = "0.1.0" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "syn" +version = "3.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12df2e0110f65b775f769bb17ef989067a1d931b2eb822bd4346631eeada89f9" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/src/ariadne/Cargo.toml b/src/ariadne/Cargo.toml index adbd789..2d5ae86 100644 --- a/src/ariadne/Cargo.toml +++ b/src/ariadne/Cargo.toml @@ -4,3 +4,5 @@ version = "0.1.0" edition = "2024" [dependencies] +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" diff --git a/third_party/crates/BUILD.bazel b/third_party/crates/BUILD.bazel index ae6a71a..7764686 100644 --- a/third_party/crates/BUILD.bazel +++ b/third_party/crates/BUILD.bazel @@ -29,3 +29,28 @@ filegroup( allow_empty = True, ), ) + +# Workspace Member Dependencies +alias( + name = "serde-1.0.229", + actual = "//third_party/crates/serde-1.0.229:serde", + tags = ["manual"], +) + +alias( + name = "serde", + actual = "//third_party/crates/serde-1.0.229:serde", + tags = ["manual"], +) + +alias( + name = "serde_json-1.0.151", + actual = "//third_party/crates/serde_json-1.0.151:serde_json", + tags = ["manual"], +) + +alias( + name = "serde_json", + actual = "//third_party/crates/serde_json-1.0.151:serde_json", + tags = ["manual"], +) diff --git a/third_party/crates/crates.bzl b/third_party/crates/crates.bzl index 837646b..41e4c7a 100644 --- a/third_party/crates/crates.bzl +++ b/third_party/crates/crates.bzl @@ -310,65 +310,96 @@ def aliases( ############################################################################### _CRATE_EDITIONS = { + "src/ariadne": "2024", "src/machoke": "2024", } _NORMAL_DEPENDENCIES = { + "src/ariadne": { + _COMMON_CONDITION: { + "serde": Label("//third_party/crates/serde-1.0.229:serde"), + "serde_json": Label("//third_party/crates/serde_json-1.0.151:serde_json"), + }, + }, "src/machoke": { }, } _NORMAL_ALIASES = { + "src/ariadne": { + _COMMON_CONDITION: { + }, + }, "src/machoke": { }, } _NORMAL_DEV_DEPENDENCIES = { + "src/ariadne": { + }, "src/machoke": { }, } _NORMAL_DEV_ALIASES = { + "src/ariadne": { + }, "src/machoke": { }, } _PROC_MACRO_DEPENDENCIES = { + "src/ariadne": { + }, "src/machoke": { }, } _PROC_MACRO_ALIASES = { + "src/ariadne": { + }, "src/machoke": { }, } _PROC_MACRO_DEV_DEPENDENCIES = { + "src/ariadne": { + }, "src/machoke": { }, } _PROC_MACRO_DEV_ALIASES = { + "src/ariadne": { + }, "src/machoke": { }, } _BUILD_DEPENDENCIES = { + "src/ariadne": { + }, "src/machoke": { }, } _BUILD_ALIASES = { + "src/ariadne": { + }, "src/machoke": { }, } _BUILD_PROC_MACRO_DEPENDENCIES = { + "src/ariadne": { + }, "src/machoke": { }, } _BUILD_PROC_MACRO_ALIASES = { + "src/ariadne": { + }, "src/machoke": { }, } @@ -390,6 +421,7 @@ _CONDITIONS = { "arm-unknown-linux-musleabi": ["@rules_rust//rust/platform:arm-unknown-linux-musleabi"], "armv7-linux-androideabi": ["@rules_rust//rust/platform:armv7-linux-androideabi"], "armv7-unknown-linux-gnueabi": ["@rules_rust//rust/platform:armv7-unknown-linux-gnueabi"], + "cfg(any())": [], "i686-apple-darwin": ["@rules_rust//rust/platform:i686-apple-darwin"], "i686-linux-android": ["@rules_rust//rust/platform:i686-linux-android"], "i686-pc-windows-msvc": ["@rules_rust//rust/platform:i686-pc-windows-msvc"], diff --git a/third_party/crates/itoa-1.0.18/.cargo-checksum.json b/third_party/crates/itoa-1.0.18/.cargo-checksum.json new file mode 100644 index 0000000..ba44778 --- /dev/null +++ b/third_party/crates/itoa-1.0.18/.cargo-checksum.json @@ -0,0 +1 @@ +{"$comment":"This file only protects against accidental modifications. It is not a security mechanism and does not protect against malicious changes.","files":{".cargo_vcs_info.json":"e0165305f3b22a9ab4217a121f85379aa56c2675caa7afedc0a7468fc187600b",".github/FUNDING.yml":"b017158736b3c9751a2d21edfce7fe61c8954e2fced8da8dd3013c2f3e295bd9",".github/workflows/ci.yml":"89c4f60223daf03217ea7c1e8879135b11d2554bd1e57dd9eff5c02f1adc7909","Cargo.lock":"1cd64090b8e883963bb08d91e6968cc1e83ffdba4f4b2f47651ce9d351a8a947","Cargo.toml":"894c215e4e7e973b556b0e9627bf9b6a719a043fac9b5af9838660816392a09f","Cargo.toml.orig":"44ca1ae5d9b48743305b57f3367051289512037e7836b8b3693b68d48dec0483","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"1305bd79675db0194915d9bc91bd0b3cf9487bc1126e05bf46b48ab43edce44b","benches/bench.rs":"29a0bdb973848007d681e571c57487e21e1bfb7aed5980c2190dba354498b154","src/lib.rs":"e962338e1886873aa7c3399ec89aa5378ccbfed712b9690f043628079390a34f","src/u128_ext.rs":"498cc94f13805e551248fd82f47cc318f51d953a5002a9f8698858cd12fbae3c","tests/test.rs":"b22f8a8ed89edcbb4140b74f5edd7f2adf3cb0e363990dd6010cd6ebe0dc36b7"},"package":"8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"} \ No newline at end of file diff --git a/third_party/crates/itoa-1.0.18/.cargo_vcs_info.json b/third_party/crates/itoa-1.0.18/.cargo_vcs_info.json new file mode 100644 index 0000000..c084258 --- /dev/null +++ b/third_party/crates/itoa-1.0.18/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "af77385d0daf4d0e949e81f2588be2e44f69f086" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/third_party/crates/itoa-1.0.18/.github/FUNDING.yml b/third_party/crates/itoa-1.0.18/.github/FUNDING.yml new file mode 100644 index 0000000..7507077 --- /dev/null +++ b/third_party/crates/itoa-1.0.18/.github/FUNDING.yml @@ -0,0 +1 @@ +github: dtolnay diff --git a/third_party/crates/itoa-1.0.18/.github/workflows/ci.yml b/third_party/crates/itoa-1.0.18/.github/workflows/ci.yml new file mode 100644 index 0000000..6b7c03d --- /dev/null +++ b/third_party/crates/itoa-1.0.18/.github/workflows/ci.yml @@ -0,0 +1,126 @@ +name: CI + +on: + push: + pull_request: + workflow_dispatch: + schedule: [cron: "40 1 * * *"] + +permissions: + contents: read + +env: + RUSTFLAGS: -Dwarnings + +jobs: + pre_ci: + uses: dtolnay/.github/.github/workflows/pre_ci.yml@master + + test: + name: Rust ${{matrix.rust}} + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + rust: [nightly, beta, stable, 1.86.0] + timeout-minutes: 45 + steps: + - uses: actions/checkout@v6 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{matrix.rust}} + - name: Enable type layout randomization + run: echo RUSTFLAGS=${RUSTFLAGS}\ -Zrandomize-layout >> $GITHUB_ENV + if: matrix.rust == 'nightly' + - run: cargo build + - run: cargo test + - run: cargo test --release + - run: cargo build --no-default-features + - run: cargo test --tests --no-default-features + - run: cargo test --tests --no-default-features --release + - run: cargo build --tests --features no-panic --release + if: matrix.rust == 'nightly' + - run: cargo bench --no-run + if: matrix.rust == 'nightly' + - uses: actions/upload-artifact@v6 + if: matrix.rust == 'nightly' && always() + with: + name: Cargo.lock + path: Cargo.lock + continue-on-error: true + + msrv: + name: Rust 1.68.0 + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@v6 + - uses: dtolnay/rust-toolchain@1.68 + - run: cargo build + - run: cargo build --no-default-features + + doc: + name: Documentation + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + timeout-minutes: 45 + env: + RUSTDOCFLAGS: -Dwarnings + steps: + - uses: actions/checkout@v6 + - uses: dtolnay/rust-toolchain@nightly + - uses: dtolnay/install@cargo-docs-rs + - run: cargo docs-rs + + miri: + name: Miri + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@v6 + - uses: dtolnay/rust-toolchain@miri + - run: cargo miri setup + - run: cargo miri test + env: + MIRIFLAGS: -Zmiri-strict-provenance + + clippy: + name: Clippy + runs-on: ubuntu-latest + if: github.event_name != 'pull_request' + timeout-minutes: 45 + steps: + - uses: actions/checkout@v6 + - uses: dtolnay/rust-toolchain@clippy + - run: cargo clippy --tests --benches -- -Dclippy::all -Dclippy::pedantic + + fuzz: + name: Fuzz + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@v6 + - uses: dtolnay/rust-toolchain@nightly + - uses: dtolnay/install@cargo-fuzz + - run: cargo fuzz check + + 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 + - run: cargo outdated --manifest-path fuzz/Cargo.toml --exit-code 1 diff --git a/third_party/crates/itoa-1.0.18/BUILD.bazel b/third_party/crates/itoa-1.0.18/BUILD.bazel new file mode 100644 index 0000000..42bb35e --- /dev/null +++ b/third_party/crates/itoa-1.0.18/BUILD.bazel @@ -0,0 +1,110 @@ +############################################################################### +# @generated +# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To +# regenerate this file, run the following: +# +# bazel run @@//third_party:vendor_crates +############################################################################### + +load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") +load("@rules_rust//rust:defs.bzl", "rust_library") + +package(default_visibility = ["//visibility:public"]) + +cargo_toml_env_vars( + name = "cargo_toml_env_vars", + src = "Cargo.toml", +) + +rust_library( + name = "itoa", + srcs = glob( + include = ["**/*.rs"], + allow_empty = False, + ), + compile_data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + crate_root = "src/lib.rs", + edition = "2021", + rustc_env_files = [ + ":cargo_toml_env_vars", + ], + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=itoa", + "manual", + "noclippy", + "norustfmt", + ], + target_compatible_with = select({ + "@rules_rust//rust/platform:aarch64-apple-darwin": [], + "@rules_rust//rust/platform:aarch64-apple-ios": [], + "@rules_rust//rust/platform:aarch64-apple-ios-macabi": [], + "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], + "@rules_rust//rust/platform:aarch64-linux-android": [], + "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], + "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], + "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-none": [], + "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], + "@rules_rust//rust/platform:aarch64-unknown-uefi": [], + "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], + "@rules_rust//rust/platform:armv7-linux-androideabi": [], + "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:i686-apple-darwin": [], + "@rules_rust//rust/platform:i686-linux-android": [], + "@rules_rust//rust/platform:i686-pc-windows-msvc": [], + "@rules_rust//rust/platform:i686-unknown-freebsd": [], + "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], + "@rules_rust//rust/platform:loongarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:mips-unknown-linux-gnu": [], + "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv32imac-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], + "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-netbsd": [], + "@rules_rust//rust/platform:sparc64-unknown-openbsd": [], + "@rules_rust//rust/platform:thumbv6m-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabihf": [], + "@rules_rust//rust/platform:thumbv7m-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabihf": [], + "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], + "@rules_rust//rust/platform:wasm32-unknown-unknown": [], + "@rules_rust//rust/platform:wasm32-wasip1": [], + "@rules_rust//rust/platform:wasm32-wasip1-threads": [], + "@rules_rust//rust/platform:wasm32-wasip2": [], + "@rules_rust//rust/platform:x86_64-apple-darwin": [], + "@rules_rust//rust/platform:x86_64-apple-ios": [], + "@rules_rust//rust/platform:x86_64-apple-ios-macabi": [], + "@rules_rust//rust/platform:x86_64-linux-android": [], + "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], + "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], + "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], + "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-none": [], + "@rules_rust//rust/platform:x86_64-unknown-uefi": [], + "//conditions:default": ["@platforms//:incompatible"], + }), + version = "1.0.18", +) diff --git a/third_party/crates/itoa-1.0.18/Cargo.lock b/third_party/crates/itoa-1.0.18/Cargo.lock new file mode 100644 index 0000000..8954517 --- /dev/null +++ b/third_party/crates/itoa-1.0.18/Cargo.lock @@ -0,0 +1,460 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloca" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7d05ea6aea7e9e64d25b9156ba2fee3fdd659e34e41063cd2fc7cd020d7f4" +dependencies = [ + "cc", +] + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cc" +version = "1.2.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +dependencies = [ + "anstyle", + "clap_lex", +] + +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + +[[package]] +name = "criterion" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "950046b2aa2492f9a536f5f4f9a3de7b9e2476e575e05bd6c333371add4d98f3" +dependencies = [ + "alloca", + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "itertools", + "num-traits", + "oorandom", + "page_size", + "regex", + "serde", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8d80a2f4f5b554395e47b5d8305bc3d27813bacb73493eb1001e8f76dae29ea" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "itoa" +version = "1.0.18" +dependencies = [ + "criterion", + "no-panic", +] + +[[package]] +name = "libc" +version = "0.2.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "no-panic" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f967505aabc8af5752d098c34146544a43684817cdba8f9725b292530cabbf53" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "oorandom" +version = "11.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" + +[[package]] +name = "page_size" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa 1.0.17", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "zerocopy" +version = "0.8.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efbb2a062be311f2ba113ce66f697a4dc589f85e78a4aea276200804cea0ed87" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e8bc7269b54418e7aeeef514aa68f8690b8c0489a06b0136e5f57c4c5ccab89" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/third_party/crates/itoa-1.0.18/Cargo.toml b/third_party/crates/itoa-1.0.18/Cargo.toml new file mode 100644 index 0000000..d60aa96 --- /dev/null +++ b/third_party/crates/itoa-1.0.18/Cargo.toml @@ -0,0 +1,66 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.68" +name = "itoa" +version = "1.0.18" +authors = ["David Tolnay "] +build = false +exclude = ["*.png"] +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Fast integer primitive to string conversion" +documentation = "https://docs.rs/itoa" +readme = "README.md" +keywords = ["integer"] +categories = [ + "value-formatting", + "no-std", + "no-std::no-alloc", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/dtolnay/itoa" + +[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", +] + +[lib] +name = "itoa" +path = "src/lib.rs" + +[[test]] +name = "test" +path = "tests/test.rs" + +[[bench]] +name = "bench" +path = "benches/bench.rs" +harness = false + +[dependencies.no-panic] +version = "0.1" +optional = true + +[target."cfg(not(miri))".dev-dependencies.criterion] +version = "0.8" +default-features = false diff --git a/third_party/crates/itoa-1.0.18/Cargo.toml.orig b/third_party/crates/itoa-1.0.18/Cargo.toml.orig new file mode 100644 index 0000000..d8bd99a --- /dev/null +++ b/third_party/crates/itoa-1.0.18/Cargo.toml.orig @@ -0,0 +1,33 @@ +[package] +name = "itoa" +version = "1.0.18" +authors = ["David Tolnay "] +categories = ["value-formatting", "no-std", "no-std::no-alloc"] +description = "Fast integer primitive to string conversion" +documentation = "https://docs.rs/itoa" +edition = "2021" +exclude = ["*.png"] +keywords = ["integer"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/dtolnay/itoa" +rust-version = "1.68" + +[dependencies] +no-panic = { version = "0.1", optional = true } + +[target.'cfg(not(miri))'.dev-dependencies] +criterion = { version = "0.8", default-features = false } + +[[bench]] +name = "bench" +harness = false + +[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", +] diff --git a/third_party/crates/itoa-1.0.18/LICENSE-APACHE b/third_party/crates/itoa-1.0.18/LICENSE-APACHE new file mode 100644 index 0000000..1b5ec8b --- /dev/null +++ b/third_party/crates/itoa-1.0.18/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/third_party/crates/itoa-1.0.18/LICENSE-MIT b/third_party/crates/itoa-1.0.18/LICENSE-MIT new file mode 100644 index 0000000..31aa793 --- /dev/null +++ b/third_party/crates/itoa-1.0.18/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/crates/itoa-1.0.18/README.md b/third_party/crates/itoa-1.0.18/README.md new file mode 100644 index 0000000..c539202 --- /dev/null +++ b/third_party/crates/itoa-1.0.18/README.md @@ -0,0 +1,65 @@ +itoa +==== + +[github](https://github.com/dtolnay/itoa) +[crates.io](https://crates.io/crates/itoa) +[docs.rs](https://docs.rs/itoa) +[build status](https://github.com/dtolnay/itoa/actions?query=branch%3Amaster) + +This crate provides a fast conversion of integer primitives to decimal strings. +The implementation comes straight from [libcore] but avoids the performance +penalty of going through [`core::fmt::Formatter`]. + +See also [`zmij`] for printing floating point primitives. + +[libcore]: https://github.com/rust-lang/rust/blob/1.92.0/library/core/src/fmt/num.rs#L190-L253 +[`core::fmt::Formatter`]: https://doc.rust-lang.org/std/fmt/struct.Formatter.html +[`zmij`]: https://github.com/dtolnay/zmij + +```toml +[dependencies] +itoa = "1.0" +``` + +
+ +## Example + +```rust +fn main() { + let mut buffer = itoa::Buffer::new(); + let printed = buffer.format(128u64); + assert_eq!(printed, "128"); +} +``` + +
+ +## Performance + +The [itoa-benchmark] compares this library and other Rust integer formatting +implementations across a range of integer sizes. The vertical axis in this chart +shows nanoseconds taken by a single execution of +`itoa::Buffer::new().format(value)` so a lower result indicates a faster +library. + +[itoa-benchmark]: https://github.com/dtolnay/itoa-benchmark + +![performance](https://raw.githubusercontent.com/dtolnay/itoa/master/itoa-benchmark.png) + +
+ +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + diff --git a/third_party/crates/itoa-1.0.18/benches/bench.rs b/third_party/crates/itoa-1.0.18/benches/bench.rs new file mode 100644 index 0000000..bfd3192 --- /dev/null +++ b/third_party/crates/itoa-1.0.18/benches/bench.rs @@ -0,0 +1,41 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use std::fmt::Display; +use std::hint; +use std::io::Write; + +fn do_bench(c: &mut Criterion, group_name: &str, int: impl itoa::Integer + Display) { + let mut group = c.benchmark_group(group_name); + group.bench_function("itoa", |b| { + let mut buf = itoa::Buffer::new(); + b.iter(move || { + let int = hint::black_box(int); + let formatted = buf.format(int); + hint::black_box(formatted); + }); + }); + group.bench_function("std::fmt", |b| { + let mut buf = Vec::with_capacity(20); + b.iter(|| { + buf.clear(); + let int = hint::black_box(int); + write!(&mut buf, "{int}").unwrap(); + hint::black_box(buf.as_slice()); + }); + }); + group.finish(); +} + +fn bench(c: &mut Criterion) { + do_bench(c, "u64[0]", 0u64); + do_bench(c, "u64[half]", u64::from(u32::MAX)); + do_bench(c, "u64[max]", u64::MAX); + + do_bench(c, "i16[0]", 0i16); + do_bench(c, "i16[min]", i16::MIN); + + do_bench(c, "u128[0]", 0u128); + do_bench(c, "u128[max]", u128::MAX); +} + +criterion_group!(benches, bench); +criterion_main!(benches); diff --git a/third_party/crates/itoa-1.0.18/src/lib.rs b/third_party/crates/itoa-1.0.18/src/lib.rs new file mode 100644 index 0000000..74cd9b4 --- /dev/null +++ b/third_party/crates/itoa-1.0.18/src/lib.rs @@ -0,0 +1,466 @@ +//! [![github]](https://github.com/dtolnay/itoa) [![crates-io]](https://crates.io/crates/itoa) [![docs-rs]](https://docs.rs/itoa) +//! +//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github +//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust +//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs +//! +//!
+//! +//! This crate provides a fast conversion of integer primitives to decimal +//! strings. The implementation comes straight from [libcore] but avoids the +//! performance penalty of going through [`core::fmt::Formatter`]. +//! +//! See also [`zmij`] for printing floating point primitives. +//! +//! [libcore]: https://github.com/rust-lang/rust/blob/1.92.0/library/core/src/fmt/num.rs#L190-L253 +//! [`zmij`]: https://github.com/dtolnay/zmij +//! +//! # Example +//! +//! ``` +//! fn main() { +//! let mut buffer = itoa::Buffer::new(); +//! let printed = buffer.format(128u64); +//! assert_eq!(printed, "128"); +//! } +//! ``` +//! +//! # Performance +//! +//! The [itoa-benchmark] compares this library and other Rust integer formatting +//! implementations across a range of integer sizes. The vertical axis in this +//! chart shows nanoseconds taken by a single execution of +//! `itoa::Buffer::new().format(value)` so a lower result indicates a faster +//! library. +//! +//! [itoa-benchmark]: https://github.com/dtolnay/itoa-benchmark +//! +//! ![performance](https://raw.githubusercontent.com/dtolnay/itoa/master/itoa-benchmark.png) + +#![doc(html_root_url = "https://docs.rs/itoa/1.0.18")] +#![no_std] +#![allow( + clippy::cast_lossless, + clippy::cast_possible_truncation, + clippy::cast_sign_loss, + clippy::expl_impl_clone_on_copy, + clippy::identity_op, + clippy::items_after_statements, + clippy::must_use_candidate, + clippy::needless_doctest_main, + clippy::unreadable_literal +)] + +mod u128_ext; + +use core::hint; +use core::mem::{self, MaybeUninit}; +use core::str; +#[cfg(feature = "no-panic")] +use no_panic::no_panic; + +/// A correctly sized stack allocation for the formatted integer to be written +/// into. +/// +/// # Example +/// +/// ``` +/// let mut buffer = itoa::Buffer::new(); +/// let printed = buffer.format(1234); +/// assert_eq!(printed, "1234"); +/// ``` +pub struct Buffer { + bytes: [MaybeUninit; i128::MAX_STR_LEN], +} + +impl Default for Buffer { + #[inline] + fn default() -> Buffer { + Buffer::new() + } +} + +impl Copy for Buffer {} + +#[allow(clippy::non_canonical_clone_impl)] +impl Clone for Buffer { + #[inline] + fn clone(&self) -> Self { + Buffer::new() + } +} + +impl Buffer { + /// This is a cheap operation; you don't need to worry about reusing buffers + /// for efficiency. + #[inline] + #[cfg_attr(feature = "no-panic", no_panic)] + pub fn new() -> Buffer { + let bytes = [MaybeUninit::::uninit(); i128::MAX_STR_LEN]; + Buffer { bytes } + } + + /// Print an integer into this buffer and return a reference to its string + /// representation within the buffer. + #[cfg_attr(feature = "no-panic", no_panic)] + pub fn format(&mut self, i: I) -> &str { + let buf_ptr = self.bytes.as_mut_ptr().cast::(); + let string = i.write(unsafe { &mut *buf_ptr }); + if string.len() > I::MAX_STR_LEN { + unsafe { hint::unreachable_unchecked() }; + } + string + } +} + +/// An integer that can be written into an [`itoa::Buffer`][Buffer]. +/// +/// This trait is sealed and cannot be implemented for types outside of itoa. +pub trait Integer: private::Sealed { + /// The maximum length of string that formatting an integer of this type can + /// produce on the current target platform. + const MAX_STR_LEN: usize; +} + +// Seal to prevent downstream implementations of the Integer trait. +mod private { + #[doc(hidden)] + pub trait Sealed: Copy { + #[doc(hidden)] + type Buffer: 'static; + fn write(self, buf: &mut Self::Buffer) -> &str; + } +} + +macro_rules! impl_Integer { + ($Signed:ident, $Unsigned:ident) => { + const _: () = { + assert!($Signed::MIN < 0, "need signed"); + assert!($Unsigned::MIN == 0, "need unsigned"); + assert!($Signed::BITS == $Unsigned::BITS, "need counterparts"); + }; + + impl Integer for $Unsigned { + const MAX_STR_LEN: usize = $Unsigned::MAX.ilog10() as usize + 1; + } + + impl private::Sealed for $Unsigned { + type Buffer = [MaybeUninit; Self::MAX_STR_LEN]; + + #[inline] + #[cfg_attr(feature = "no-panic", no_panic)] + fn write(self, buf: &mut Self::Buffer) -> &str { + let offset = Unsigned::fmt(self, buf); + // SAFETY: Starting from `offset`, all elements of the slice have been set. + unsafe { slice_buffer_to_str(buf, offset) } + } + } + + impl Integer for $Signed { + const MAX_STR_LEN: usize = $Signed::MAX.ilog10() as usize + 2; + } + + impl private::Sealed for $Signed { + type Buffer = [MaybeUninit; Self::MAX_STR_LEN]; + + #[inline] + #[cfg_attr(feature = "no-panic", no_panic)] + fn write(self, buf: &mut Self::Buffer) -> &str { + let mut offset = Self::MAX_STR_LEN - $Unsigned::MAX_STR_LEN; + offset += Unsigned::fmt( + self.unsigned_abs(), + (&mut buf[offset..]).try_into().unwrap(), + ); + if self < 0 { + offset -= 1; + buf[offset].write(b'-'); + } + // SAFETY: Starting from `offset`, all elements of the slice have been set. + unsafe { slice_buffer_to_str(buf, offset) } + } + } + }; +} + +impl_Integer!(i8, u8); +impl_Integer!(i16, u16); +impl_Integer!(i32, u32); +impl_Integer!(i64, u64); +impl_Integer!(i128, u128); + +macro_rules! impl_Integer_size { + ($t:ty as $primitive:ident #[cfg(target_pointer_width = $width:literal)]) => { + #[cfg(target_pointer_width = $width)] + impl Integer for $t { + const MAX_STR_LEN: usize = <$primitive as Integer>::MAX_STR_LEN; + } + + #[cfg(target_pointer_width = $width)] + impl private::Sealed for $t { + type Buffer = <$primitive as private::Sealed>::Buffer; + + #[inline] + #[cfg_attr(feature = "no-panic", no_panic)] + fn write(self, buf: &mut Self::Buffer) -> &str { + (self as $primitive).write(buf) + } + } + }; +} + +impl_Integer_size!(isize as i16 #[cfg(target_pointer_width = "16")]); +impl_Integer_size!(usize as u16 #[cfg(target_pointer_width = "16")]); +impl_Integer_size!(isize as i32 #[cfg(target_pointer_width = "32")]); +impl_Integer_size!(usize as u32 #[cfg(target_pointer_width = "32")]); +impl_Integer_size!(isize as i64 #[cfg(target_pointer_width = "64")]); +impl_Integer_size!(usize as u64 #[cfg(target_pointer_width = "64")]); + +#[repr(C, align(2))] +struct DecimalPairs([u8; 200]); + +// The string of all two-digit numbers in range 00..99 is used as a lookup table. +static DECIMAL_PAIRS: DecimalPairs = DecimalPairs( + *b"0001020304050607080910111213141516171819\ + 2021222324252627282930313233343536373839\ + 4041424344454647484950515253545556575859\ + 6061626364656667686970717273747576777879\ + 8081828384858687888990919293949596979899", +); + +// Returns {value / 100, value % 100} correct for values of up to 4 digits. +fn divmod100(value: u32) -> (u32, u32) { + debug_assert!(value < 10_000); + const EXP: u32 = 19; // 19 is faster or equal to 12 even for 3 digits. + const SIG: u32 = (1 << EXP) / 100 + 1; + let div = (value * SIG) >> EXP; // value / 100 + (div, value - div * 100) +} + +/// This function converts a slice of ascii characters into a `&str` starting +/// from `offset`. +/// +/// # Safety +/// +/// `buf` content starting from `offset` index MUST BE initialized and MUST BE +/// ascii characters. +#[cfg_attr(feature = "no-panic", no_panic)] +unsafe fn slice_buffer_to_str(buf: &[MaybeUninit], offset: usize) -> &str { + // SAFETY: `offset` is always included between 0 and `buf`'s length. + let written = unsafe { buf.get_unchecked(offset..) }; + // SAFETY: (`assume_init_ref`) All buf content since offset is set. + // SAFETY: (`from_utf8_unchecked`) Writes use ASCII from the lookup table exclusively. + unsafe { str::from_utf8_unchecked(&*(written as *const [MaybeUninit] as *const [u8])) } +} + +trait Unsigned: Integer { + fn fmt(self, buf: &mut Self::Buffer) -> usize; +} + +macro_rules! impl_Unsigned { + ($Unsigned:ident) => { + impl Unsigned for $Unsigned { + #[cfg_attr(feature = "no-panic", no_panic)] + fn fmt(self, buf: &mut Self::Buffer) -> usize { + // Count the number of bytes in buf that are not initialized. + let mut offset = buf.len(); + // Consume the least-significant decimals from a working copy. + let mut remain = self; + + // Format per four digits from the lookup table. + // Four digits need a 16-bit $Unsigned or wider. + while mem::size_of::() > 1 + && remain + > 999 + .try_into() + .expect("branch is not hit for types that cannot fit 999 (u8)") + { + offset -= 4; + + // pull two pairs + let scale: Self = 1_00_00 + .try_into() + .expect("branch is not hit for types that cannot fit 1E4 (u8)"); + let quad = remain % scale; + remain /= scale; + let (pair1, pair2) = divmod100(quad as u32); + unsafe { + buf[offset + 0] + .write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 0)); + buf[offset + 1] + .write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 1)); + buf[offset + 2] + .write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 0)); + buf[offset + 3] + .write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 1)); + } + } + + // Format per two digits from the lookup table. + if remain > 9 { + offset -= 2; + + let (last, pair) = divmod100(remain as u32); + remain = last as Self; + unsafe { + buf[offset + 0] + .write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 + 0)); + buf[offset + 1] + .write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 + 1)); + } + } + + // Format the last remaining digit, if any. + if remain != 0 || self == 0 { + offset -= 1; + + // Either the compiler sees that remain < 10, or it prevents + // a boundary check up next. + let last = remain as u8 & 15; + buf[offset].write(b'0' + last); + // not used: remain = 0; + } + + offset + } + } + }; +} + +impl_Unsigned!(u8); +impl_Unsigned!(u16); +impl_Unsigned!(u32); +impl_Unsigned!(u64); + +impl Unsigned for u128 { + #[cfg_attr(feature = "no-panic", no_panic)] + fn fmt(self, buf: &mut Self::Buffer) -> usize { + // Optimize common-case zero, which would also need special treatment due to + // its "leading" zero. + if self == 0 { + let offset = buf.len() - 1; + buf[offset].write(b'0'); + return offset; + } + // Take the 16 least-significant decimals. + let (quot_1e16, mod_1e16) = div_rem_1e16(self); + let (mut remain, mut offset) = if quot_1e16 == 0 { + (mod_1e16, u128::MAX_STR_LEN) + } else { + // Write digits at buf[23..39]. + enc_16lsd::<{ u128::MAX_STR_LEN - 16 }>(buf, mod_1e16); + + // Take another 16 decimals. + let (quot2, mod2) = div_rem_1e16(quot_1e16); + if quot2 == 0 { + (mod2, u128::MAX_STR_LEN - 16) + } else { + // Write digits at buf[7..23]. + enc_16lsd::<{ u128::MAX_STR_LEN - 32 }>(buf, mod2); + // Quot2 has at most 7 decimals remaining after two 1e16 divisions. + (quot2 as u64, u128::MAX_STR_LEN - 32) + } + }; + + // Format per four digits from the lookup table. + while remain > 999 { + offset -= 4; + + // pull two pairs + let quad = remain % 1_00_00; + remain /= 1_00_00; + let (pair1, pair2) = divmod100(quad as u32); + unsafe { + buf[offset + 0].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 0)); + buf[offset + 1].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 1)); + buf[offset + 2].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 0)); + buf[offset + 3].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 1)); + } + } + + // Format per two digits from the lookup table. + if remain > 9 { + offset -= 2; + + let (last, pair) = divmod100(remain as u32); + remain = last as u64; + unsafe { + buf[offset + 0].write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 + 0)); + buf[offset + 1].write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 + 1)); + } + } + + // Format the last remaining digit, if any. + if remain != 0 { + offset -= 1; + + // Either the compiler sees that remain < 10, or it prevents + // a boundary check up next. + let last = remain as u8 & 15; + buf[offset].write(b'0' + last); + // not used: remain = 0; + } + offset + } +} + +// Encodes the 16 least-significant decimals of n into `buf[OFFSET..OFFSET + 16]`. +#[cfg_attr(feature = "no-panic", no_panic)] +fn enc_16lsd(buf: &mut [MaybeUninit], n: u64) { + // Consume the least-significant decimals from a working copy. + let mut remain = n; + + // Format per four digits from the lookup table. + for quad_index in (1..4).rev() { + // pull two pairs + let quad = remain % 1_00_00; + remain /= 1_00_00; + let (pair1, pair2) = divmod100(quad as u32); + unsafe { + buf[quad_index * 4 + OFFSET + 0] + .write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 0)); + buf[quad_index * 4 + OFFSET + 1] + .write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 1)); + buf[quad_index * 4 + OFFSET + 2] + .write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 0)); + buf[quad_index * 4 + OFFSET + 3] + .write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 1)); + } + } + + // final two pairs + let (pair1, pair2) = divmod100(remain as u32); + unsafe { + buf[OFFSET + 0].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 0)); + buf[OFFSET + 1].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 1)); + buf[OFFSET + 2].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 0)); + buf[OFFSET + 3].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 1)); + } +} + +// Euclidean division plus remainder with constant 1E16 basically consumes 16 +// decimals from n. +// +// The integer division algorithm is based on the following paper: +// +// T. Granlund and P. Montgomery, “Division by Invariant Integers Using Multiplication” +// in Proc. of the SIGPLAN94 Conference on Programming Language Design and +// Implementation, 1994, pp. 61–72 +// +#[cfg_attr(feature = "no-panic", no_panic)] +fn div_rem_1e16(n: u128) -> (u128, u64) { + const D: u128 = 1_0000_0000_0000_0000; + // The check inlines well with the caller flow. + if n < D { + return (0, n as u64); + } + + // These constant values are computed with the CHOOSE_MULTIPLIER procedure + // from the Granlund & Montgomery paper, using N=128, prec=128 and d=1E16. + const M_HIGH: u128 = 76624777043294442917917351357515459181; + const SH_POST: u8 = 51; + + // n.widening_mul(M_HIGH).1 >> SH_POST + let quot = u128_ext::mulhi(n, M_HIGH) >> SH_POST; + let rem = n - quot * D; + (quot, rem as u64) +} diff --git a/third_party/crates/itoa-1.0.18/src/u128_ext.rs b/third_party/crates/itoa-1.0.18/src/u128_ext.rs new file mode 100644 index 0000000..866a733 --- /dev/null +++ b/third_party/crates/itoa-1.0.18/src/u128_ext.rs @@ -0,0 +1,22 @@ +#[cfg(feature = "no-panic")] +use no_panic::no_panic; + +/// Multiply unsigned 128 bit integers, return upper 128 bits of the result +#[inline] +#[cfg_attr(feature = "no-panic", no_panic)] +pub(crate) fn mulhi(x: u128, y: u128) -> u128 { + let x_lo = x as u64; + let x_hi = (x >> 64) as u64; + let y_lo = y as u64; + let y_hi = (y >> 64) as u64; + + // handle possibility of overflow + let carry = (u128::from(x_lo) * u128::from(y_lo)) >> 64; + let m = u128::from(x_lo) * u128::from(y_hi) + carry; + let high1 = m >> 64; + + let m_lo = m as u64; + let high2 = (u128::from(x_hi) * u128::from(y_lo) + u128::from(m_lo)) >> 64; + + u128::from(x_hi) * u128::from(y_hi) + high1 + high2 +} diff --git a/third_party/crates/itoa-1.0.18/tests/test.rs b/third_party/crates/itoa-1.0.18/tests/test.rs new file mode 100644 index 0000000..c4f0617 --- /dev/null +++ b/third_party/crates/itoa-1.0.18/tests/test.rs @@ -0,0 +1,45 @@ +#![allow(non_snake_case)] + +macro_rules! test { + ($($name:ident($value:expr, $expected:expr))*) => { + $( + #[test] + fn $name() { + let mut buffer = itoa::Buffer::new(); + let s = buffer.format($value); + assert_eq!(s, $expected); + } + )* + } +} + +test! { + test_u64_0(0u64, "0") + test_u64_half(u64::from(u32::MAX), "4294967295") + test_u64_max(u64::MAX, "18446744073709551615") + test_i64_min(i64::MIN, "-9223372036854775808") + + test_i16_0(0i16, "0") + test_i16_min(i16::MIN, "-32768") + + test_u128_0(0u128, "0") + test_u128_max(u128::MAX, "340282366920938463463374607431768211455") + test_i128_min(i128::MIN, "-170141183460469231731687303715884105728") + test_i128_max(i128::MAX, "170141183460469231731687303715884105727") +} + +#[test] +fn test_max_str_len() { + use itoa::Integer as _; + + assert_eq!(i8::MAX_STR_LEN, 4); + assert_eq!(u8::MAX_STR_LEN, 3); + assert_eq!(i16::MAX_STR_LEN, 6); + assert_eq!(u16::MAX_STR_LEN, 5); + assert_eq!(i32::MAX_STR_LEN, 11); + assert_eq!(u32::MAX_STR_LEN, 10); + assert_eq!(i64::MAX_STR_LEN, 20); + assert_eq!(u64::MAX_STR_LEN, 20); + assert_eq!(i128::MAX_STR_LEN, 40); + assert_eq!(u128::MAX_STR_LEN, 39); +} diff --git a/third_party/crates/memchr-2.8.3/.cargo-checksum.json b/third_party/crates/memchr-2.8.3/.cargo-checksum.json new file mode 100644 index 0000000..f33354d --- /dev/null +++ b/third_party/crates/memchr-2.8.3/.cargo-checksum.json @@ -0,0 +1 @@ +{"$comment":"This file only protects against accidental modifications. It is not a security mechanism and does not protect against malicious changes.","files":{".cargo_vcs_info.json":"739b57f156ae78ce5ad0f2bc44ff727f1a9d48e743bc266e8e3ab8c35baa5ecb",".ignore":"ae8b19032d4fc418b99ccae9e7cc3996b1386665d0bd5edc5634a158e7d2f6a2",".vim/coc-settings.json":"cdc5e2b88bddbdbd1b85f21389c4d882720e4c4488ad566c43fccd9124f2e3bf","AI_POLICY.md":"eb058d5b8387f03159cf6ef868100459d7e01f49499733028fcc916bc97c1cc4","CONTRIBUTING.md":"f5b2b4a9a3dbcd9a6f2654eb97dd7135e6af3717b9a3f037a9cbf714e387af76","COPYING":"01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f","Cargo.lock":"54b66d3eabcf4993f06c5b556ab1df0082dd14985529e301124590280dbe0554","Cargo.toml":"a14f68b8fa55f15fd03b15dced37bcf66a0a628f568eedc82817cdb7f9281951","Cargo.toml.orig":"2d004168044e88b00f971e65d7e6c988a555aa00d7ef4d0ceb5b5a9c228fb0c9","LICENSE-MIT":"0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f","README.md":"92a74aaffe011bdaa06fbc34a01686a6eba58ca1322e976759417a547fddf734","UNLICENSE":"7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c","rustfmt.toml":"1ca600239a27401c4a43f363cf3f38183a212affc1f31bff3ae93234bbaec228","src/arch/aarch64/memchr.rs":"5bb70f915084e629d940dbc322f5b9096b2e658cf63fea8a2f6e7550412e73a0","src/arch/aarch64/mod.rs":"44cd1a614bd66f1e66fc86c541d3c3b8d3a14a644c13e8bf816df3f555eac2d4","src/arch/aarch64/neon/memchr.rs":"e8c00b8fb2c7e2711832ae3cedefe59f32ebedd7dfa4d0ec6de2a566c979daea","src/arch/aarch64/neon/mod.rs":"eab6d56c2b2354db4ee395f40282cd49f97e2ab853547be5de6e65fbe1b2f634","src/arch/aarch64/neon/packedpair.rs":"32d3e4cd0dd9b6c8382e5308cbd896d20242c90b12862c44a5de6a8b4d6126df","src/arch/all/memchr.rs":"b0b1214aa573ed5d02ae62a77c42c773065566b50274d4096e37817d65ab1594","src/arch/all/mod.rs":"05f3fc2b069682eb1545fc6366d167bb620a454365dac8b8dd6cde6cd64de18a","src/arch/all/packedpair/default_rank.rs":"abffd1b5b8b7a3be95c03dd1105b905c246a379854dc56f1e846ea7c4408f2c7","src/arch/all/packedpair/mod.rs":"292b66042c5b5c78bba33db6526aeae6904db803d601fcdd29032b87b3eb3754","src/arch/all/rabinkarp.rs":"06038cce1cbead7b088e541ba41bcc1c095c34bde483b7df6ad9f77a49c1063c","src/arch/all/shiftor.rs":"0d79117f52a1e4795843603a3bb0b45397df4ad5e4184bbc923658dab9dc3b5f","src/arch/all/twoway.rs":"0b27eb1cd7402c1375a50466f8f66a68cb2806c3f69a647340b2759793eed4f8","src/arch/generic/memchr.rs":"ee2a77afcbf506655e352eb3cd42451a70cc2c39e3da487b2985638bc09ced3e","src/arch/generic/mod.rs":"1dd75f61e0ea2563b8205a08aaa7b55500130aa331d18b9e9f995724b66c7a39","src/arch/generic/packedpair.rs":"892d6ee28f0f5007c973d11d697e43e6f6888341b15ea95ce4571e9584069dc5","src/arch/mod.rs":"ca3960b7e2ed28d1b3c121710a870430531aad792f64d4dcb4ca4709d6cbda30","src/arch/wasm32/memchr.rs":"d88ac79f891d8530f505f5035062d3da274a05d66c611480c75430d52709d052","src/arch/wasm32/mod.rs":"a20377aa8fe07d68594879101dc73061e4f51d9c8d812b593b1f376e3c8add79","src/arch/wasm32/simd128/memchr.rs":"bac2c4c43fe710c83a6f2b1118fede043be89dd821d4b532907f129f09fdb5cf","src/arch/wasm32/simd128/mod.rs":"c157b373faedbfd65323be432e25bc411d97aa1b7bc58e76048614c7b2bf3bf6","src/arch/wasm32/simd128/packedpair.rs":"288ba6e5eee6a7a8e5e45c64cff1aa5d72d996c2a6bc228be372c75789f08e45","src/arch/x86_64/avx2/memchr.rs":"576ec0c30f49874f7fd9f6caeb490d56132c0fbbaa4d877b1aa532cafce19323","src/arch/x86_64/avx2/mod.rs":"0033d1b712d0b10f0f273ef9aa8caa53e05e49f4c56a64f39af0b9df97eec584","src/arch/x86_64/avx2/packedpair.rs":"87b69cb4301815906127db4f6370f572c7c5d5dad35c0946c00ad888dbcaec8c","src/arch/x86_64/memchr.rs":"4cf0611c926c3016d1b640880ef14e5654a8d1c1b480fe9a5965956be7eeeeef","src/arch/x86_64/mod.rs":"61b2aa876942fd3e78714c2ae21e356c8634545c06995020f443fa50218df027","src/arch/x86_64/sse2/memchr.rs":"0de0444e26d885eaf866220578752aac871e03bebee7b4f5de7fe8a35f5fa97f","src/arch/x86_64/sse2/mod.rs":"38b70ae52a64ec974dbb91d04d6ca8013d9e06d1fe4af852206bbc2faf1c59aa","src/arch/x86_64/sse2/packedpair.rs":"ad893c5ab9525966693e742673fb666f54ff9102949fc91c5e61642c8ad2f110","src/cow.rs":"2b053e393d3841f780425b3b0da5bec4f187603fa7c271b045ecb7d885b23395","src/ext.rs":"210f89d1e32211bc64414cbd56e97b4f56ce8a8832d321d77a9fe519634e27ea","src/lib.rs":"614f778a41e88a29ea0ceb8e92c839dbb6b5a61c967f8bfd962975e18f932c71","src/macros.rs":"3e4b39252bfa471fad384160a43f113ebfec7bec46a85d16f006622881dd2081","src/memchr.rs":"6ae779ec5d00f443075316e0105edf30b489a38e2e96325bec14ccecd014145b","src/memmem/mod.rs":"d869159f0d0c1915d7acc42a6a4aa3c97c049ddc043e6566afeb78ad290995d1","src/memmem/searcher.rs":"84f6a23bef907696cb672e6898c15fb87008058abc100dde58519d8ec5ebca5d","src/tests/memchr/mod.rs":"269f8e4b4f7f5ea458f27a3c174eb1020ffb2484eeba9464170beb51747df69b","src/tests/memchr/naive.rs":"6a0bee033e5edfb5b1d5769a5fa1c78388f7e9ff7bb91cb67f0ad029289e00e7","src/tests/memchr/prop.rs":"1854eea2338c405fe4635aac430f51e10d2069cd37a7489ddaff47da95f8720b","src/tests/mod.rs":"7cec8f809e279310a465c6a7725087970f219a676cc76c83de30c695bb490740","src/tests/packedpair.rs":"b02ec4fbb61a8653cb5f2268c31bc9168b8043347f2abdcc74081acf83b98e15","src/tests/substring/mod.rs":"c7660d10749363ac4687e7da2b5fda60768230425df8ba416c0c28b8d56a5c74","src/tests/substring/naive.rs":"df6f55d165382b8a53762ba4c324926cac13ebc62cde1805f4ce08740b326483","src/tests/substring/prop.rs":"38c15992609b5681a95d838ae6f2933e00a1219f2c971bfba245f96e0729fcdc","src/vector.rs":"9b104d0bda9b8e18b10c41633513637af84346282bf113f3be3813725605fe31"},"package":"cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"} \ No newline at end of file diff --git a/third_party/crates/memchr-2.8.3/.cargo_vcs_info.json b/third_party/crates/memchr-2.8.3/.cargo_vcs_info.json new file mode 100644 index 0000000..eeb3b56 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "5fdb40c054e1fff359a2f7bdf7f87a13b34b465d" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/third_party/crates/memchr-2.8.3/.ignore b/third_party/crates/memchr-2.8.3/.ignore new file mode 100644 index 0000000..47ec474 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/.ignore @@ -0,0 +1 @@ +!.github diff --git a/third_party/crates/memchr-2.8.3/.vim/coc-settings.json b/third_party/crates/memchr-2.8.3/.vim/coc-settings.json new file mode 100644 index 0000000..38f35ce --- /dev/null +++ b/third_party/crates/memchr-2.8.3/.vim/coc-settings.json @@ -0,0 +1,16 @@ +{ + "rust-analyzer.cargo.allFeatures": false, + "rust-analyzer.linkedProjects": [ + "benchmarks/engines/libc/Cargo.toml", + "benchmarks/engines/rust-bytecount/Cargo.toml", + "benchmarks/engines/rust-jetscii/Cargo.toml", + "benchmarks/engines/rust-memchr/Cargo.toml", + "benchmarks/engines/rust-memchrold/Cargo.toml", + "benchmarks/engines/rust-sliceslice/Cargo.toml", + "benchmarks/engines/rust-std/Cargo.toml", + "benchmarks/engines/stringzilla/Cargo.toml", + "benchmarks/shared/Cargo.toml", + "fuzz/Cargo.toml", + "Cargo.toml" + ] +} diff --git a/third_party/crates/memchr-2.8.3/AI_POLICY.md b/third_party/crates/memchr-2.8.3/AI_POLICY.md new file mode 100644 index 0000000..e0ddbaa --- /dev/null +++ b/third_party/crates/memchr-2.8.3/AI_POLICY.md @@ -0,0 +1,38 @@ +# AI Policy + +Using AI (i.e., LLMs) as tools for coding is welcome. A high bar is held for +all contributions to this project. Moreover, the project maintainers remain +responsible for any code that is published as part of a release. Contributors +are expected to be responsible for any code they publish. + +**AI should not be used to generate comments when communicating with +maintainers**. Comments are expected to be written by humans. Comments that are +believed to be written by AI may be hidden without notice. + +If you are opening an issue, you should be able to describe the problem in your +own words. + +If you are opening a pull request, you are expected to be able to explain the +proposed changes in your own words. This includes the pull request body and +responses to questions. **Do not copy responses from the AI when replying to +questions from maintainers.** + +This project requires a human in the loop who understands the work produced +by AI. **Autonomous agents are not allowed to be used for contributing to our +projects**. Pull requests that appear in violation of this will be closed, +perhaps without notice. + +If you wish to include context from an interaction with AI in your comments, it +must be in a quote block (e.g., using `>`) and disclosed as such. It must be +accompanied by human commentary explaining the relevance and implications of +the context. Do not share long snippets. + +AI is useful when communicating as a non-native English speaker. If you are +using AI to edit your comments for this purpose, please take the time to ensure +it reflects your own voice and ideas. If using AI for translation, we recommend +writing in your native language and including the AI translation in a quote +block. + +This policy was adapted from [uv's AI policy]. + +[uv's AI policy]: https://github.com/astral-sh/.github/blob/c5187e200db51bfe11d56e13053d29bd3793fdd8/AI_POLICY.md diff --git a/third_party/crates/memchr-2.8.3/BUILD.bazel b/third_party/crates/memchr-2.8.3/BUILD.bazel new file mode 100644 index 0000000..21426ba --- /dev/null +++ b/third_party/crates/memchr-2.8.3/BUILD.bazel @@ -0,0 +1,114 @@ +############################################################################### +# @generated +# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To +# regenerate this file, run the following: +# +# bazel run @@//third_party:vendor_crates +############################################################################### + +load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") +load("@rules_rust//rust:defs.bzl", "rust_library") + +package(default_visibility = ["//visibility:public"]) + +cargo_toml_env_vars( + name = "cargo_toml_env_vars", + src = "Cargo.toml", +) + +rust_library( + name = "memchr", + srcs = glob( + include = ["**/*.rs"], + allow_empty = False, + ), + compile_data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + crate_features = [ + "alloc", + "std", + ], + crate_root = "src/lib.rs", + edition = "2021", + rustc_env_files = [ + ":cargo_toml_env_vars", + ], + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=memchr", + "manual", + "noclippy", + "norustfmt", + ], + target_compatible_with = select({ + "@rules_rust//rust/platform:aarch64-apple-darwin": [], + "@rules_rust//rust/platform:aarch64-apple-ios": [], + "@rules_rust//rust/platform:aarch64-apple-ios-macabi": [], + "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], + "@rules_rust//rust/platform:aarch64-linux-android": [], + "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], + "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], + "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-none": [], + "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], + "@rules_rust//rust/platform:aarch64-unknown-uefi": [], + "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], + "@rules_rust//rust/platform:armv7-linux-androideabi": [], + "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:i686-apple-darwin": [], + "@rules_rust//rust/platform:i686-linux-android": [], + "@rules_rust//rust/platform:i686-pc-windows-msvc": [], + "@rules_rust//rust/platform:i686-unknown-freebsd": [], + "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], + "@rules_rust//rust/platform:loongarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:mips-unknown-linux-gnu": [], + "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv32imac-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], + "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-netbsd": [], + "@rules_rust//rust/platform:sparc64-unknown-openbsd": [], + "@rules_rust//rust/platform:thumbv6m-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabihf": [], + "@rules_rust//rust/platform:thumbv7m-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabihf": [], + "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], + "@rules_rust//rust/platform:wasm32-unknown-unknown": [], + "@rules_rust//rust/platform:wasm32-wasip1": [], + "@rules_rust//rust/platform:wasm32-wasip1-threads": [], + "@rules_rust//rust/platform:wasm32-wasip2": [], + "@rules_rust//rust/platform:x86_64-apple-darwin": [], + "@rules_rust//rust/platform:x86_64-apple-ios": [], + "@rules_rust//rust/platform:x86_64-apple-ios-macabi": [], + "@rules_rust//rust/platform:x86_64-linux-android": [], + "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], + "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], + "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], + "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-none": [], + "@rules_rust//rust/platform:x86_64-unknown-uefi": [], + "//conditions:default": ["@platforms//:incompatible"], + }), + version = "2.8.3", +) diff --git a/third_party/crates/memchr-2.8.3/CONTRIBUTING.md b/third_party/crates/memchr-2.8.3/CONTRIBUTING.md new file mode 100644 index 0000000..86cb4d0 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/CONTRIBUTING.md @@ -0,0 +1,8 @@ +# Contributing + +## Use of AI + +All use of AI in contributions must follow the +[AI Policy](https://github.com/BurntSushi/jiff/blob/master/AI_POLICY.md). + +Contributions not following the AI Policy will be closed. diff --git a/third_party/crates/memchr-2.8.3/COPYING b/third_party/crates/memchr-2.8.3/COPYING new file mode 100644 index 0000000..bb9c20a --- /dev/null +++ b/third_party/crates/memchr-2.8.3/COPYING @@ -0,0 +1,3 @@ +This project is dual-licensed under the Unlicense and MIT licenses. + +You may use this code under the terms of either license. diff --git a/third_party/crates/memchr-2.8.3/Cargo.lock b/third_party/crates/memchr-2.8.3/Cargo.lock new file mode 100644 index 0000000..ecdaf9b --- /dev/null +++ b/third_party/crates/memchr-2.8.3/Cargo.lock @@ -0,0 +1,80 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.176" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "memchr" +version = "2.8.3" +dependencies = [ + "log", + "quickcheck", + "rustc-std-workspace-core", +] + +[[package]] +name = "quickcheck" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" +dependencies = [ + "rand", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rustc-std-workspace-core" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9c45b374136f52f2d6311062c7146bff20fec063c3f5d46a410bd937746955" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" diff --git a/third_party/crates/memchr-2.8.3/Cargo.toml b/third_party/crates/memchr-2.8.3/Cargo.toml new file mode 100644 index 0000000..a03a2ad --- /dev/null +++ b/third_party/crates/memchr-2.8.3/Cargo.toml @@ -0,0 +1,89 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.61" +name = "memchr" +version = "2.8.3" +authors = [ + "Andrew Gallant ", + "bluss", +] +build = false +exclude = [ + "/.github", + "/benchmarks", + "/fuzz", + "/scripts", + "/tmp", +] +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = """ +Provides extremely fast (uses SIMD on x86_64, aarch64 and wasm32) routines for +1, 2 or 3 byte search and single substring search. +""" +homepage = "https://github.com/BurntSushi/memchr" +documentation = "https://docs.rs/memchr/" +readme = "README.md" +keywords = [ + "memchr", + "memmem", + "substring", + "find", + "search", +] +license = "Unlicense OR MIT" +repository = "https://github.com/BurntSushi/memchr" + +[package.metadata.docs.rs] +rustdoc-args = ["--generate-link-to-definition"] + +[features] +alloc = [] +default = ["std"] +libc = [] +logging = ["dep:log"] +rustc-dep-of-std = ["core"] +std = ["alloc"] +use_std = ["std"] + +[lib] +name = "memchr" +path = "src/lib.rs" +bench = false + +[dependencies.core] +version = "1.0.0" +optional = true +package = "rustc-std-workspace-core" + +[dependencies.log] +version = "0.4.20" +optional = true + +[dev-dependencies.quickcheck] +version = "1.0.3" +default-features = false + +[profile.bench] +debug = 2 + +[profile.release] +debug = 2 + +[profile.test] +opt-level = 3 +debug = 2 diff --git a/third_party/crates/memchr-2.8.3/Cargo.toml.orig b/third_party/crates/memchr-2.8.3/Cargo.toml.orig new file mode 100644 index 0000000..5459969 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/Cargo.toml.orig @@ -0,0 +1,78 @@ +[package] +name = "memchr" +version = "2.8.3" #:version +authors = ["Andrew Gallant ", "bluss"] +description = """ +Provides extremely fast (uses SIMD on x86_64, aarch64 and wasm32) routines for +1, 2 or 3 byte search and single substring search. +""" +documentation = "https://docs.rs/memchr/" +homepage = "https://github.com/BurntSushi/memchr" +repository = "https://github.com/BurntSushi/memchr" +readme = "README.md" +keywords = ["memchr", "memmem", "substring", "find", "search"] +license = "Unlicense OR MIT" +exclude = ["/.github", "/benchmarks", "/fuzz", "/scripts", "/tmp"] +edition = "2021" +rust-version = "1.61" + +[lib] +name = "memchr" +bench = false + +[features] +default = ["std"] + +# The 'std' feature permits the memchr crate to use the standard library. This +# permits this crate to use runtime CPU feature detection to automatically +# accelerate searching via vector instructions. Without the standard library, +# this automatic detection is not possible. +std = ["alloc"] + +# The 'alloc' feature enables some APIs that require allocation, such as +# 'Finder::into_owned'. Note that this feature does not enable runtime CPU +# feature detection. That still requires 'std'. +alloc = [] + +# When enabled (it's disabled by default), the `log` crate will be used to +# emit a spattering of log messages. For the most part, the log messages are +# meant to indicate what strategies are being employed. For example, whether +# a vector or a scalar algorithm is used for substring search. This can be +# useful when debugging performance problems. +# +# This is disabled by default. +logging = ["dep:log"] + +# The 'use_std' feature is DEPRECATED. It will be removed in memchr 3. Until +# then, it is alias for the 'std' feature. +use_std = ["std"] + +# The 'libc' feature has been DEPRECATED and no longer has any effect. +libc = [] + +# Internal feature, only used when building as part of libstd, not part of the +# stable interface of this crate. +rustc-dep-of-std = ['core'] + +[dependencies] +# Only used when the `logging` feature is enabled (disabled by default). +log = { version = "0.4.20", optional = true } +# Internal feature, only used when building as part of libstd, not part of the +# stable interface of this crate. +core = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-core' } + +[dev-dependencies] +quickcheck = { version = "1.0.3", default-features = false } + +[profile.release] +debug = true + +[profile.bench] +debug = true + +[profile.test] +opt-level = 3 +debug = true + +[package.metadata.docs.rs] +rustdoc-args = ["--generate-link-to-definition"] diff --git a/third_party/crates/memchr-2.8.3/LICENSE-MIT b/third_party/crates/memchr-2.8.3/LICENSE-MIT new file mode 100644 index 0000000..3b0a5dc --- /dev/null +++ b/third_party/crates/memchr-2.8.3/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/third_party/crates/memchr-2.8.3/README.md b/third_party/crates/memchr-2.8.3/README.md new file mode 100644 index 0000000..db00ebb --- /dev/null +++ b/third_party/crates/memchr-2.8.3/README.md @@ -0,0 +1,196 @@ +memchr +====== +This library provides heavily optimized routines for string search primitives. + +[![Build status](https://github.com/BurntSushi/memchr/workflows/ci/badge.svg)](https://github.com/BurntSushi/memchr/actions) +[![Crates.io](https://img.shields.io/crates/v/memchr.svg)](https://crates.io/crates/memchr) + +Dual-licensed under MIT or the [UNLICENSE](https://unlicense.org/). + + +### Documentation + +[https://docs.rs/memchr](https://docs.rs/memchr) + + +### Overview + +* The top-level module provides routines for searching for 1, 2 or 3 bytes + in the forward or reverse direction. When searching for more than one byte, + positions are considered a match if the byte at that position matches any + of the bytes. +* The `memmem` sub-module provides forward and reverse substring search + routines. + +In all such cases, routines operate on `&[u8]` without regard to encoding. This +is exactly what you want when searching either UTF-8 or arbitrary bytes. + +### Compiling without the standard library + +memchr links to the standard library by default, but you can disable the +`std` feature if you want to use it in a `#![no_std]` crate: + +```toml +[dependencies] +memchr = { version = "2", default-features = false } +``` + +On `x86_64` platforms, when the `std` feature is disabled, the SSE2 accelerated +implementations will be used. When `std` is enabled, AVX2 accelerated +implementations will be used if the CPU is determined to support it at runtime. + +SIMD accelerated routines are also available on the `wasm32` and `aarch64` +targets. The `std` feature is not required to use them. + +When a SIMD version is not available, then this crate falls back to +[SWAR](https://en.wikipedia.org/wiki/SWAR) techniques. + +### Minimum Rust version policy + +This crate's minimum supported `rustc` version is `1.61.0`. + +The current policy is that the minimum Rust version required to use this crate +can be increased in minor version updates. For example, if `crate 1.0` requires +Rust 1.20.0, then `crate 1.0.z` for all values of `z` will also require Rust +1.20.0 or newer. However, `crate 1.y` for `y > 0` may require a newer minimum +version of Rust. + +In general, this crate will be conservative with respect to the minimum +supported version of Rust. + + +### Testing strategy + +Given the complexity of the code in this crate, along with the pervasive use +of `unsafe`, this crate has an extensive testing strategy. It combines multiple +approaches: + +* Hand-written tests. +* Exhaustive-style testing meant to exercise all possible branching and offset + calculations. +* Property based testing through [`quickcheck`](https://github.com/BurntSushi/quickcheck). +* Fuzz testing through [`cargo fuzz`](https://github.com/rust-fuzz/cargo-fuzz). +* A huge suite of benchmarks that are also run as tests. Benchmarks always + confirm that the expected result occurs. + +Improvements to the testing infrastructure are very welcome. + + +### Algorithms used + +At time of writing, this crate's implementation of substring search actually +has a few different algorithms to choose from depending on the situation. + +* For very small haystacks, + [Rabin-Karp](https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm) + is used to reduce latency. Rabin-Karp has very small overhead and can often + complete before other searchers have even been constructed. +* For small needles, a variant of the + ["Generic SIMD"](http://0x80.pl/articles/simd-strfind.html#algorithm-1-generic-simd) + algorithm is used. Instead of using the first and last bytes, a heuristic is + used to select bytes based on a background distribution of byte frequencies. +* In all other cases, + [Two-Way](https://en.wikipedia.org/wiki/Two-way_string-matching_algorithm) + is used. If possible, a prefilter based on the "Generic SIMD" algorithm + linked above is used to find candidates quickly. A dynamic heuristic is used + to detect if the prefilter is ineffective, and if so, disables it. + + +### Why is the standard library's substring search so much slower? + +We'll start by establishing what the difference in performance actually +is. There are two relevant benchmark classes to consider: `prebuilt` and +`oneshot`. The `prebuilt` benchmarks are designed to measure---to the extent +possible---search time only. That is, the benchmark first starts by building a +searcher and then only tracking the time for _using_ the searcher: + +``` +$ rebar rank benchmarks/record/x86_64/2023-08-26.csv --intersection -e memchr/memmem/prebuilt -e std/memmem/prebuilt +Engine Version Geometric mean of speed ratios Benchmark count +------ ------- ------------------------------ --------------- +rust/memchr/memmem/prebuilt 2.5.0 1.03 53 +rust/std/memmem/prebuilt 1.73.0-nightly 180dffba1 6.50 53 +``` + +Conversely, the `oneshot` benchmark class measures the time it takes to both +build the searcher _and_ use it: + +``` +$ rebar rank benchmarks/record/x86_64/2023-08-26.csv --intersection -e memchr/memmem/oneshot -e std/memmem/oneshot +Engine Version Geometric mean of speed ratios Benchmark count +------ ------- ------------------------------ --------------- +rust/memchr/memmem/oneshot 2.5.0 1.04 53 +rust/std/memmem/oneshot 1.73.0-nightly 180dffba1 5.26 53 +``` + +**NOTE:** Replace `rebar rank` with `rebar cmp` in the above commands to +explore the specific benchmarks and their differences. + +So in both cases, this crate is quite a bit faster over a broad sampling of +benchmarks regardless of whether you measure only search time or search time +plus construction time. The difference is a little smaller when you include +construction time in your measurements. + +These two different types of benchmark classes make for a nice segue into +one reason why the standard library's substring search can be slower: API +design. In the standard library, the only APIs available to you require +one to re-construct the searcher for every search. While you can benefit +from building a searcher once and iterating over all matches in a single +string, you cannot reuse that searcher to search other strings. This might +come up when, for example, searching a file one line at a time. You'll need +to re-build the searcher for every line searched, and this can [really +matter][burntsushi-bstr-blog]. + +**NOTE:** The `prebuilt` benchmark for the standard library can't actually +avoid measuring searcher construction at some level, because there is no API +for it. Instead, the benchmark consists of building the searcher once and then +finding all matches in a single string via an iterator. This tends to +approximate a benchmark where searcher construction isn't measured, but it +isn't perfect. While this means the comparison is not strictly +apples-to-apples, it does reflect what is maximally possible with the standard +library, and thus reflects the best that one could do in a real world scenario. + +While there is more to the story than just API design here, it's important to +point out that even if the standard library's substring search were a precise +clone of this crate internally, it would still be at a disadvantage in some +workloads because of its API. (The same also applies to C's standard library +`memmem` function. There is no way to amortize construction of the searcher. +You need to pay for it on every call.) + +The other reason for the difference in performance is that +the standard library has trouble using SIMD. In particular, substring search +is implemented in the `core` library, where platform specific code generally +can't exist. That's an issue because in order to utilize SIMD beyond SSE2 +while maintaining portable binaries, one needs to use [dynamic CPU feature +detection][dynamic-cpu], and that in turn requires platform specific code. +While there is [an RFC for enabling target feature detection in +`core`][core-feature], it doesn't yet exist. + +The bottom line here is that `core`'s substring search implementation is +limited to making use of SSE2, but not AVX. + +Still though, this crate does accelerate substring search even when only SSE2 +is available. The standard library could therefore adopt the techniques in this +crate just for SSE2. The reason why that hasn't happened yet isn't totally +clear to me. It likely needs a champion to push it through. The standard +library tends to be more conservative in these things. With that said, the +standard library does use some [SSE2 acceleration on `x86-64`][std-sse2] added +in [this PR][std-sse2-pr]. However, at the time of writing, it is only used +for short needles and doesn't use the frequency based heuristics found in this +crate. + +**NOTE:** Another thing worth mentioning is that the standard library's +substring search routine requires that both the needle and haystack have type +`&str`. Unless you can assume that your data is valid UTF-8, building a `&str` +will come with the overhead of UTF-8 validation. This may in turn result in +overall slower searching depending on your workload. In contrast, the `memchr` +crate permits both the needle and the haystack to have type `&[u8]`, where +`&[u8]` can be created from a `&str` with zero cost. Therefore, the substring +search in this crate is strictly more flexible than what the standard library +provides. + +[burntsushi-bstr-blog]: https://blog.burntsushi.net/bstr/#motivation-based-on-performance +[dynamic-cpu]: https://doc.rust-lang.org/std/arch/index.html#dynamic-cpu-feature-detection +[core-feature]: https://github.com/rust-lang/rfcs/pull/3469 +[std-sse2]: https://github.com/rust-lang/rust/blob/bf9229a2e366b4c311f059014a4aa08af16de5d8/library/core/src/str/pattern.rs#L1719-L1857 +[std-sse2-pr]: https://github.com/rust-lang/rust/pull/103779 diff --git a/third_party/crates/memchr-2.8.3/UNLICENSE b/third_party/crates/memchr-2.8.3/UNLICENSE new file mode 100644 index 0000000..68a49da --- /dev/null +++ b/third_party/crates/memchr-2.8.3/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/third_party/crates/memchr-2.8.3/rustfmt.toml b/third_party/crates/memchr-2.8.3/rustfmt.toml new file mode 100644 index 0000000..aa37a21 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/rustfmt.toml @@ -0,0 +1,2 @@ +max_width = 79 +use_small_heuristics = "max" diff --git a/third_party/crates/memchr-2.8.3/src/arch/aarch64/memchr.rs b/third_party/crates/memchr-2.8.3/src/arch/aarch64/memchr.rs new file mode 100644 index 0000000..e0053b2 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/aarch64/memchr.rs @@ -0,0 +1,137 @@ +/*! +Wrapper routines for `memchr` and friends. + +These routines choose the best implementation at compile time. (This is +different from `x86_64` because it is expected that `neon` is almost always +available for `aarch64` targets.) +*/ + +macro_rules! defraw { + ($ty:ident, $find:ident, $start:ident, $end:ident, $($needles:ident),+) => {{ + #[cfg(target_feature = "neon")] + { + use crate::arch::aarch64::neon::memchr::$ty; + + debug!("chose neon for {}", stringify!($ty)); + debug_assert!($ty::is_available()); + // SAFETY: We know that wasm memchr is always available whenever + // code is compiled for `aarch64` with the `neon` target feature + // enabled. + $ty::new_unchecked($($needles),+).$find($start, $end) + } + #[cfg(not(target_feature = "neon"))] + { + use crate::arch::all::memchr::$ty; + + debug!( + "no neon feature available, using fallback for {}", + stringify!($ty), + ); + $ty::new($($needles),+).$find($start, $end) + } + }} +} + +/// memchr, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `One::find_raw`. +#[inline(always)] +pub(crate) unsafe fn memchr_raw( + n1: u8, + start: *const u8, + end: *const u8, +) -> Option<*const u8> { + defraw!(One, find_raw, start, end, n1) +} + +/// memrchr, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `One::rfind_raw`. +#[inline(always)] +pub(crate) unsafe fn memrchr_raw( + n1: u8, + start: *const u8, + end: *const u8, +) -> Option<*const u8> { + defraw!(One, rfind_raw, start, end, n1) +} + +/// memchr2, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `Two::find_raw`. +#[inline(always)] +pub(crate) unsafe fn memchr2_raw( + n1: u8, + n2: u8, + start: *const u8, + end: *const u8, +) -> Option<*const u8> { + defraw!(Two, find_raw, start, end, n1, n2) +} + +/// memrchr2, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `Two::rfind_raw`. +#[inline(always)] +pub(crate) unsafe fn memrchr2_raw( + n1: u8, + n2: u8, + start: *const u8, + end: *const u8, +) -> Option<*const u8> { + defraw!(Two, rfind_raw, start, end, n1, n2) +} + +/// memchr3, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `Three::find_raw`. +#[inline(always)] +pub(crate) unsafe fn memchr3_raw( + n1: u8, + n2: u8, + n3: u8, + start: *const u8, + end: *const u8, +) -> Option<*const u8> { + defraw!(Three, find_raw, start, end, n1, n2, n3) +} + +/// memrchr3, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `Three::rfind_raw`. +#[inline(always)] +pub(crate) unsafe fn memrchr3_raw( + n1: u8, + n2: u8, + n3: u8, + start: *const u8, + end: *const u8, +) -> Option<*const u8> { + defraw!(Three, rfind_raw, start, end, n1, n2, n3) +} + +/// Count all matching bytes, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `One::count_raw`. +#[inline(always)] +pub(crate) unsafe fn count_raw( + n1: u8, + start: *const u8, + end: *const u8, +) -> usize { + defraw!(One, count_raw, start, end, n1) +} diff --git a/third_party/crates/memchr-2.8.3/src/arch/aarch64/mod.rs b/third_party/crates/memchr-2.8.3/src/arch/aarch64/mod.rs new file mode 100644 index 0000000..7b32912 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/aarch64/mod.rs @@ -0,0 +1,7 @@ +/*! +Vector algorithms for the `aarch64` target. +*/ + +pub mod neon; + +pub(crate) mod memchr; diff --git a/third_party/crates/memchr-2.8.3/src/arch/aarch64/neon/memchr.rs b/third_party/crates/memchr-2.8.3/src/arch/aarch64/neon/memchr.rs new file mode 100644 index 0000000..5fcc762 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/aarch64/neon/memchr.rs @@ -0,0 +1,1031 @@ +/*! +This module defines 128-bit vector implementations of `memchr` and friends. + +The main types in this module are [`One`], [`Two`] and [`Three`]. They are for +searching for one, two or three distinct bytes, respectively, in a haystack. +Each type also has corresponding double ended iterators. These searchers are +typically much faster than scalar routines accomplishing the same task. + +The `One` searcher also provides a [`One::count`] routine for efficiently +counting the number of times a single byte occurs in a haystack. This is +useful, for example, for counting the number of lines in a haystack. This +routine exists because it is usually faster, especially with a high match +count, then using [`One::find`] repeatedly. ([`OneIter`] specializes its +`Iterator::count` implementation to use this routine.) + +Only one, two and three bytes are supported because three bytes is about +the point where one sees diminishing returns. Beyond this point and it's +probably (but not necessarily) better to just use a simple `[bool; 256]` array +or similar. However, it depends mightily on the specific work-load and the +expected match frequency. +*/ + +use core::arch::aarch64::uint8x16_t; + +use crate::{arch::generic::memchr as generic, ext::Pointer, vector::Vector}; + +/// Finds all occurrences of a single byte in a haystack. +#[derive(Clone, Copy, Debug)] +pub struct One(generic::One); + +impl One { + /// Create a new searcher that finds occurrences of the needle byte given. + /// + /// This particular searcher is specialized to use neon vector instructions + /// that typically make it quite fast. + /// + /// If neon is unavailable in the current environment, then `None` is + /// returned. + #[inline] + pub fn new(needle: u8) -> Option { + if One::is_available() { + // SAFETY: we check that neon is available above. + unsafe { Some(One::new_unchecked(needle)) } + } else { + None + } + } + + /// Create a new finder specific to neon vectors and routines without + /// checking that neon is available. + /// + /// # Safety + /// + /// Callers must guarantee that it is safe to execute `neon` instructions + /// in the current environment. + /// + /// Note that it is a common misconception that if one compiles for an + /// `x86_64` target, then they therefore automatically have access to neon + /// instructions. While this is almost always the case, it isn't true in + /// 100% of cases. + #[target_feature(enable = "neon")] + #[inline] + pub unsafe fn new_unchecked(needle: u8) -> One { + One(generic::One::new(needle)) + } + + /// Returns true when this implementation is available in the current + /// environment. + /// + /// When this is true, it is guaranteed that [`One::new`] will return + /// a `Some` value. Similarly, when it is false, it is guaranteed that + /// `One::new` will return a `None` value. + /// + /// Note also that for the lifetime of a single program, if this returns + /// true then it will always return true. + #[inline] + pub fn is_available() -> bool { + #[cfg(target_feature = "neon")] + { + true + } + #[cfg(not(target_feature = "neon"))] + { + false + } + } + + /// Return the first occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value is `haystack.len() - 1`. + #[inline] + pub fn find(&self, haystack: &[u8]) -> Option { + // SAFETY: `find_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.find_raw(s, e) + }) + } + } + + /// Return the last occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value is `haystack.len() - 1`. + #[inline] + pub fn rfind(&self, haystack: &[u8]) -> Option { + // SAFETY: `rfind_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.rfind_raw(s, e) + }) + } + } + + /// Counts all occurrences of this byte in the given haystack. + #[inline] + pub fn count(&self, haystack: &[u8]) -> usize { + // SAFETY: All of our pointers are derived directly from a borrowed + // slice, which is guaranteed to be valid. + unsafe { + let start = haystack.as_ptr(); + let end = start.add(haystack.len()); + self.count_raw(start, end) + } + } + + /// Like `find`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn find_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + if end.distance(start) < uint8x16_t::BYTES { + // SAFETY: We require the caller to pass valid start/end pointers. + return generic::fwd_byte_by_byte(start, end, |b| { + b == self.0.needle1() + }); + } + // SAFETY: Building a `One` means it's safe to call 'neon' routines. + // Also, we've checked that our haystack is big enough to run on the + // vector routine. Pointer validity is caller's responsibility. + self.find_raw_impl(start, end) + } + + /// Like `rfind`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn rfind_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + if end.distance(start) < uint8x16_t::BYTES { + // SAFETY: We require the caller to pass valid start/end pointers. + return generic::rev_byte_by_byte(start, end, |b| { + b == self.0.needle1() + }); + } + // SAFETY: Building a `One` means it's safe to call 'neon' routines. + // Also, we've checked that our haystack is big enough to run on the + // vector routine. Pointer validity is caller's responsibility. + self.rfind_raw_impl(start, end) + } + + /// Like `count`, but accepts and returns raw pointers. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn count_raw(&self, start: *const u8, end: *const u8) -> usize { + if start >= end { + return 0; + } + if end.distance(start) < uint8x16_t::BYTES { + // SAFETY: We require the caller to pass valid start/end pointers. + return generic::count_byte_by_byte(start, end, |b| { + b == self.0.needle1() + }); + } + // SAFETY: Building a `One` means it's safe to call 'neon' routines. + // Also, we've checked that our haystack is big enough to run on the + // vector routine. Pointer validity is caller's responsibility. + self.count_raw_impl(start, end) + } + + /// Execute a search using neon vectors and routines. + /// + /// # Safety + /// + /// Same as [`One::find_raw`], except the distance between `start` and + /// `end` must be at least the size of a neon vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `One`, which can only be constructed + /// when it is safe to call `neon` routines.) + #[target_feature(enable = "neon")] + #[inline] + unsafe fn find_raw_impl( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.0.find_raw(start, end) + } + + /// Execute a search using neon vectors and routines. + /// + /// # Safety + /// + /// Same as [`One::rfind_raw`], except the distance between `start` and + /// `end` must be at least the size of a neon vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `One`, which can only be constructed + /// when it is safe to call `neon` routines.) + #[target_feature(enable = "neon")] + #[inline] + unsafe fn rfind_raw_impl( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.0.rfind_raw(start, end) + } + + /// Execute a count using neon vectors and routines. + /// + /// # Safety + /// + /// Same as [`One::count_raw`], except the distance between `start` and + /// `end` must be at least the size of a neon vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `One`, which can only be constructed + /// when it is safe to call `neon` routines.) + #[target_feature(enable = "neon")] + #[inline] + unsafe fn count_raw_impl( + &self, + start: *const u8, + end: *const u8, + ) -> usize { + self.0.count_raw(start, end) + } + + /// Returns an iterator over all occurrences of the needle byte in the + /// given haystack. + /// + /// The iterator returned implements `DoubleEndedIterator`. This means it + /// can also be used to find occurrences in reverse order. + #[inline] + pub fn iter<'a, 'h>(&'a self, haystack: &'h [u8]) -> OneIter<'a, 'h> { + OneIter { searcher: self, it: generic::Iter::new(haystack) } + } +} + +/// An iterator over all occurrences of a single byte in a haystack. +/// +/// This iterator implements `DoubleEndedIterator`, which means it can also be +/// used to find occurrences in reverse order. +/// +/// This iterator is created by the [`One::iter`] method. +/// +/// The lifetime parameters are as follows: +/// +/// * `'a` refers to the lifetime of the underlying [`One`] searcher. +/// * `'h` refers to the lifetime of the haystack being searched. +#[derive(Clone, Debug)] +pub struct OneIter<'a, 'h> { + searcher: &'a One, + it: generic::Iter<'h>, +} + +impl<'a, 'h> Iterator for OneIter<'a, 'h> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'find_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next(|s, e| self.searcher.find_raw(s, e)) } + } + + #[inline] + fn count(self) -> usize { + self.it.count(|s, e| { + // SAFETY: We rely on our generic iterator to return valid start + // and end pointers. + unsafe { self.searcher.count_raw(s, e) } + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, 'h> DoubleEndedIterator for OneIter<'a, 'h> { + #[inline] + fn next_back(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'rfind_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next_back(|s, e| self.searcher.rfind_raw(s, e)) } + } +} + +impl<'a, 'h> core::iter::FusedIterator for OneIter<'a, 'h> {} + +/// Finds all occurrences of two bytes in a haystack. +/// +/// That is, this reports matches of one of two possible bytes. For example, +/// searching for `a` or `b` in `afoobar` would report matches at offsets `0`, +/// `4` and `5`. +#[derive(Clone, Copy, Debug)] +pub struct Two(generic::Two); + +impl Two { + /// Create a new searcher that finds occurrences of the needle bytes given. + /// + /// This particular searcher is specialized to use neon vector instructions + /// that typically make it quite fast. + /// + /// If neon is unavailable in the current environment, then `None` is + /// returned. + #[inline] + pub fn new(needle1: u8, needle2: u8) -> Option { + if Two::is_available() { + // SAFETY: we check that neon is available above. + unsafe { Some(Two::new_unchecked(needle1, needle2)) } + } else { + None + } + } + + /// Create a new finder specific to neon vectors and routines without + /// checking that neon is available. + /// + /// # Safety + /// + /// Callers must guarantee that it is safe to execute `neon` instructions + /// in the current environment. + /// + /// Note that it is a common misconception that if one compiles for an + /// `x86_64` target, then they therefore automatically have access to neon + /// instructions. While this is almost always the case, it isn't true in + /// 100% of cases. + #[target_feature(enable = "neon")] + #[inline] + pub unsafe fn new_unchecked(needle1: u8, needle2: u8) -> Two { + Two(generic::Two::new(needle1, needle2)) + } + + /// Returns true when this implementation is available in the current + /// environment. + /// + /// When this is true, it is guaranteed that [`Two::new`] will return + /// a `Some` value. Similarly, when it is false, it is guaranteed that + /// `Two::new` will return a `None` value. + /// + /// Note also that for the lifetime of a single program, if this returns + /// true then it will always return true. + #[inline] + pub fn is_available() -> bool { + #[cfg(target_feature = "neon")] + { + true + } + #[cfg(not(target_feature = "neon"))] + { + false + } + } + + /// Return the first occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value is `haystack.len() - 1`. + #[inline] + pub fn find(&self, haystack: &[u8]) -> Option { + // SAFETY: `find_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.find_raw(s, e) + }) + } + } + + /// Return the last occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value is `haystack.len() - 1`. + #[inline] + pub fn rfind(&self, haystack: &[u8]) -> Option { + // SAFETY: `rfind_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.rfind_raw(s, e) + }) + } + } + + /// Like `find`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn find_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + if end.distance(start) < uint8x16_t::BYTES { + // SAFETY: We require the caller to pass valid start/end pointers. + return generic::fwd_byte_by_byte(start, end, |b| { + b == self.0.needle1() || b == self.0.needle2() + }); + } + // SAFETY: Building a `Two` means it's safe to call 'neon' routines. + // Also, we've checked that our haystack is big enough to run on the + // vector routine. Pointer validity is caller's responsibility. + self.find_raw_impl(start, end) + } + + /// Like `rfind`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn rfind_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + if end.distance(start) < uint8x16_t::BYTES { + // SAFETY: We require the caller to pass valid start/end pointers. + return generic::rev_byte_by_byte(start, end, |b| { + b == self.0.needle1() || b == self.0.needle2() + }); + } + // SAFETY: Building a `Two` means it's safe to call 'neon' routines. + // Also, we've checked that our haystack is big enough to run on the + // vector routine. Pointer validity is caller's responsibility. + self.rfind_raw_impl(start, end) + } + + /// Execute a search using neon vectors and routines. + /// + /// # Safety + /// + /// Same as [`Two::find_raw`], except the distance between `start` and + /// `end` must be at least the size of a neon vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Two`, which can only be constructed + /// when it is safe to call `neon` routines.) + #[target_feature(enable = "neon")] + #[inline] + unsafe fn find_raw_impl( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.0.find_raw(start, end) + } + + /// Execute a search using neon vectors and routines. + /// + /// # Safety + /// + /// Same as [`Two::rfind_raw`], except the distance between `start` and + /// `end` must be at least the size of a neon vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Two`, which can only be constructed + /// when it is safe to call `neon` routines.) + #[target_feature(enable = "neon")] + #[inline] + unsafe fn rfind_raw_impl( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.0.rfind_raw(start, end) + } + + /// Returns an iterator over all occurrences of the needle bytes in the + /// given haystack. + /// + /// The iterator returned implements `DoubleEndedIterator`. This means it + /// can also be used to find occurrences in reverse order. + #[inline] + pub fn iter<'a, 'h>(&'a self, haystack: &'h [u8]) -> TwoIter<'a, 'h> { + TwoIter { searcher: self, it: generic::Iter::new(haystack) } + } +} + +/// An iterator over all occurrences of two possible bytes in a haystack. +/// +/// This iterator implements `DoubleEndedIterator`, which means it can also be +/// used to find occurrences in reverse order. +/// +/// This iterator is created by the [`Two::iter`] method. +/// +/// The lifetime parameters are as follows: +/// +/// * `'a` refers to the lifetime of the underlying [`Two`] searcher. +/// * `'h` refers to the lifetime of the haystack being searched. +#[derive(Clone, Debug)] +pub struct TwoIter<'a, 'h> { + searcher: &'a Two, + it: generic::Iter<'h>, +} + +impl<'a, 'h> Iterator for TwoIter<'a, 'h> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'find_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next(|s, e| self.searcher.find_raw(s, e)) } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, 'h> DoubleEndedIterator for TwoIter<'a, 'h> { + #[inline] + fn next_back(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'rfind_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next_back(|s, e| self.searcher.rfind_raw(s, e)) } + } +} + +impl<'a, 'h> core::iter::FusedIterator for TwoIter<'a, 'h> {} + +/// Finds all occurrences of three bytes in a haystack. +/// +/// That is, this reports matches of one of three possible bytes. For example, +/// searching for `a`, `b` or `o` in `afoobar` would report matches at offsets +/// `0`, `2`, `3`, `4` and `5`. +#[derive(Clone, Copy, Debug)] +pub struct Three(generic::Three); + +impl Three { + /// Create a new searcher that finds occurrences of the needle bytes given. + /// + /// This particular searcher is specialized to use neon vector instructions + /// that typically make it quite fast. + /// + /// If neon is unavailable in the current environment, then `None` is + /// returned. + #[inline] + pub fn new(needle1: u8, needle2: u8, needle3: u8) -> Option { + if Three::is_available() { + // SAFETY: we check that neon is available above. + unsafe { Some(Three::new_unchecked(needle1, needle2, needle3)) } + } else { + None + } + } + + /// Create a new finder specific to neon vectors and routines without + /// checking that neon is available. + /// + /// # Safety + /// + /// Callers must guarantee that it is safe to execute `neon` instructions + /// in the current environment. + /// + /// Note that it is a common misconception that if one compiles for an + /// `x86_64` target, then they therefore automatically have access to neon + /// instructions. While this is almost always the case, it isn't true in + /// 100% of cases. + #[target_feature(enable = "neon")] + #[inline] + pub unsafe fn new_unchecked( + needle1: u8, + needle2: u8, + needle3: u8, + ) -> Three { + Three(generic::Three::new(needle1, needle2, needle3)) + } + + /// Returns true when this implementation is available in the current + /// environment. + /// + /// When this is true, it is guaranteed that [`Three::new`] will return + /// a `Some` value. Similarly, when it is false, it is guaranteed that + /// `Three::new` will return a `None` value. + /// + /// Note also that for the lifetime of a single program, if this returns + /// true then it will always return true. + #[inline] + pub fn is_available() -> bool { + #[cfg(target_feature = "neon")] + { + true + } + #[cfg(not(target_feature = "neon"))] + { + false + } + } + + /// Return the first occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value is `haystack.len() - 1`. + #[inline] + pub fn find(&self, haystack: &[u8]) -> Option { + // SAFETY: `find_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.find_raw(s, e) + }) + } + } + + /// Return the last occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value is `haystack.len() - 1`. + #[inline] + pub fn rfind(&self, haystack: &[u8]) -> Option { + // SAFETY: `rfind_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.rfind_raw(s, e) + }) + } + } + + /// Like `find`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn find_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + if end.distance(start) < uint8x16_t::BYTES { + // SAFETY: We require the caller to pass valid start/end pointers. + return generic::fwd_byte_by_byte(start, end, |b| { + b == self.0.needle1() + || b == self.0.needle2() + || b == self.0.needle3() + }); + } + // SAFETY: Building a `Three` means it's safe to call 'neon' routines. + // Also, we've checked that our haystack is big enough to run on the + // vector routine. Pointer validity is caller's responsibility. + self.find_raw_impl(start, end) + } + + /// Like `rfind`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn rfind_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + if end.distance(start) < uint8x16_t::BYTES { + // SAFETY: We require the caller to pass valid start/end pointers. + return generic::rev_byte_by_byte(start, end, |b| { + b == self.0.needle1() + || b == self.0.needle2() + || b == self.0.needle3() + }); + } + // SAFETY: Building a `Three` means it's safe to call 'neon' routines. + // Also, we've checked that our haystack is big enough to run on the + // vector routine. Pointer validity is caller's responsibility. + self.rfind_raw_impl(start, end) + } + + /// Execute a search using neon vectors and routines. + /// + /// # Safety + /// + /// Same as [`Three::find_raw`], except the distance between `start` and + /// `end` must be at least the size of a neon vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Three`, which can only be constructed + /// when it is safe to call `neon` routines.) + #[target_feature(enable = "neon")] + #[inline] + unsafe fn find_raw_impl( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.0.find_raw(start, end) + } + + /// Execute a search using neon vectors and routines. + /// + /// # Safety + /// + /// Same as [`Three::rfind_raw`], except the distance between `start` and + /// `end` must be at least the size of a neon vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Three`, which can only be constructed + /// when it is safe to call `neon` routines.) + #[target_feature(enable = "neon")] + #[inline] + unsafe fn rfind_raw_impl( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.0.rfind_raw(start, end) + } + + /// Returns an iterator over all occurrences of the needle byte in the + /// given haystack. + /// + /// The iterator returned implements `DoubleEndedIterator`. This means it + /// can also be used to find occurrences in reverse order. + #[inline] + pub fn iter<'a, 'h>(&'a self, haystack: &'h [u8]) -> ThreeIter<'a, 'h> { + ThreeIter { searcher: self, it: generic::Iter::new(haystack) } + } +} + +/// An iterator over all occurrences of three possible bytes in a haystack. +/// +/// This iterator implements `DoubleEndedIterator`, which means it can also be +/// used to find occurrences in reverse order. +/// +/// This iterator is created by the [`Three::iter`] method. +/// +/// The lifetime parameters are as follows: +/// +/// * `'a` refers to the lifetime of the underlying [`Three`] searcher. +/// * `'h` refers to the lifetime of the haystack being searched. +#[derive(Clone, Debug)] +pub struct ThreeIter<'a, 'h> { + searcher: &'a Three, + it: generic::Iter<'h>, +} + +impl<'a, 'h> Iterator for ThreeIter<'a, 'h> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'find_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next(|s, e| self.searcher.find_raw(s, e)) } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, 'h> DoubleEndedIterator for ThreeIter<'a, 'h> { + #[inline] + fn next_back(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'rfind_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next_back(|s, e| self.searcher.rfind_raw(s, e)) } + } +} + +impl<'a, 'h> core::iter::FusedIterator for ThreeIter<'a, 'h> {} + +#[cfg(test)] +mod tests { + use super::*; + + define_memchr_quickcheck!(super); + + #[test] + fn forward_one() { + crate::tests::memchr::Runner::new(1).forward_iter( + |haystack, needles| { + Some(One::new(needles[0])?.iter(haystack).collect()) + }, + ) + } + + #[test] + fn reverse_one() { + crate::tests::memchr::Runner::new(1).reverse_iter( + |haystack, needles| { + Some(One::new(needles[0])?.iter(haystack).rev().collect()) + }, + ) + } + + #[test] + fn count_one() { + crate::tests::memchr::Runner::new(1).count_iter(|haystack, needles| { + Some(One::new(needles[0])?.iter(haystack).count()) + }) + } + + #[test] + fn forward_two() { + crate::tests::memchr::Runner::new(2).forward_iter( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + Some(Two::new(n1, n2)?.iter(haystack).collect()) + }, + ) + } + + #[test] + fn reverse_two() { + crate::tests::memchr::Runner::new(2).reverse_iter( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + Some(Two::new(n1, n2)?.iter(haystack).rev().collect()) + }, + ) + } + + #[test] + fn forward_three() { + crate::tests::memchr::Runner::new(3).forward_iter( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + let n3 = needles.get(2).copied()?; + Some(Three::new(n1, n2, n3)?.iter(haystack).collect()) + }, + ) + } + + #[test] + fn reverse_three() { + crate::tests::memchr::Runner::new(3).reverse_iter( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + let n3 = needles.get(2).copied()?; + Some(Three::new(n1, n2, n3)?.iter(haystack).rev().collect()) + }, + ) + } +} diff --git a/third_party/crates/memchr-2.8.3/src/arch/aarch64/neon/mod.rs b/third_party/crates/memchr-2.8.3/src/arch/aarch64/neon/mod.rs new file mode 100644 index 0000000..ccf9cf8 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/aarch64/neon/mod.rs @@ -0,0 +1,6 @@ +/*! +Algorithms for the `aarch64` target using 128-bit vectors via NEON. +*/ + +pub mod memchr; +pub mod packedpair; diff --git a/third_party/crates/memchr-2.8.3/src/arch/aarch64/neon/packedpair.rs b/third_party/crates/memchr-2.8.3/src/arch/aarch64/neon/packedpair.rs new file mode 100644 index 0000000..5cc2a02 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/aarch64/neon/packedpair.rs @@ -0,0 +1,236 @@ +/*! +A 128-bit vector implementation of the "packed pair" SIMD algorithm. + +The "packed pair" algorithm is based on the [generic SIMD] algorithm. The main +difference is that it (by default) uses a background distribution of byte +frequencies to heuristically select the pair of bytes to search for. + +[generic SIMD]: http://0x80.pl/articles/simd-strfind.html#first-and-last +*/ + +use core::arch::aarch64::uint8x16_t; + +use crate::arch::{all::packedpair::Pair, generic::packedpair}; + +/// A "packed pair" finder that uses 128-bit vector operations. +/// +/// This finder picks two bytes that it believes have high predictive power +/// for indicating an overall match of a needle. Depending on whether +/// `Finder::find` or `Finder::find_prefilter` is used, it reports offsets +/// where the needle matches or could match. In the prefilter case, candidates +/// are reported whenever the [`Pair`] of bytes given matches. +#[derive(Clone, Copy, Debug)] +pub struct Finder(packedpair::Finder); + +/// A "packed pair" finder that uses 128-bit vector operations. +/// +/// This finder picks two bytes that it believes have high predictive power +/// for indicating an overall match of a needle. Depending on whether +/// `Finder::find` or `Finder::find_prefilter` is used, it reports offsets +/// where the needle matches or could match. In the prefilter case, candidates +/// are reported whenever the [`Pair`] of bytes given matches. +impl Finder { + /// Create a new pair searcher. The searcher returned can either report + /// exact matches of `needle` or act as a prefilter and report candidate + /// positions of `needle`. + /// + /// If neon is unavailable in the current environment or if a [`Pair`] + /// could not be constructed from the needle given, then `None` is + /// returned. + #[inline] + pub fn new(needle: &[u8]) -> Option { + Finder::with_pair(needle, Pair::new(needle)?) + } + + /// Create a new "packed pair" finder using the pair of bytes given. + /// + /// This constructor permits callers to control precisely which pair of + /// bytes is used as a predicate. + /// + /// If neon is unavailable in the current environment, then `None` is + /// returned. + #[inline] + pub fn with_pair(needle: &[u8], pair: Pair) -> Option { + if Finder::is_available() { + // SAFETY: we check that NEON is available above. We are also + // guaranteed to have needle.len() > 1 because we have a valid + // Pair. + unsafe { Some(Finder::with_pair_impl(needle, pair)) } + } else { + None + } + } + + /// Create a new `Finder` specific to neon vectors and routines. + /// + /// # Safety + /// + /// Same as the safety for `packedpair::Finder::new`, and callers must also + /// ensure that neon is available. + #[target_feature(enable = "neon")] + #[inline] + unsafe fn with_pair_impl(needle: &[u8], pair: Pair) -> Finder { + let finder = packedpair::Finder::::new(needle, pair); + Finder(finder) + } + + /// Returns true when this implementation is available in the current + /// environment. + /// + /// When this is true, it is guaranteed that [`Finder::with_pair`] will + /// return a `Some` value. Similarly, when it is false, it is guaranteed + /// that `Finder::with_pair` will return a `None` value. Notice that this + /// does not guarantee that [`Finder::new`] will return a `Finder`. Namely, + /// even when `Finder::is_available` is true, it is not guaranteed that a + /// valid [`Pair`] can be found from the needle given. + /// + /// Note also that for the lifetime of a single program, if this returns + /// true then it will always return true. + #[inline] + pub fn is_available() -> bool { + #[cfg(target_feature = "neon")] + { + true + } + #[cfg(not(target_feature = "neon"))] + { + false + } + } + + /// Execute a search using neon vectors and routines. + /// + /// # Panics + /// + /// When `haystack.len()` is less than [`Finder::min_haystack_len`]. + #[inline] + pub fn find(&self, haystack: &[u8], needle: &[u8]) -> Option { + // SAFETY: Building a `Finder` means it's safe to call 'neon' routines. + unsafe { self.find_impl(haystack, needle) } + } + + /// Execute a search using neon vectors and routines. + /// + /// # Panics + /// + /// When `haystack.len()` is less than [`Finder::min_haystack_len`]. + #[inline] + pub fn find_prefilter(&self, haystack: &[u8]) -> Option { + // SAFETY: Building a `Finder` means it's safe to call 'neon' routines. + unsafe { self.find_prefilter_impl(haystack) } + } + + /// Execute a search using neon vectors and routines. + /// + /// # Panics + /// + /// When `haystack.len()` is less than [`Finder::min_haystack_len`]. + /// + /// # Safety + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Finder`, which can only be constructed + /// when it is safe to call `neon` routines.) + #[target_feature(enable = "neon")] + #[inline] + unsafe fn find_impl( + &self, + haystack: &[u8], + needle: &[u8], + ) -> Option { + self.0.find(haystack, needle) + } + + /// Execute a prefilter search using neon vectors and routines. + /// + /// # Panics + /// + /// When `haystack.len()` is less than [`Finder::min_haystack_len`]. + /// + /// # Safety + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Finder`, which can only be constructed + /// when it is safe to call `neon` routines.) + #[target_feature(enable = "neon")] + #[inline] + unsafe fn find_prefilter_impl(&self, haystack: &[u8]) -> Option { + self.0.find_prefilter(haystack) + } + + /// Returns the pair of offsets (into the needle) used to check as a + /// predicate before confirming whether a needle exists at a particular + /// position. + #[inline] + pub fn pair(&self) -> &Pair { + self.0.pair() + } + + /// Returns the minimum haystack length that this `Finder` can search. + /// + /// Using a haystack with length smaller than this in a search will result + /// in a panic. The reason for this restriction is that this finder is + /// meant to be a low-level component that is part of a larger substring + /// strategy. In that sense, it avoids trying to handle all cases and + /// instead only handles the cases that it can handle very well. + #[inline] + pub fn min_haystack_len(&self) -> usize { + self.0.min_haystack_len() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn find(haystack: &[u8], needle: &[u8]) -> Option> { + let f = Finder::new(needle)?; + if haystack.len() < f.min_haystack_len() { + return None; + } + Some(f.find(haystack, needle)) + } + + define_substring_forward_quickcheck!(find); + + #[test] + fn forward_substring() { + crate::tests::substring::Runner::new().fwd(find).run() + } + + #[test] + fn forward_packedpair() { + fn find( + haystack: &[u8], + needle: &[u8], + index1: u8, + index2: u8, + ) -> Option> { + let pair = Pair::with_indices(needle, index1, index2)?; + let f = Finder::with_pair(needle, pair)?; + if haystack.len() < f.min_haystack_len() { + return None; + } + Some(f.find(haystack, needle)) + } + crate::tests::packedpair::Runner::new().fwd(find).run() + } + + #[test] + fn forward_packedpair_prefilter() { + fn find( + haystack: &[u8], + needle: &[u8], + index1: u8, + index2: u8, + ) -> Option> { + let pair = Pair::with_indices(needle, index1, index2)?; + let f = Finder::with_pair(needle, pair)?; + if haystack.len() < f.min_haystack_len() { + return None; + } + Some(f.find_prefilter(haystack)) + } + crate::tests::packedpair::Runner::new().fwd(find).run() + } +} diff --git a/third_party/crates/memchr-2.8.3/src/arch/all/memchr.rs b/third_party/crates/memchr-2.8.3/src/arch/all/memchr.rs new file mode 100644 index 0000000..7f327f8 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/all/memchr.rs @@ -0,0 +1,1022 @@ +/*! +Provides architecture independent implementations of `memchr` and friends. + +The main types in this module are [`One`], [`Two`] and [`Three`]. They are for +searching for one, two or three distinct bytes, respectively, in a haystack. +Each type also has corresponding double ended iterators. These searchers +are typically slower than hand-coded vector routines accomplishing the same +task, but are also typically faster than naive scalar code. These routines +effectively work by treating a `usize` as a vector of 8-bit lanes, and thus +achieves some level of data parallelism even without explicit vector support. + +The `One` searcher also provides a [`One::count`] routine for efficiently +counting the number of times a single byte occurs in a haystack. This is +useful, for example, for counting the number of lines in a haystack. This +routine exists because it is usually faster, especially with a high match +count, than using [`One::find`] repeatedly. ([`OneIter`] specializes its +`Iterator::count` implementation to use this routine.) + +Only one, two and three bytes are supported because three bytes is about +the point where one sees diminishing returns. Beyond this point and it's +probably (but not necessarily) better to just use a simple `[bool; 256]` array +or similar. However, it depends mightily on the specific work-load and the +expected match frequency. +*/ + +use crate::{arch::generic::memchr as generic, ext::Pointer}; + +/// The number of bytes in a single `usize` value. +const USIZE_BYTES: usize = (usize::BITS / 8) as usize; +/// The bits that must be zero for a `*const usize` to be properly aligned. +const USIZE_ALIGN: usize = USIZE_BYTES - 1; + +/// Finds all occurrences of a single byte in a haystack. +#[derive(Clone, Copy, Debug)] +pub struct One { + s1: u8, + v1: usize, +} + +impl One { + /// The number of bytes we examine per each iteration of our search loop. + const LOOP_BYTES: usize = 2 * USIZE_BYTES; + + /// Create a new searcher that finds occurrences of the byte given. + #[inline] + pub fn new(needle: u8) -> One { + One { s1: needle, v1: splat(needle) } + } + + /// A test-only routine so that we can bundle a bunch of quickcheck + /// properties into a single macro. Basically, this provides a constructor + /// that makes it identical to most other memchr implementations, which + /// have fallible constructors. + #[cfg(test)] + pub(crate) fn try_new(needle: u8) -> Option { + Some(One::new(needle)) + } + + /// Return the first occurrence of the needle in the given haystack. If no + /// such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value for a non-empty haystack is `haystack.len() - 1`. + #[inline] + pub fn find(&self, haystack: &[u8]) -> Option { + // SAFETY: `find_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.find_raw(s, e) + }) + } + } + + /// Return the last occurrence of the needle in the given haystack. If no + /// such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value for a non-empty haystack is `haystack.len() - 1`. + #[inline] + pub fn rfind(&self, haystack: &[u8]) -> Option { + // SAFETY: `find_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.rfind_raw(s, e) + }) + } + } + + /// Counts all occurrences of this byte in the given haystack. + #[inline] + pub fn count(&self, haystack: &[u8]) -> usize { + // SAFETY: All of our pointers are derived directly from a borrowed + // slice, which is guaranteed to be valid. + unsafe { + let start = haystack.as_ptr(); + let end = start.add(haystack.len()); + self.count_raw(start, end) + } + } + + /// Like `find`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn find_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + let confirm = |b| self.confirm(b); + let len = end.distance(start); + if len < USIZE_BYTES { + return generic::fwd_byte_by_byte(start, end, confirm); + } + + // The start of the search may not be aligned to `*const usize`, + // so we do an unaligned load here. + let chunk = start.cast::().read_unaligned(); + if self.has_needle(chunk) { + return generic::fwd_byte_by_byte(start, end, confirm); + } + + // And now we start our search at a guaranteed aligned position. + // The first iteration of the loop below will overlap with the the + // unaligned chunk above in cases where the search starts at an + // unaligned offset, but that's okay as we're only here if that + // above didn't find a match. + let mut cur = + start.add(USIZE_BYTES - (start.as_usize() & USIZE_ALIGN)); + debug_assert!(cur > start); + if len <= One::LOOP_BYTES { + return generic::fwd_byte_by_byte(cur, end, confirm); + } + debug_assert!(end.sub(One::LOOP_BYTES) >= start); + while cur <= end.sub(One::LOOP_BYTES) { + debug_assert_eq!(0, cur.as_usize() % USIZE_BYTES); + + let a = cur.cast::().read(); + let b = cur.add(USIZE_BYTES).cast::().read(); + if self.has_needle(a) || self.has_needle(b) { + break; + } + cur = cur.add(One::LOOP_BYTES); + } + generic::fwd_byte_by_byte(cur, end, confirm) + } + + /// Like `rfind`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn rfind_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + let confirm = |b| self.confirm(b); + let len = end.distance(start); + if len < USIZE_BYTES { + return generic::rev_byte_by_byte(start, end, confirm); + } + + let chunk = end.sub(USIZE_BYTES).cast::().read_unaligned(); + if self.has_needle(chunk) { + return generic::rev_byte_by_byte(start, end, confirm); + } + + let mut cur = end.sub(end.as_usize() & USIZE_ALIGN); + debug_assert!(start <= cur && cur <= end); + if len <= One::LOOP_BYTES { + return generic::rev_byte_by_byte(start, cur, confirm); + } + while cur >= start.add(One::LOOP_BYTES) { + debug_assert_eq!(0, cur.as_usize() % USIZE_BYTES); + + let a = cur.sub(2 * USIZE_BYTES).cast::().read(); + let b = cur.sub(1 * USIZE_BYTES).cast::().read(); + if self.has_needle(a) || self.has_needle(b) { + break; + } + cur = cur.sub(One::LOOP_BYTES); + } + generic::rev_byte_by_byte(start, cur, confirm) + } + + /// Counts all occurrences of this byte in the given haystack represented + /// by raw pointers. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `0` will always be returned. + #[inline] + pub unsafe fn count_raw(&self, start: *const u8, end: *const u8) -> usize { + if start >= end { + return 0; + } + // Sadly I couldn't get the SWAR approach to work here, so we just do + // one byte at a time for now. PRs to improve this are welcome. + let mut ptr = start; + let mut count = 0; + while ptr < end { + count += (ptr.read() == self.s1) as usize; + ptr = ptr.offset(1); + } + count + } + + /// Returns an iterator over all occurrences of the needle byte in the + /// given haystack. + /// + /// The iterator returned implements `DoubleEndedIterator`. This means it + /// can also be used to find occurrences in reverse order. + pub fn iter<'a, 'h>(&'a self, haystack: &'h [u8]) -> OneIter<'a, 'h> { + OneIter { searcher: self, it: generic::Iter::new(haystack) } + } + + #[inline(always)] + fn has_needle(&self, chunk: usize) -> bool { + has_zero_byte(self.v1 ^ chunk) + } + + #[inline(always)] + fn confirm(&self, haystack_byte: u8) -> bool { + self.s1 == haystack_byte + } +} + +/// An iterator over all occurrences of a single byte in a haystack. +/// +/// This iterator implements `DoubleEndedIterator`, which means it can also be +/// used to find occurrences in reverse order. +/// +/// This iterator is created by the [`One::iter`] method. +/// +/// The lifetime parameters are as follows: +/// +/// * `'a` refers to the lifetime of the underlying [`One`] searcher. +/// * `'h` refers to the lifetime of the haystack being searched. +#[derive(Clone, Debug)] +pub struct OneIter<'a, 'h> { + /// The underlying memchr searcher. + searcher: &'a One, + /// Generic iterator implementation. + it: generic::Iter<'h>, +} + +impl<'a, 'h> Iterator for OneIter<'a, 'h> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'find_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next(|s, e| self.searcher.find_raw(s, e)) } + } + + #[inline] + fn count(self) -> usize { + self.it.count(|s, e| { + // SAFETY: We rely on our generic iterator to return valid start + // and end pointers. + unsafe { self.searcher.count_raw(s, e) } + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, 'h> DoubleEndedIterator for OneIter<'a, 'h> { + #[inline] + fn next_back(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'rfind_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next_back(|s, e| self.searcher.rfind_raw(s, e)) } + } +} + +/// Finds all occurrences of two bytes in a haystack. +/// +/// That is, this reports matches of one of two possible bytes. For example, +/// searching for `a` or `b` in `afoobar` would report matches at offsets `0`, +/// `4` and `5`. +#[derive(Clone, Copy, Debug)] +pub struct Two { + s1: u8, + s2: u8, + v1: usize, + v2: usize, +} + +impl Two { + /// Create a new searcher that finds occurrences of the two needle bytes + /// given. + #[inline] + pub fn new(needle1: u8, needle2: u8) -> Two { + Two { + s1: needle1, + s2: needle2, + v1: splat(needle1), + v2: splat(needle2), + } + } + + /// A test-only routine so that we can bundle a bunch of quickcheck + /// properties into a single macro. Basically, this provides a constructor + /// that makes it identical to most other memchr implementations, which + /// have fallible constructors. + #[cfg(test)] + pub(crate) fn try_new(needle1: u8, needle2: u8) -> Option { + Some(Two::new(needle1, needle2)) + } + + /// Return the first occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value for a non-empty haystack is `haystack.len() - 1`. + #[inline] + pub fn find(&self, haystack: &[u8]) -> Option { + // SAFETY: `find_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.find_raw(s, e) + }) + } + } + + /// Return the last occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value for a non-empty haystack is `haystack.len() - 1`. + #[inline] + pub fn rfind(&self, haystack: &[u8]) -> Option { + // SAFETY: `find_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.rfind_raw(s, e) + }) + } + } + + /// Like `find`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn find_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + let confirm = |b| self.confirm(b); + let len = end.distance(start); + if len < USIZE_BYTES { + return generic::fwd_byte_by_byte(start, end, confirm); + } + + // The start of the search may not be aligned to `*const usize`, + // so we do an unaligned load here. + let chunk = start.cast::().read_unaligned(); + if self.has_needle(chunk) { + return generic::fwd_byte_by_byte(start, end, confirm); + } + + // And now we start our search at a guaranteed aligned position. + // The first iteration of the loop below will overlap with the + // unaligned chunk above in cases where the search starts at an + // unaligned offset, but that's okay as we're only here if that + // above didn't find a match. + let mut cur = + start.add(USIZE_BYTES - (start.as_usize() & USIZE_ALIGN)); + debug_assert!(cur > start); + debug_assert!(end.sub(USIZE_BYTES) >= start); + while cur <= end.sub(USIZE_BYTES) { + debug_assert_eq!(0, cur.as_usize() % USIZE_BYTES); + + let chunk = cur.cast::().read(); + if self.has_needle(chunk) { + break; + } + cur = cur.add(USIZE_BYTES); + } + generic::fwd_byte_by_byte(cur, end, confirm) + } + + /// Like `rfind`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn rfind_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + let confirm = |b| self.confirm(b); + let len = end.distance(start); + if len < USIZE_BYTES { + return generic::rev_byte_by_byte(start, end, confirm); + } + + let chunk = end.sub(USIZE_BYTES).cast::().read_unaligned(); + if self.has_needle(chunk) { + return generic::rev_byte_by_byte(start, end, confirm); + } + + let mut cur = end.sub(end.as_usize() & USIZE_ALIGN); + debug_assert!(start <= cur && cur <= end); + while cur >= start.add(USIZE_BYTES) { + debug_assert_eq!(0, cur.as_usize() % USIZE_BYTES); + + let chunk = cur.sub(USIZE_BYTES).cast::().read(); + if self.has_needle(chunk) { + break; + } + cur = cur.sub(USIZE_BYTES); + } + generic::rev_byte_by_byte(start, cur, confirm) + } + + /// Returns an iterator over all occurrences of one of the needle bytes in + /// the given haystack. + /// + /// The iterator returned implements `DoubleEndedIterator`. This means it + /// can also be used to find occurrences in reverse order. + pub fn iter<'a, 'h>(&'a self, haystack: &'h [u8]) -> TwoIter<'a, 'h> { + TwoIter { searcher: self, it: generic::Iter::new(haystack) } + } + + #[inline(always)] + fn has_needle(&self, chunk: usize) -> bool { + has_zero_byte(self.v1 ^ chunk) || has_zero_byte(self.v2 ^ chunk) + } + + #[inline(always)] + fn confirm(&self, haystack_byte: u8) -> bool { + self.s1 == haystack_byte || self.s2 == haystack_byte + } +} + +/// An iterator over all occurrences of two possible bytes in a haystack. +/// +/// This iterator implements `DoubleEndedIterator`, which means it can also be +/// used to find occurrences in reverse order. +/// +/// This iterator is created by the [`Two::iter`] method. +/// +/// The lifetime parameters are as follows: +/// +/// * `'a` refers to the lifetime of the underlying [`Two`] searcher. +/// * `'h` refers to the lifetime of the haystack being searched. +#[derive(Clone, Debug)] +pub struct TwoIter<'a, 'h> { + /// The underlying memchr searcher. + searcher: &'a Two, + /// Generic iterator implementation. + it: generic::Iter<'h>, +} + +impl<'a, 'h> Iterator for TwoIter<'a, 'h> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'find_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next(|s, e| self.searcher.find_raw(s, e)) } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, 'h> DoubleEndedIterator for TwoIter<'a, 'h> { + #[inline] + fn next_back(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'rfind_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next_back(|s, e| self.searcher.rfind_raw(s, e)) } + } +} + +/// Finds all occurrences of three bytes in a haystack. +/// +/// That is, this reports matches of one of three possible bytes. For example, +/// searching for `a`, `b` or `o` in `afoobar` would report matches at offsets +/// `0`, `2`, `3`, `4` and `5`. +#[derive(Clone, Copy, Debug)] +pub struct Three { + s1: u8, + s2: u8, + s3: u8, + v1: usize, + v2: usize, + v3: usize, +} + +impl Three { + /// Create a new searcher that finds occurrences of the three needle bytes + /// given. + #[inline] + pub fn new(needle1: u8, needle2: u8, needle3: u8) -> Three { + Three { + s1: needle1, + s2: needle2, + s3: needle3, + v1: splat(needle1), + v2: splat(needle2), + v3: splat(needle3), + } + } + + /// A test-only routine so that we can bundle a bunch of quickcheck + /// properties into a single macro. Basically, this provides a constructor + /// that makes it identical to most other memchr implementations, which + /// have fallible constructors. + #[cfg(test)] + pub(crate) fn try_new( + needle1: u8, + needle2: u8, + needle3: u8, + ) -> Option { + Some(Three::new(needle1, needle2, needle3)) + } + + /// Return the first occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value for a non-empty haystack is `haystack.len() - 1`. + #[inline] + pub fn find(&self, haystack: &[u8]) -> Option { + // SAFETY: `find_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.find_raw(s, e) + }) + } + } + + /// Return the last occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value for a non-empty haystack is `haystack.len() - 1`. + #[inline] + pub fn rfind(&self, haystack: &[u8]) -> Option { + // SAFETY: `find_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.rfind_raw(s, e) + }) + } + } + + /// Like `find`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn find_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + let confirm = |b| self.confirm(b); + let len = end.distance(start); + if len < USIZE_BYTES { + return generic::fwd_byte_by_byte(start, end, confirm); + } + + // The start of the search may not be aligned to `*const usize`, + // so we do an unaligned load here. + let chunk = start.cast::().read_unaligned(); + if self.has_needle(chunk) { + return generic::fwd_byte_by_byte(start, end, confirm); + } + + // And now we start our search at a guaranteed aligned position. + // The first iteration of the loop below will overlap with the + // unaligned chunk above in cases where the search starts at an + // unaligned offset, but that's okay as we're only here if that + // above didn't find a match. + let mut cur = + start.add(USIZE_BYTES - (start.as_usize() & USIZE_ALIGN)); + debug_assert!(cur > start); + debug_assert!(end.sub(USIZE_BYTES) >= start); + while cur <= end.sub(USIZE_BYTES) { + debug_assert_eq!(0, cur.as_usize() % USIZE_BYTES); + + let chunk = cur.cast::().read(); + if self.has_needle(chunk) { + break; + } + cur = cur.add(USIZE_BYTES); + } + generic::fwd_byte_by_byte(cur, end, confirm) + } + + /// Like `rfind`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn rfind_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + let confirm = |b| self.confirm(b); + let len = end.distance(start); + if len < USIZE_BYTES { + return generic::rev_byte_by_byte(start, end, confirm); + } + + let chunk = end.sub(USIZE_BYTES).cast::().read_unaligned(); + if self.has_needle(chunk) { + return generic::rev_byte_by_byte(start, end, confirm); + } + + let mut cur = end.sub(end.as_usize() & USIZE_ALIGN); + debug_assert!(start <= cur && cur <= end); + while cur >= start.add(USIZE_BYTES) { + debug_assert_eq!(0, cur.as_usize() % USIZE_BYTES); + + let chunk = cur.sub(USIZE_BYTES).cast::().read(); + if self.has_needle(chunk) { + break; + } + cur = cur.sub(USIZE_BYTES); + } + generic::rev_byte_by_byte(start, cur, confirm) + } + + /// Returns an iterator over all occurrences of one of the needle bytes in + /// the given haystack. + /// + /// The iterator returned implements `DoubleEndedIterator`. This means it + /// can also be used to find occurrences in reverse order. + pub fn iter<'a, 'h>(&'a self, haystack: &'h [u8]) -> ThreeIter<'a, 'h> { + ThreeIter { searcher: self, it: generic::Iter::new(haystack) } + } + + #[inline(always)] + fn has_needle(&self, chunk: usize) -> bool { + has_zero_byte(self.v1 ^ chunk) + || has_zero_byte(self.v2 ^ chunk) + || has_zero_byte(self.v3 ^ chunk) + } + + #[inline(always)] + fn confirm(&self, haystack_byte: u8) -> bool { + self.s1 == haystack_byte + || self.s2 == haystack_byte + || self.s3 == haystack_byte + } +} + +/// An iterator over all occurrences of three possible bytes in a haystack. +/// +/// This iterator implements `DoubleEndedIterator`, which means it can also be +/// used to find occurrences in reverse order. +/// +/// This iterator is created by the [`Three::iter`] method. +/// +/// The lifetime parameters are as follows: +/// +/// * `'a` refers to the lifetime of the underlying [`Three`] searcher. +/// * `'h` refers to the lifetime of the haystack being searched. +#[derive(Clone, Debug)] +pub struct ThreeIter<'a, 'h> { + /// The underlying memchr searcher. + searcher: &'a Three, + /// Generic iterator implementation. + it: generic::Iter<'h>, +} + +impl<'a, 'h> Iterator for ThreeIter<'a, 'h> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'find_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next(|s, e| self.searcher.find_raw(s, e)) } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, 'h> DoubleEndedIterator for ThreeIter<'a, 'h> { + #[inline] + fn next_back(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'rfind_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next_back(|s, e| self.searcher.rfind_raw(s, e)) } + } +} + +/// Return `true` if `x` contains any zero byte. +/// +/// That is, this routine treats `x` as a register of 8-bit lanes and returns +/// true when any of those lanes is `0`. +/// +/// From "Matters Computational" by J. Arndt. +#[inline(always)] +fn has_zero_byte(x: usize) -> bool { + // "The idea is to subtract one from each of the bytes and then look for + // bytes where the borrow propagated all the way to the most significant + // bit." + const LO: usize = splat(0x01); + const HI: usize = splat(0x80); + + (x.wrapping_sub(LO) & !x & HI) != 0 +} + +/// Repeat the given byte into a word size number. That is, every 8 bits +/// is equivalent to the given byte. For example, if `b` is `\x4E` or +/// `01001110` in binary, then the returned value on a 32-bit system would be: +/// `01001110_01001110_01001110_01001110`. +#[inline(always)] +const fn splat(b: u8) -> usize { + // TODO: use `usize::from` once it can be used in const context. + (b as usize) * (usize::MAX / 255) +} + +#[cfg(test)] +mod tests { + use super::*; + + define_memchr_quickcheck!(super, try_new); + + #[test] + fn forward_one() { + crate::tests::memchr::Runner::new(1).forward_iter( + |haystack, needles| { + Some(One::new(needles[0]).iter(haystack).collect()) + }, + ) + } + + #[test] + fn reverse_one() { + crate::tests::memchr::Runner::new(1).reverse_iter( + |haystack, needles| { + Some(One::new(needles[0]).iter(haystack).rev().collect()) + }, + ) + } + + #[test] + fn count_one() { + crate::tests::memchr::Runner::new(1).count_iter(|haystack, needles| { + Some(One::new(needles[0]).iter(haystack).count()) + }) + } + + #[test] + fn forward_two() { + crate::tests::memchr::Runner::new(2).forward_iter( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + Some(Two::new(n1, n2).iter(haystack).collect()) + }, + ) + } + + #[test] + fn reverse_two() { + crate::tests::memchr::Runner::new(2).reverse_iter( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + Some(Two::new(n1, n2).iter(haystack).rev().collect()) + }, + ) + } + + #[test] + fn forward_three() { + crate::tests::memchr::Runner::new(3).forward_iter( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + let n3 = needles.get(2).copied()?; + Some(Three::new(n1, n2, n3).iter(haystack).collect()) + }, + ) + } + + #[test] + fn reverse_three() { + crate::tests::memchr::Runner::new(3).reverse_iter( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + let n3 = needles.get(2).copied()?; + Some(Three::new(n1, n2, n3).iter(haystack).rev().collect()) + }, + ) + } + + // This was found by quickcheck in the course of refactoring this crate + // after memchr 2.5.0. + #[test] + fn regression_double_ended_iterator() { + let finder = One::new(b'a'); + let haystack = "a"; + let mut it = finder.iter(haystack.as_bytes()); + assert_eq!(Some(0), it.next()); + assert_eq!(None, it.next_back()); + } + + // This regression test was caught by ripgrep's test suite on i686 when + // upgrading to memchr 2.6. Namely, something about the \x0B bytes here + // screws with the SWAR counting approach I was using. This regression test + // prompted me to remove the SWAR counting approach and just replace it + // with a byte-at-a-time loop. + #[test] + fn regression_count_new_lines() { + let haystack = "01234567\x0b\n\x0b\n\x0b\n\x0b\nx"; + let count = One::new(b'\n').count(haystack.as_bytes()); + assert_eq!(4, count); + } + + // A test[1] that failed on some big endian targets after a perf + // improvement was merged[2]. + // + // At first it seemed like the test suite somehow missed the regression, + // but in actuality, CI was not running tests with `cross` but instead with + // `cargo` specifically. This is because those steps were using `cargo` + // instead of `${{ env.CARGO }}`. So adding this regression test doesn't + // really help catch that class of failure, but we add it anyway for good + // measure. + // + // [1]: https://github.com/BurntSushi/memchr/issues/152 + // [2]: https://github.com/BurntSushi/memchr/pull/151 + #[test] + fn regression_big_endian1() { + assert_eq!(One::new(b':').find(b"1:23"), Some(1)); + } + + // Interestingly, I couldn't get `regression_big_endian1` to fail for me + // on the `powerpc64-unknown-linux-gnu` target. But I found another case + // through quickcheck that does. + #[test] + fn regression_big_endian2() { + let data = [0, 0, 0, 0, 0, 0, 0, 0]; + assert_eq!(One::new(b'\x00').find(&data), Some(0)); + } +} diff --git a/third_party/crates/memchr-2.8.3/src/arch/all/mod.rs b/third_party/crates/memchr-2.8.3/src/arch/all/mod.rs new file mode 100644 index 0000000..559cb75 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/all/mod.rs @@ -0,0 +1,234 @@ +/*! +Contains architecture independent routines. + +These routines are often used as a "fallback" implementation when the more +specialized architecture dependent routines are unavailable. +*/ + +pub mod memchr; +pub mod packedpair; +pub mod rabinkarp; +#[cfg(feature = "alloc")] +pub mod shiftor; +pub mod twoway; + +/// Returns true if and only if `needle` is a prefix of `haystack`. +/// +/// This uses a latency optimized variant of `memcmp` internally which *might* +/// make this faster for very short strings. +/// +/// # Inlining +/// +/// This routine is marked `inline(always)`. If you want to call this function +/// in a way that is not always inlined, you'll need to wrap a call to it in +/// another function that is marked as `inline(never)` or just `inline`. +#[inline(always)] +pub fn is_prefix(haystack: &[u8], needle: &[u8]) -> bool { + needle.len() <= haystack.len() + && is_equal(&haystack[..needle.len()], needle) +} + +/// Returns true if and only if `needle` is a suffix of `haystack`. +/// +/// This uses a latency optimized variant of `memcmp` internally which *might* +/// make this faster for very short strings. +/// +/// # Inlining +/// +/// This routine is marked `inline(always)`. If you want to call this function +/// in a way that is not always inlined, you'll need to wrap a call to it in +/// another function that is marked as `inline(never)` or just `inline`. +#[inline(always)] +pub fn is_suffix(haystack: &[u8], needle: &[u8]) -> bool { + needle.len() <= haystack.len() + && is_equal(&haystack[haystack.len() - needle.len()..], needle) +} + +/// Compare corresponding bytes in `x` and `y` for equality. +/// +/// That is, this returns true if and only if `x.len() == y.len()` and +/// `x[i] == y[i]` for all `0 <= i < x.len()`. +/// +/// # Inlining +/// +/// This routine is marked `inline(always)`. If you want to call this function +/// in a way that is not always inlined, you'll need to wrap a call to it in +/// another function that is marked as `inline(never)` or just `inline`. +/// +/// # Motivation +/// +/// Why not use slice equality instead? Well, slice equality usually results in +/// a call out to the current platform's `libc` which might not be inlineable +/// or have other overhead. This routine isn't guaranteed to be a win, but it +/// might be in some cases. +#[inline(always)] +pub fn is_equal(x: &[u8], y: &[u8]) -> bool { + if x.len() != y.len() { + return false; + } + // SAFETY: Our pointers are derived directly from borrowed slices which + // uphold all of our safety guarantees except for length. We account for + // length with the check above. + unsafe { is_equal_raw(x.as_ptr(), y.as_ptr(), x.len()) } +} + +/// Compare `n` bytes at the given pointers for equality. +/// +/// This returns true if and only if `*x.add(i) == *y.add(i)` for all +/// `0 <= i < n`. +/// +/// # Inlining +/// +/// This routine is marked `inline(always)`. If you want to call this function +/// in a way that is not always inlined, you'll need to wrap a call to it in +/// another function that is marked as `inline(never)` or just `inline`. +/// +/// # Motivation +/// +/// Why not use slice equality instead? Well, slice equality usually results in +/// a call out to the current platform's `libc` which might not be inlineable +/// or have other overhead. This routine isn't guaranteed to be a win, but it +/// might be in some cases. +/// +/// # Safety +/// +/// * Both `x` and `y` must be valid for reads of up to `n` bytes. +/// * Both `x` and `y` must point to an initialized value. +/// * Both `x` and `y` must each point to an allocated object and +/// must either be in bounds or at most one byte past the end of the +/// allocated object. `x` and `y` do not need to point to the same allocated +/// object, but they may. +/// * Both `x` and `y` must be _derived from_ a pointer to their respective +/// allocated objects. +/// * The distance between `x` and `x+n` must not overflow `isize`. Similarly +/// for `y` and `y+n`. +/// * The distance being in bounds must not rely on "wrapping around" the +/// address space. +#[inline(always)] +pub unsafe fn is_equal_raw( + mut x: *const u8, + mut y: *const u8, + mut n: usize, +) -> bool { + // When we have 4 or more bytes to compare, then proceed in chunks of 4 at + // a time using unaligned loads. + // + // Also, why do 4 byte loads instead of, say, 8 byte loads? The reason is + // that this particular version of memcmp is likely to be called with tiny + // needles. That means that if we do 8 byte loads, then a higher proportion + // of memcmp calls will use the slower variant above. With that said, this + // is a hypothesis and is only loosely supported by benchmarks. There's + // likely some improvement that could be made here. The main thing here + // though is to optimize for latency, not throughput. + + // SAFETY: The caller is responsible for ensuring the pointers we get are + // valid and readable for at least `n` bytes. We also do unaligned loads, + // so there's no need to ensure we're aligned. (This is justified by this + // routine being specifically for short strings.) + while n >= 4 { + let vx = x.cast::().read_unaligned(); + let vy = y.cast::().read_unaligned(); + if vx != vy { + return false; + } + x = x.add(4); + y = y.add(4); + n -= 4; + } + // If we don't have enough bytes to do 4-byte at a time loads, then + // do partial loads. Note that I used to have a byte-at-a-time + // loop here and that turned out to be quite a bit slower for the + // memmem/pathological/defeat-simple-vector-alphabet benchmark. + if n >= 2 { + let vx = x.cast::().read_unaligned(); + let vy = y.cast::().read_unaligned(); + if vx != vy { + return false; + } + x = x.add(2); + y = y.add(2); + n -= 2; + } + if n > 0 { + if x.read() != y.read() { + return false; + } + } + true +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn equals_different_lengths() { + assert!(!is_equal(b"", b"a")); + assert!(!is_equal(b"a", b"")); + assert!(!is_equal(b"ab", b"a")); + assert!(!is_equal(b"a", b"ab")); + } + + #[test] + fn equals_mismatch() { + let one_mismatch = [ + (&b"a"[..], &b"x"[..]), + (&b"ab"[..], &b"ax"[..]), + (&b"abc"[..], &b"abx"[..]), + (&b"abcd"[..], &b"abcx"[..]), + (&b"abcde"[..], &b"abcdx"[..]), + (&b"abcdef"[..], &b"abcdex"[..]), + (&b"abcdefg"[..], &b"abcdefx"[..]), + (&b"abcdefgh"[..], &b"abcdefgx"[..]), + (&b"abcdefghi"[..], &b"abcdefghx"[..]), + (&b"abcdefghij"[..], &b"abcdefghix"[..]), + (&b"abcdefghijk"[..], &b"abcdefghijx"[..]), + (&b"abcdefghijkl"[..], &b"abcdefghijkx"[..]), + (&b"abcdefghijklm"[..], &b"abcdefghijklx"[..]), + (&b"abcdefghijklmn"[..], &b"abcdefghijklmx"[..]), + ]; + for (x, y) in one_mismatch { + assert_eq!(x.len(), y.len(), "lengths should match"); + assert!(!is_equal(x, y)); + assert!(!is_equal(y, x)); + } + } + + #[test] + fn equals_yes() { + assert!(is_equal(b"", b"")); + assert!(is_equal(b"a", b"a")); + assert!(is_equal(b"ab", b"ab")); + assert!(is_equal(b"abc", b"abc")); + assert!(is_equal(b"abcd", b"abcd")); + assert!(is_equal(b"abcde", b"abcde")); + assert!(is_equal(b"abcdef", b"abcdef")); + assert!(is_equal(b"abcdefg", b"abcdefg")); + assert!(is_equal(b"abcdefgh", b"abcdefgh")); + assert!(is_equal(b"abcdefghi", b"abcdefghi")); + } + + #[test] + fn prefix() { + assert!(is_prefix(b"", b"")); + assert!(is_prefix(b"a", b"")); + assert!(is_prefix(b"ab", b"")); + assert!(is_prefix(b"foo", b"foo")); + assert!(is_prefix(b"foobar", b"foo")); + + assert!(!is_prefix(b"foo", b"fob")); + assert!(!is_prefix(b"foobar", b"fob")); + } + + #[test] + fn suffix() { + assert!(is_suffix(b"", b"")); + assert!(is_suffix(b"a", b"")); + assert!(is_suffix(b"ab", b"")); + assert!(is_suffix(b"foo", b"foo")); + assert!(is_suffix(b"foobar", b"bar")); + + assert!(!is_suffix(b"foo", b"goo")); + assert!(!is_suffix(b"foobar", b"gar")); + } +} diff --git a/third_party/crates/memchr-2.8.3/src/arch/all/packedpair/default_rank.rs b/third_party/crates/memchr-2.8.3/src/arch/all/packedpair/default_rank.rs new file mode 100644 index 0000000..6aa3895 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/all/packedpair/default_rank.rs @@ -0,0 +1,258 @@ +pub(crate) const RANK: [u8; 256] = [ + 55, // '\x00' + 52, // '\x01' + 51, // '\x02' + 50, // '\x03' + 49, // '\x04' + 48, // '\x05' + 47, // '\x06' + 46, // '\x07' + 45, // '\x08' + 103, // '\t' + 242, // '\n' + 66, // '\x0b' + 67, // '\x0c' + 229, // '\r' + 44, // '\x0e' + 43, // '\x0f' + 42, // '\x10' + 41, // '\x11' + 40, // '\x12' + 39, // '\x13' + 38, // '\x14' + 37, // '\x15' + 36, // '\x16' + 35, // '\x17' + 34, // '\x18' + 33, // '\x19' + 56, // '\x1a' + 32, // '\x1b' + 31, // '\x1c' + 30, // '\x1d' + 29, // '\x1e' + 28, // '\x1f' + 255, // ' ' + 148, // '!' + 164, // '"' + 149, // '#' + 136, // '$' + 160, // '%' + 155, // '&' + 173, // "'" + 221, // '(' + 222, // ')' + 134, // '*' + 122, // '+' + 232, // ',' + 202, // '-' + 215, // '.' + 224, // '/' + 208, // '0' + 220, // '1' + 204, // '2' + 187, // '3' + 183, // '4' + 179, // '5' + 177, // '6' + 168, // '7' + 178, // '8' + 200, // '9' + 226, // ':' + 195, // ';' + 154, // '<' + 184, // '=' + 174, // '>' + 126, // '?' + 120, // '@' + 191, // 'A' + 157, // 'B' + 194, // 'C' + 170, // 'D' + 189, // 'E' + 162, // 'F' + 161, // 'G' + 150, // 'H' + 193, // 'I' + 142, // 'J' + 137, // 'K' + 171, // 'L' + 176, // 'M' + 185, // 'N' + 167, // 'O' + 186, // 'P' + 112, // 'Q' + 175, // 'R' + 192, // 'S' + 188, // 'T' + 156, // 'U' + 140, // 'V' + 143, // 'W' + 123, // 'X' + 133, // 'Y' + 128, // 'Z' + 147, // '[' + 138, // '\\' + 146, // ']' + 114, // '^' + 223, // '_' + 151, // '`' + 249, // 'a' + 216, // 'b' + 238, // 'c' + 236, // 'd' + 253, // 'e' + 227, // 'f' + 218, // 'g' + 230, // 'h' + 247, // 'i' + 135, // 'j' + 180, // 'k' + 241, // 'l' + 233, // 'm' + 246, // 'n' + 244, // 'o' + 231, // 'p' + 139, // 'q' + 245, // 'r' + 243, // 's' + 251, // 't' + 235, // 'u' + 201, // 'v' + 196, // 'w' + 240, // 'x' + 214, // 'y' + 152, // 'z' + 182, // '{' + 205, // '|' + 181, // '}' + 127, // '~' + 27, // '\x7f' + 212, // '\x80' + 211, // '\x81' + 210, // '\x82' + 213, // '\x83' + 228, // '\x84' + 197, // '\x85' + 169, // '\x86' + 159, // '\x87' + 131, // '\x88' + 172, // '\x89' + 105, // '\x8a' + 80, // '\x8b' + 98, // '\x8c' + 96, // '\x8d' + 97, // '\x8e' + 81, // '\x8f' + 207, // '\x90' + 145, // '\x91' + 116, // '\x92' + 115, // '\x93' + 144, // '\x94' + 130, // '\x95' + 153, // '\x96' + 121, // '\x97' + 107, // '\x98' + 132, // '\x99' + 109, // '\x9a' + 110, // '\x9b' + 124, // '\x9c' + 111, // '\x9d' + 82, // '\x9e' + 108, // '\x9f' + 118, // '\xa0' + 141, // '¡' + 113, // '¢' + 129, // '£' + 119, // '¤' + 125, // '¥' + 165, // '¦' + 117, // '§' + 92, // '¨' + 106, // '©' + 83, // 'ª' + 72, // '«' + 99, // '¬' + 93, // '\xad' + 65, // '®' + 79, // '¯' + 166, // '°' + 237, // '±' + 163, // '²' + 199, // '³' + 190, // '´' + 225, // 'µ' + 209, // '¶' + 203, // '·' + 198, // '¸' + 217, // '¹' + 219, // 'º' + 206, // '»' + 234, // '¼' + 248, // '½' + 158, // '¾' + 239, // '¿' + 255, // 'À' + 255, // 'Á' + 255, // 'Â' + 255, // 'Ã' + 255, // 'Ä' + 255, // 'Å' + 255, // 'Æ' + 255, // 'Ç' + 255, // 'È' + 255, // 'É' + 255, // 'Ê' + 255, // 'Ë' + 255, // 'Ì' + 255, // 'Í' + 255, // 'Î' + 255, // 'Ï' + 255, // 'Ð' + 255, // 'Ñ' + 255, // 'Ò' + 255, // 'Ó' + 255, // 'Ô' + 255, // 'Õ' + 255, // 'Ö' + 255, // '×' + 255, // 'Ø' + 255, // 'Ù' + 255, // 'Ú' + 255, // 'Û' + 255, // 'Ü' + 255, // 'Ý' + 255, // 'Þ' + 255, // 'ß' + 255, // 'à' + 255, // 'á' + 255, // 'â' + 255, // 'ã' + 255, // 'ä' + 255, // 'å' + 255, // 'æ' + 255, // 'ç' + 255, // 'è' + 255, // 'é' + 255, // 'ê' + 255, // 'ë' + 255, // 'ì' + 255, // 'í' + 255, // 'î' + 255, // 'ï' + 255, // 'ð' + 255, // 'ñ' + 255, // 'ò' + 255, // 'ó' + 255, // 'ô' + 255, // 'õ' + 255, // 'ö' + 255, // '÷' + 255, // 'ø' + 255, // 'ù' + 255, // 'ú' + 255, // 'û' + 255, // 'ü' + 255, // 'ý' + 255, // 'þ' + 255, // 'ÿ' +]; diff --git a/third_party/crates/memchr-2.8.3/src/arch/all/packedpair/mod.rs b/third_party/crates/memchr-2.8.3/src/arch/all/packedpair/mod.rs new file mode 100644 index 0000000..148a985 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/all/packedpair/mod.rs @@ -0,0 +1,359 @@ +/*! +Provides an architecture independent implementation of the "packed pair" +algorithm. + +The "packed pair" algorithm is based on the [generic SIMD] algorithm. The main +difference is that it (by default) uses a background distribution of byte +frequencies to heuristically select the pair of bytes to search for. Note that +this module provides an architecture independent version that doesn't do as +good of a job keeping the search for candidates inside a SIMD hot path. It +however can be good enough in many circumstances. + +[generic SIMD]: http://0x80.pl/articles/simd-strfind.html#first-and-last +*/ + +use crate::memchr; + +mod default_rank; + +/// An architecture independent "packed pair" finder. +/// +/// This finder picks two bytes that it believes have high predictive power for +/// indicating an overall match of a needle. At search time, it reports offsets +/// where the needle could match based on whether the pair of bytes it chose +/// match. +/// +/// This is architecture independent because it utilizes `memchr` to find the +/// occurrence of one of the bytes in the pair, and then checks whether the +/// second byte matches. If it does, in the case of [`Finder::find_prefilter`], +/// the location at which the needle could match is returned. +/// +/// It is generally preferred to use architecture specific routines for a +/// "packed pair" prefilter, but this can be a useful fallback when the +/// architecture independent routines are unavailable. +#[derive(Clone, Copy, Debug)] +pub struct Finder { + pair: Pair, + byte1: u8, + byte2: u8, +} + +impl Finder { + /// Create a new prefilter that reports possible locations where the given + /// needle matches. + #[inline] + pub fn new(needle: &[u8]) -> Option { + Finder::with_pair(needle, Pair::new(needle)?) + } + + /// Create a new prefilter using the pair given. + /// + /// If the prefilter could not be constructed, then `None` is returned. + /// + /// This constructor permits callers to control precisely which pair of + /// bytes is used as a predicate. + #[inline] + pub fn with_pair(needle: &[u8], pair: Pair) -> Option { + let byte1 = needle[usize::from(pair.index1())]; + let byte2 = needle[usize::from(pair.index2())]; + // Currently this can never fail so we could just return a Finder, + // but it's conceivable this could change. + Some(Finder { pair, byte1, byte2 }) + } + + /// Run this finder on the given haystack as a prefilter. + /// + /// If a candidate match is found, then an offset where the needle *could* + /// begin in the haystack is returned. + #[inline] + pub fn find_prefilter(&self, haystack: &[u8]) -> Option { + let mut i = 0; + let index1 = usize::from(self.pair.index1()); + let index2 = usize::from(self.pair.index2()); + loop { + // Use a fast vectorized implementation to skip to the next + // occurrence of the rarest byte (heuristically chosen) in the + // needle. + i += memchr(self.byte1, &haystack[i..])?; + let found = i; + i += 1; + + // If we can't align our first byte match with the haystack, then a + // match is impossible. + let aligned1 = match found.checked_sub(index1) { + None => continue, + Some(aligned1) => aligned1, + }; + + // Now align the second byte match with the haystack. A mismatch + // means that a match is impossible. + let aligned2 = match aligned1.checked_add(index2) { + None => continue, + Some(aligned_index2) => aligned_index2, + }; + if haystack.get(aligned2).map_or(true, |&b| b != self.byte2) { + continue; + } + + // We've done what we can. There might be a match here. + return Some(aligned1); + } + } + + /// Returns the pair of offsets (into the needle) used to check as a + /// predicate before confirming whether a needle exists at a particular + /// position. + #[inline] + pub fn pair(&self) -> &Pair { + &self.pair + } +} + +/// A pair of byte offsets into a needle to use as a predicate. +/// +/// This pair is used as a predicate to quickly filter out positions in a +/// haystack in which a needle cannot match. In some cases, this pair can even +/// be used in vector algorithms such that the vector algorithm only switches +/// over to scalar code once this pair has been found. +/// +/// A pair of offsets can be used in both substring search implementations and +/// in prefilters. The former will report matches of a needle in a haystack +/// where as the latter will only report possible matches of a needle. +/// +/// The offsets are limited each to a maximum of 255 to keep memory usage low. +/// Moreover, it's rarely advantageous to create a predicate using offsets +/// greater than 255 anyway. +/// +/// The only guarantee enforced on the pair of offsets is that they are not +/// equivalent. It is not necessarily the case that `index1 < index2` for +/// example. By convention, `index1` corresponds to the byte in the needle +/// that is believed to be most the predictive. Note also that because of the +/// requirement that the indices be both valid for the needle used to build +/// the pair and not equal, it follows that a pair can only be constructed for +/// needles with length at least 2. +#[derive(Clone, Copy, Debug)] +pub struct Pair { + index1: u8, + index2: u8, +} + +impl Pair { + /// Create a new pair of offsets from the given needle. + /// + /// If a pair could not be created (for example, if the needle is too + /// short), then `None` is returned. + /// + /// This chooses the pair in the needle that is believed to be as + /// predictive of an overall match of the needle as possible. + #[inline] + pub fn new(needle: &[u8]) -> Option { + Pair::with_ranker(needle, DefaultFrequencyRank) + } + + /// Create a new pair of offsets from the given needle and ranker. + /// + /// This permits the caller to choose a background frequency distribution + /// with which bytes are selected. The idea is to select a pair of bytes + /// that is believed to strongly predict a match in the haystack. This + /// usually means selecting bytes that occur rarely in a haystack. + /// + /// If a pair could not be created (for example, if the needle is too + /// short), then `None` is returned. + #[inline] + pub fn with_ranker( + needle: &[u8], + ranker: R, + ) -> Option { + if needle.len() <= 1 { + return None; + } + // Find the rarest two bytes. We make them distinct indices by + // construction. (The actual byte value may be the same in degenerate + // cases, but that's OK.) + let (mut rare1, mut index1) = (needle[0], 0); + let (mut rare2, mut index2) = (needle[1], 1); + if ranker.rank(rare2) < ranker.rank(rare1) { + core::mem::swap(&mut rare1, &mut rare2); + core::mem::swap(&mut index1, &mut index2); + } + let max = usize::from(core::u8::MAX); + for (i, &b) in needle.iter().enumerate().take(max).skip(2) { + if ranker.rank(b) < ranker.rank(rare1) { + rare2 = rare1; + index2 = index1; + rare1 = b; + index1 = u8::try_from(i).unwrap(); + } else if b != rare1 && ranker.rank(b) < ranker.rank(rare2) { + rare2 = b; + index2 = u8::try_from(i).unwrap(); + } + } + // While not strictly required for how a Pair is normally used, we + // really don't want these to be equivalent. If they were, it would + // reduce the effectiveness of candidate searching using these rare + // bytes by increasing the rate of false positives. + assert_ne!(index1, index2); + Some(Pair { index1, index2 }) + } + + /// Create a new pair using the offsets given for the needle given. + /// + /// This bypasses any sort of heuristic process for choosing the offsets + /// and permits the caller to choose the offsets themselves. + /// + /// Indices are limited to valid `u8` values so that a `Pair` uses less + /// memory. It is not possible to create a `Pair` with offsets bigger than + /// `u8::MAX`. It's likely that such a thing is not needed, but if it is, + /// it's suggested to build your own bespoke algorithm because you're + /// likely working on a very niche case. (File an issue if this suggestion + /// does not make sense to you.) + /// + /// If a pair could not be created (for example, if the needle is too + /// short), then `None` is returned. + #[inline] + pub fn with_indices( + needle: &[u8], + index1: u8, + index2: u8, + ) -> Option { + // While not strictly required for how a Pair is normally used, we + // really don't want these to be equivalent. If they were, it would + // reduce the effectiveness of candidate searching using these rare + // bytes by increasing the rate of false positives. + if index1 == index2 { + return None; + } + // Similarly, invalid indices means the Pair is invalid too. + if usize::from(index1) >= needle.len() { + return None; + } + if usize::from(index2) >= needle.len() { + return None; + } + Some(Pair { index1, index2 }) + } + + /// Returns the first offset of the pair. + #[inline] + pub fn index1(&self) -> u8 { + self.index1 + } + + /// Returns the second offset of the pair. + #[inline] + pub fn index2(&self) -> u8 { + self.index2 + } +} + +/// This trait allows the user to customize the heuristic used to determine the +/// relative frequency of a given byte in the dataset being searched. +/// +/// The use of this trait can have a dramatic impact on performance depending +/// on the type of data being searched. The details of why are explained in the +/// docs of [`crate::memmem::Prefilter`]. To summarize, the core algorithm uses +/// a prefilter to quickly identify candidate matches that are later verified +/// more slowly. This prefilter is implemented in terms of trying to find +/// `rare` bytes at specific offsets that will occur less frequently in the +/// dataset. While the concept of a `rare` byte is similar for most datasets, +/// there are some specific datasets (like binary executables) that have +/// dramatically different byte distributions. For these datasets customizing +/// the byte frequency heuristic can have a massive impact on performance, and +/// might even need to be done at runtime. +/// +/// The default implementation of `HeuristicFrequencyRank` reads from the +/// static frequency table defined in `src/memmem/byte_frequencies.rs`. This +/// is optimal for most inputs, so if you are unsure of the impact of using a +/// custom `HeuristicFrequencyRank` you should probably just use the default. +/// +/// # Example +/// +/// ``` +/// use memchr::{ +/// arch::all::packedpair::HeuristicFrequencyRank, +/// memmem::FinderBuilder, +/// }; +/// +/// /// A byte-frequency table that is good for scanning binary executables. +/// struct Binary; +/// +/// impl HeuristicFrequencyRank for Binary { +/// fn rank(&self, byte: u8) -> u8 { +/// const TABLE: [u8; 256] = [ +/// 255, 128, 61, 43, 50, 41, 27, 28, 57, 15, 21, 13, 24, 17, 17, +/// 89, 58, 16, 11, 7, 14, 23, 7, 6, 24, 9, 6, 5, 9, 4, 7, 16, +/// 68, 11, 9, 6, 88, 7, 4, 4, 23, 9, 4, 8, 8, 5, 10, 4, 30, 11, +/// 9, 24, 11, 5, 5, 5, 19, 11, 6, 17, 9, 9, 6, 8, +/// 48, 58, 11, 14, 53, 40, 9, 9, 254, 35, 3, 6, 52, 23, 6, 6, 27, +/// 4, 7, 11, 14, 13, 10, 11, 11, 5, 2, 10, 16, 12, 6, 19, +/// 19, 20, 5, 14, 16, 31, 19, 7, 14, 20, 4, 4, 19, 8, 18, 20, 24, +/// 1, 25, 19, 58, 29, 10, 5, 15, 20, 2, 2, 9, 4, 3, 5, +/// 51, 11, 4, 53, 23, 39, 6, 4, 13, 81, 4, 186, 5, 67, 3, 2, 15, +/// 0, 0, 1, 3, 2, 0, 0, 5, 0, 0, 0, 2, 0, 0, 0, +/// 12, 2, 1, 1, 3, 1, 1, 1, 6, 1, 2, 1, 3, 1, 1, 2, 9, 1, 1, 0, +/// 2, 2, 4, 4, 11, 6, 7, 3, 6, 9, 4, 5, +/// 46, 18, 8, 18, 17, 3, 8, 20, 16, 10, 3, 7, 175, 4, 6, 7, 13, +/// 3, 7, 3, 3, 1, 3, 3, 10, 3, 1, 5, 2, 0, 1, 2, +/// 16, 3, 5, 1, 6, 1, 1, 2, 58, 20, 3, 14, 12, 2, 1, 3, 16, 3, 5, +/// 8, 3, 1, 8, 6, 17, 6, 5, 3, 8, 6, 13, 175, +/// ]; +/// TABLE[byte as usize] +/// } +/// } +/// // Create a new finder with the custom heuristic. +/// let finder = FinderBuilder::new() +/// .build_forward_with_ranker(Binary, b"\x00\x00\xdd\xdd"); +/// // Find needle with custom heuristic. +/// assert!(finder.find(b"\x00\x00\x00\xdd\xdd").is_some()); +/// ``` +pub trait HeuristicFrequencyRank { + /// Return the heuristic frequency rank of the given byte. A lower rank + /// means the byte is believed to occur less frequently in the haystack. + /// + /// Some uses of this heuristic may treat arbitrary absolute rank values as + /// significant. For example, an implementation detail in this crate may + /// determine that heuristic prefilters are inappropriate if every byte in + /// the needle has a "high" rank. + fn rank(&self, byte: u8) -> u8; +} + +/// The default byte frequency heuristic that is good for most haystacks. +pub(crate) struct DefaultFrequencyRank; + +impl HeuristicFrequencyRank for DefaultFrequencyRank { + fn rank(&self, byte: u8) -> u8 { + self::default_rank::RANK[usize::from(byte)] + } +} + +/// This permits passing any implementation of `HeuristicFrequencyRank` as a +/// borrowed version of itself. +impl<'a, R> HeuristicFrequencyRank for &'a R +where + R: HeuristicFrequencyRank, +{ + fn rank(&self, byte: u8) -> u8 { + (**self).rank(byte) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn forward_packedpair() { + fn find( + haystack: &[u8], + needle: &[u8], + _index1: u8, + _index2: u8, + ) -> Option> { + // We ignore the index positions requested since it winds up making + // this test too slow overall. + let f = Finder::new(needle)?; + Some(f.find_prefilter(haystack)) + } + crate::tests::packedpair::Runner::new().fwd(find).run() + } +} diff --git a/third_party/crates/memchr-2.8.3/src/arch/all/rabinkarp.rs b/third_party/crates/memchr-2.8.3/src/arch/all/rabinkarp.rs new file mode 100644 index 0000000..ce14795 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/all/rabinkarp.rs @@ -0,0 +1,390 @@ +/*! +An implementation of the [Rabin-Karp substring search algorithm][rabinkarp]. + +Rabin-Karp works by creating a hash of the needle provided and then computing +a rolling hash for each needle sized window in the haystack. When the rolling +hash matches the hash of the needle, a byte-wise comparison is done to check +if a match exists. The worst case time complexity of Rabin-Karp is `O(m * +n)` where `m ~ len(needle)` and `n ~ len(haystack)`. Its worst case space +complexity is constant. + +The main utility of Rabin-Karp is that the searcher can be constructed very +quickly with very little memory. This makes it especially useful when searching +for small needles in small haystacks, as it might finish its search before a +beefier algorithm (like Two-Way) even starts. + +[rabinkarp]: https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm +*/ + +/* +(This was the comment I wrote for this module originally when it was not +exposed. The comment still looks useful, but it's a bit in the weeds, so it's +not public itself.) + +This module implements the classical Rabin-Karp substring search algorithm, +with no extra frills. While its use would seem to break our time complexity +guarantee of O(m+n) (RK's time complexity is O(mn)), we are careful to only +ever use RK on a constant subset of haystacks. The main point here is that +RK has good latency properties for small needles/haystacks. It's very quick +to compute a needle hash and zip through the haystack when compared to +initializing Two-Way, for example. And this is especially useful for cases +where the haystack is just too short for vector instructions to do much good. + +The hashing function used here is the same one recommended by ESMAJ. + +Another choice instead of Rabin-Karp would be Shift-Or. But its latency +isn't quite as good since its preprocessing time is a bit more expensive +(both in practice and in theory). However, perhaps Shift-Or has a place +somewhere else for short patterns. I think the main problem is that it +requires space proportional to the alphabet and the needle. If we, for +example, supported needles up to length 16, then the total table size would be +len(alphabet)*size_of::()==512 bytes. Which isn't exactly small, and it's +probably bad to put that on the stack. So ideally, we'd throw it on the heap, +but we'd really like to write as much code without using alloc/std as possible. +But maybe it's worth the special casing. It's a TODO to benchmark. + +Wikipedia has a decent explanation, if a bit heavy on the theory: +https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm + +But ESMAJ provides something a bit more concrete: +http://www-igm.univ-mlv.fr/~lecroq/string/node5.html + +Finally, aho-corasick uses Rabin-Karp for multiple pattern match in some cases: +https://github.com/BurntSushi/aho-corasick/blob/3852632f10587db0ff72ef29e88d58bf305a0946/src/packed/rabinkarp.rs +*/ + +use crate::ext::Pointer; + +/// A forward substring searcher using the Rabin-Karp algorithm. +/// +/// Note that, as a lower level API, a `Finder` does not have access to the +/// needle it was constructed with. For this reason, executing a search +/// with a `Finder` requires passing both the needle and the haystack, +/// where the needle is exactly equivalent to the one given to the `Finder` +/// at construction time. This design was chosen so that callers can have +/// more precise control over where and how many times a needle is stored. +/// For example, in cases where Rabin-Karp is just one of several possible +/// substring search algorithms. +#[derive(Clone, Debug)] +pub struct Finder { + /// The actual hash. + hash: Hash, + /// The factor needed to multiply a byte by in order to subtract it from + /// the hash. It is defined to be 2^(n-1) (using wrapping exponentiation), + /// where n is the length of the needle. This is how we "remove" a byte + /// from the hash once the hash window rolls past it. + hash_2pow: u32, +} + +impl Finder { + /// Create a new Rabin-Karp forward searcher for the given `needle`. + /// + /// The needle may be empty. The empty needle matches at every byte offset. + /// + /// Note that callers must pass the same needle to all search calls using + /// this `Finder`. + #[inline] + pub fn new(needle: &[u8]) -> Finder { + let mut s = Finder { hash: Hash::new(), hash_2pow: 1 }; + let first_byte = match needle.first() { + None => return s, + Some(&first_byte) => first_byte, + }; + s.hash.add(first_byte); + for b in needle.iter().copied().skip(1) { + s.hash.add(b); + s.hash_2pow = s.hash_2pow.wrapping_shl(1); + } + s + } + + /// Return the first occurrence of the `needle` in the `haystack` + /// given. If no such occurrence exists, then `None` is returned. + /// + /// The `needle` provided must match the needle given to this finder at + /// construction time. + /// + /// The maximum value this can return is `haystack.len()`, which can only + /// occur when the needle and haystack both have length zero. Otherwise, + /// for non-empty haystacks, the maximum value is `haystack.len() - 1`. + #[inline] + pub fn find(&self, haystack: &[u8], needle: &[u8]) -> Option { + unsafe { + let hstart = haystack.as_ptr(); + let hend = hstart.add(haystack.len()); + let nstart = needle.as_ptr(); + let nend = nstart.add(needle.len()); + let found = self.find_raw(hstart, hend, nstart, nend)?; + Some(found.distance(hstart)) + } + } + + /// Like `find`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `<= end`. The pointer returned is only ever equivalent + /// to `end` when both the needle and haystack are empty. (That is, the + /// empty string matches the empty string.) + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// Note that `start` and `end` below refer to both pairs of pointers given + /// to this routine. That is, the conditions apply to both `hstart`/`hend` + /// and `nstart`/`nend`. + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// * It must be the case that `start <= end`. + #[inline] + pub unsafe fn find_raw( + &self, + hstart: *const u8, + hend: *const u8, + nstart: *const u8, + nend: *const u8, + ) -> Option<*const u8> { + let hlen = hend.distance(hstart); + let nlen = nend.distance(nstart); + if nlen > hlen { + return None; + } + let mut cur = hstart; + let end = hend.sub(nlen); + let mut hash = Hash::forward(cur, cur.add(nlen)); + loop { + if self.hash == hash && is_equal_raw(cur, nstart, nlen) { + return Some(cur); + } + if cur >= end { + return None; + } + hash.roll(self, cur.read(), cur.add(nlen).read()); + cur = cur.add(1); + } + } +} + +/// A reverse substring searcher using the Rabin-Karp algorithm. +#[derive(Clone, Debug)] +pub struct FinderRev(Finder); + +impl FinderRev { + /// Create a new Rabin-Karp reverse searcher for the given `needle`. + #[inline] + pub fn new(needle: &[u8]) -> FinderRev { + let mut s = FinderRev(Finder { hash: Hash::new(), hash_2pow: 1 }); + let last_byte = match needle.last() { + None => return s, + Some(&last_byte) => last_byte, + }; + s.0.hash.add(last_byte); + for b in needle.iter().rev().copied().skip(1) { + s.0.hash.add(b); + s.0.hash_2pow = s.0.hash_2pow.wrapping_shl(1); + } + s + } + + /// Return the last occurrence of the `needle` in the `haystack` + /// given. If no such occurrence exists, then `None` is returned. + /// + /// The `needle` provided must match the needle given to this finder at + /// construction time. + /// + /// The maximum value this can return is `haystack.len()`, which can only + /// occur when the needle and haystack both have length zero. Otherwise, + /// for non-empty haystacks, the maximum value is `haystack.len() - 1`. + #[inline] + pub fn rfind(&self, haystack: &[u8], needle: &[u8]) -> Option { + unsafe { + let hstart = haystack.as_ptr(); + let hend = hstart.add(haystack.len()); + let nstart = needle.as_ptr(); + let nend = nstart.add(needle.len()); + let found = self.rfind_raw(hstart, hend, nstart, nend)?; + Some(found.distance(hstart)) + } + } + + /// Like `rfind`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `<= end`. The pointer returned is only ever equivalent + /// to `end` when both the needle and haystack are empty. (That is, the + /// empty string matches the empty string.) + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// Note that `start` and `end` below refer to both pairs of pointers given + /// to this routine. That is, the conditions apply to both `hstart`/`hend` + /// and `nstart`/`nend`. + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// * It must be the case that `start <= end`. + #[inline] + pub unsafe fn rfind_raw( + &self, + hstart: *const u8, + hend: *const u8, + nstart: *const u8, + nend: *const u8, + ) -> Option<*const u8> { + let hlen = hend.distance(hstart); + let nlen = nend.distance(nstart); + if nlen > hlen { + return None; + } + let mut cur = hend.sub(nlen); + let start = hstart; + let mut hash = Hash::reverse(cur, cur.add(nlen)); + loop { + if self.0.hash == hash && is_equal_raw(cur, nstart, nlen) { + return Some(cur); + } + if cur <= start { + return None; + } + cur = cur.sub(1); + hash.roll(&self.0, cur.add(nlen).read(), cur.read()); + } + } +} + +/// Whether RK is believed to be very fast for the given needle/haystack. +#[inline] +pub(crate) fn is_fast(haystack: &[u8], _needle: &[u8]) -> bool { + haystack.len() < 16 +} + +/// A Rabin-Karp hash. This might represent the hash of a needle, or the hash +/// of a rolling window in the haystack. +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] +struct Hash(u32); + +impl Hash { + /// Create a new hash that represents the empty string. + #[inline(always)] + fn new() -> Hash { + Hash(0) + } + + /// Create a new hash from the bytes given for use in forward searches. + /// + /// # Safety + /// + /// The given pointers must be valid to read from within their range. + #[inline(always)] + unsafe fn forward(mut start: *const u8, end: *const u8) -> Hash { + let mut hash = Hash::new(); + while start < end { + hash.add(start.read()); + start = start.add(1); + } + hash + } + + /// Create a new hash from the bytes given for use in reverse searches. + /// + /// # Safety + /// + /// The given pointers must be valid to read from within their range. + #[inline(always)] + unsafe fn reverse(start: *const u8, mut end: *const u8) -> Hash { + let mut hash = Hash::new(); + while start < end { + end = end.sub(1); + hash.add(end.read()); + } + hash + } + + /// Add 'new' and remove 'old' from this hash. The given needle hash should + /// correspond to the hash computed for the needle being searched for. + /// + /// This is meant to be used when the rolling window of the haystack is + /// advanced. + #[inline(always)] + fn roll(&mut self, finder: &Finder, old: u8, new: u8) { + self.del(finder, old); + self.add(new); + } + + /// Add a byte to this hash. + #[inline(always)] + fn add(&mut self, byte: u8) { + self.0 = self.0.wrapping_shl(1).wrapping_add(u32::from(byte)); + } + + /// Remove a byte from this hash. The given needle hash should correspond + /// to the hash computed for the needle being searched for. + #[inline(always)] + fn del(&mut self, finder: &Finder, byte: u8) { + let factor = finder.hash_2pow; + self.0 = self.0.wrapping_sub(u32::from(byte).wrapping_mul(factor)); + } +} + +/// Returns true when `x[i] == y[i]` for all `0 <= i < n`. +/// +/// We forcefully don't inline this to hint at the compiler that it is unlikely +/// to be called. This causes the inner rabinkarp loop above to be a bit +/// tighter and leads to some performance improvement. See the +/// memmem/krate/prebuilt/sliceslice-words/words benchmark. +/// +/// # Safety +/// +/// Same as `crate::arch::all::is_equal_raw`. +#[cold] +#[inline(never)] +unsafe fn is_equal_raw(x: *const u8, y: *const u8, n: usize) -> bool { + crate::arch::all::is_equal_raw(x, y, n) +} + +#[cfg(test)] +mod tests { + use super::*; + + define_substring_forward_quickcheck!(|h, n| Some( + Finder::new(n).find(h, n) + )); + define_substring_reverse_quickcheck!(|h, n| Some( + FinderRev::new(n).rfind(h, n) + )); + + #[test] + fn forward() { + crate::tests::substring::Runner::new() + .fwd(|h, n| Some(Finder::new(n).find(h, n))) + .run(); + } + + #[test] + fn reverse() { + crate::tests::substring::Runner::new() + .rev(|h, n| Some(FinderRev::new(n).rfind(h, n))) + .run(); + } +} diff --git a/third_party/crates/memchr-2.8.3/src/arch/all/shiftor.rs b/third_party/crates/memchr-2.8.3/src/arch/all/shiftor.rs new file mode 100644 index 0000000..b690564 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/all/shiftor.rs @@ -0,0 +1,89 @@ +/*! +An implementation of the [Shift-Or substring search algorithm][shiftor]. + +[shiftor]: https://en.wikipedia.org/wiki/Bitap_algorithm +*/ + +use alloc::boxed::Box; + +/// The type of our mask. +/// +/// While we don't expose anyway to configure this in the public API, if one +/// really needs less memory usage or support for longer needles, then it is +/// suggested to copy the code from this module and modify it to fit your +/// needs. The code below is written to be correct regardless of whether Mask +/// is a u8, u16, u32, u64 or u128. +type Mask = u16; + +/// A forward substring searcher using the Shift-Or algorithm. +#[derive(Debug)] +pub struct Finder { + masks: Box<[Mask; 256]>, + needle_len: usize, +} + +impl Finder { + const MAX_NEEDLE_LEN: usize = (Mask::BITS - 1) as usize; + + /// Create a new Shift-Or forward searcher for the given `needle`. + /// + /// The needle may be empty. The empty needle matches at every byte offset. + #[inline] + pub fn new(needle: &[u8]) -> Option { + let needle_len = needle.len(); + if needle_len > Finder::MAX_NEEDLE_LEN { + // A match is found when bit 7 is set in 'result' in the search + // routine below. So our needle can't be bigger than 7. We could + // permit bigger needles by using u16, u32 or u64 for our mask + // entries. But this is all we need for this example. + return None; + } + let mut searcher = Finder { masks: Box::from([!0; 256]), needle_len }; + for (i, &byte) in needle.iter().enumerate() { + searcher.masks[usize::from(byte)] &= !(1 << i); + } + Some(searcher) + } + + /// Return the first occurrence of the needle given to `Finder::new` in + /// the `haystack` given. If no such occurrence exists, then `None` is + /// returned. + /// + /// Unlike most other substring search implementations in this crate, this + /// finder does not require passing the needle at search time. A match can + /// be determined without the needle at all since the required information + /// is already encoded into this finder at construction time. + /// + /// The maximum value this can return is `haystack.len()`, which can only + /// occur when the needle and haystack both have length zero. Otherwise, + /// for non-empty haystacks, the maximum value is `haystack.len() - 1`. + #[inline] + pub fn find(&self, haystack: &[u8]) -> Option { + if self.needle_len == 0 { + return Some(0); + } + let mut result = !1; + for (i, &byte) in haystack.iter().enumerate() { + result |= self.masks[usize::from(byte)]; + result <<= 1; + if result & (1 << self.needle_len) == 0 { + return Some(i + 1 - self.needle_len); + } + } + None + } +} + +#[cfg(test)] +mod tests { + use super::*; + + define_substring_forward_quickcheck!(|h, n| Some(Finder::new(n)?.find(h))); + + #[test] + fn forward() { + crate::tests::substring::Runner::new() + .fwd(|h, n| Some(Finder::new(n)?.find(h))) + .run(); + } +} diff --git a/third_party/crates/memchr-2.8.3/src/arch/all/twoway.rs b/third_party/crates/memchr-2.8.3/src/arch/all/twoway.rs new file mode 100644 index 0000000..d166c8c --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/all/twoway.rs @@ -0,0 +1,877 @@ +/*! +An implementation of the [Two-Way substring search algorithm][two-way]. + +[`Finder`] can be built for forward searches, while [`FinderRev`] can be built +for reverse searches. + +Two-Way makes for a nice general purpose substring search algorithm because of +its time and space complexity properties. It also performs well in practice. +Namely, with `m = len(needle)` and `n = len(haystack)`, Two-Way takes `O(m)` +time to create a finder, `O(1)` space and `O(n)` search time. In other words, +the preprocessing step is quick, doesn't require any heap memory and the worst +case search time is guaranteed to be linear in the haystack regardless of the +size of the needle. + +While vector algorithms will usually beat Two-Way handedly, vector algorithms +also usually have pathological or edge cases that are better handled by Two-Way. +Moreover, not all targets support vector algorithms or implementations for them +simply may not exist yet. + +Two-Way can be found in the `memmem` implementations in at least [GNU libc] and +[musl]. + +[two-way]: https://en.wikipedia.org/wiki/Two-way_string-matching_algorithm +[GNU libc]: https://www.gnu.org/software/libc/ +[musl]: https://www.musl-libc.org/ +*/ + +use core::cmp; + +use crate::{ + arch::all::{is_prefix, is_suffix}, + memmem::Pre, +}; + +/// A forward substring searcher that uses the Two-Way algorithm. +#[derive(Clone, Copy, Debug)] +pub struct Finder(TwoWay); + +/// A reverse substring searcher that uses the Two-Way algorithm. +#[derive(Clone, Copy, Debug)] +pub struct FinderRev(TwoWay); + +/// An implementation of the TwoWay substring search algorithm. +/// +/// This searcher supports forward and reverse search, although not +/// simultaneously. It runs in `O(n + m)` time and `O(1)` space, where +/// `n ~ len(needle)` and `m ~ len(haystack)`. +/// +/// The implementation here roughly matches that which was developed by +/// Crochemore and Perrin in their 1991 paper "Two-way string-matching." The +/// changes in this implementation are 1) the use of zero-based indices, 2) a +/// heuristic skip table based on the last byte (borrowed from Rust's standard +/// library) and 3) the addition of heuristics for a fast skip loop. For (3), +/// callers can pass any kind of prefilter they want, but usually it's one +/// based on a heuristic that uses an approximate background frequency of bytes +/// to choose rare bytes to quickly look for candidate match positions. Note +/// though that currently, this prefilter functionality is not exposed directly +/// in the public API. (File an issue if you want it and provide a use case +/// please.) +/// +/// The heuristic for fast skipping is automatically shut off if it's +/// detected to be ineffective at search time. Generally, this only occurs in +/// pathological cases. But this is generally necessary in order to preserve +/// a `O(n + m)` time bound. +/// +/// The code below is fairly complex and not obviously correct at all. It's +/// likely necessary to read the Two-Way paper cited above in order to fully +/// grok this code. The essence of it is: +/// +/// 1. Do something to detect a "critical" position in the needle. +/// 2. For the current position in the haystack, look if `needle[critical..]` +/// matches at that position. +/// 3. If so, look if `needle[..critical]` matches. +/// 4. If a mismatch occurs, shift the search by some amount based on the +/// critical position and a pre-computed shift. +/// +/// This type is wrapped in the forward and reverse finders that expose +/// consistent forward or reverse APIs. +#[derive(Clone, Copy, Debug)] +struct TwoWay { + /// A small bitset used as a quick prefilter (in addition to any prefilter + /// given by the caller). Namely, a bit `i` is set if and only if `b%64==i` + /// for any `b == needle[i]`. + /// + /// When used as a prefilter, if the last byte at the current candidate + /// position is NOT in this set, then we can skip that entire candidate + /// position (the length of the needle). This is essentially the shift + /// trick found in Boyer-Moore, but only applied to bytes that don't appear + /// in the needle. + /// + /// N.B. This trick was inspired by something similar in std's + /// implementation of Two-Way. + byteset: ApproximateByteSet, + /// A critical position in needle. Specifically, this position corresponds + /// to beginning of either the minimal or maximal suffix in needle. (N.B. + /// See SuffixType below for why "minimal" isn't quite the correct word + /// here.) + /// + /// This is the position at which every search begins. Namely, search + /// starts by scanning text to the right of this position, and only if + /// there's a match does the text to the left of this position get scanned. + critical_pos: usize, + /// The amount we shift by in the Two-Way search algorithm. This + /// corresponds to the "small period" and "large period" cases. + shift: Shift, +} + +impl Finder { + /// Create a searcher that finds occurrences of the given `needle`. + /// + /// An empty `needle` results in a match at every position in a haystack, + /// including at `haystack.len()`. + #[inline] + pub fn new(needle: &[u8]) -> Finder { + let byteset = ApproximateByteSet::new(needle); + let min_suffix = Suffix::forward(needle, SuffixKind::Minimal); + let max_suffix = Suffix::forward(needle, SuffixKind::Maximal); + let (period_lower_bound, critical_pos) = + if min_suffix.pos > max_suffix.pos { + (min_suffix.period, min_suffix.pos) + } else { + (max_suffix.period, max_suffix.pos) + }; + let shift = Shift::forward(needle, period_lower_bound, critical_pos); + Finder(TwoWay { byteset, critical_pos, shift }) + } + + /// Returns the first occurrence of `needle` in the given `haystack`, or + /// `None` if no such occurrence could be found. + /// + /// The `needle` given must be the same as the `needle` provided to + /// [`Finder::new`]. + /// + /// An empty `needle` results in a match at every position in a haystack, + /// including at `haystack.len()`. + #[inline] + pub fn find(&self, haystack: &[u8], needle: &[u8]) -> Option { + self.find_with_prefilter(None, haystack, needle) + } + + /// This is like [`Finder::find`], but it accepts a prefilter for + /// accelerating searches. + /// + /// Currently this is not exposed in the public API because, at the time + /// of writing, I didn't want to spend time thinking about how to expose + /// the prefilter infrastructure (if at all). If you have a compelling use + /// case for exposing this routine, please create an issue. Do *not* open + /// a PR that just exposes `Pre` and friends. Exporting this routine will + /// require API design. + #[inline(always)] + pub(crate) fn find_with_prefilter( + &self, + pre: Option>, + haystack: &[u8], + needle: &[u8], + ) -> Option { + match self.0.shift { + Shift::Small { period } => { + self.find_small_imp(pre, haystack, needle, period) + } + Shift::Large { shift } => { + self.find_large_imp(pre, haystack, needle, shift) + } + } + } + + // Each of the two search implementations below can be accelerated by a + // prefilter, but it is not always enabled. To avoid its overhead when + // its disabled, we explicitly inline each search implementation based on + // whether a prefilter will be used or not. The decision on which to use + // is made in the parent meta searcher. + + #[inline(always)] + fn find_small_imp( + &self, + mut pre: Option>, + haystack: &[u8], + needle: &[u8], + period: usize, + ) -> Option { + let mut pos = 0; + let mut shift = 0; + let last_byte_pos = match needle.len().checked_sub(1) { + None => return Some(pos), + Some(last_byte) => last_byte, + }; + while pos + needle.len() <= haystack.len() { + let mut i = cmp::max(self.0.critical_pos, shift); + if let Some(pre) = pre.as_mut() { + if pre.is_effective() { + pos += pre.find(&haystack[pos..])?; + shift = 0; + i = self.0.critical_pos; + if pos + needle.len() > haystack.len() { + return None; + } + } + } + if !self.0.byteset.contains(haystack[pos + last_byte_pos]) { + pos += needle.len(); + shift = 0; + continue; + } + while i < needle.len() && needle[i] == haystack[pos + i] { + i += 1; + } + if i < needle.len() { + pos += i - self.0.critical_pos + 1; + shift = 0; + } else { + let mut j = self.0.critical_pos; + while j > shift && needle[j] == haystack[pos + j] { + j -= 1; + } + if j <= shift && needle[shift] == haystack[pos + shift] { + return Some(pos); + } + pos += period; + shift = needle.len() - period; + } + } + None + } + + #[inline(always)] + fn find_large_imp( + &self, + mut pre: Option>, + haystack: &[u8], + needle: &[u8], + shift: usize, + ) -> Option { + let mut pos = 0; + let last_byte_pos = match needle.len().checked_sub(1) { + None => return Some(pos), + Some(last_byte) => last_byte, + }; + 'outer: while pos + needle.len() <= haystack.len() { + if let Some(pre) = pre.as_mut() { + if pre.is_effective() { + pos += pre.find(&haystack[pos..])?; + if pos + needle.len() > haystack.len() { + return None; + } + } + } + + if !self.0.byteset.contains(haystack[pos + last_byte_pos]) { + pos += needle.len(); + continue; + } + let mut i = self.0.critical_pos; + while i < needle.len() && needle[i] == haystack[pos + i] { + i += 1; + } + if i < needle.len() { + pos += i - self.0.critical_pos + 1; + } else { + for j in (0..self.0.critical_pos).rev() { + if needle[j] != haystack[pos + j] { + pos += shift; + continue 'outer; + } + } + return Some(pos); + } + } + None + } +} + +impl FinderRev { + /// Create a searcher that finds occurrences of the given `needle`. + /// + /// An empty `needle` results in a match at every position in a haystack, + /// including at `haystack.len()`. + #[inline] + pub fn new(needle: &[u8]) -> FinderRev { + let byteset = ApproximateByteSet::new(needle); + let min_suffix = Suffix::reverse(needle, SuffixKind::Minimal); + let max_suffix = Suffix::reverse(needle, SuffixKind::Maximal); + let (period_lower_bound, critical_pos) = + if min_suffix.pos < max_suffix.pos { + (min_suffix.period, min_suffix.pos) + } else { + (max_suffix.period, max_suffix.pos) + }; + let shift = Shift::reverse(needle, period_lower_bound, critical_pos); + FinderRev(TwoWay { byteset, critical_pos, shift }) + } + + /// Returns the last occurrence of `needle` in the given `haystack`, or + /// `None` if no such occurrence could be found. + /// + /// The `needle` given must be the same as the `needle` provided to + /// [`FinderRev::new`]. + /// + /// An empty `needle` results in a match at every position in a haystack, + /// including at `haystack.len()`. + #[inline] + pub fn rfind(&self, haystack: &[u8], needle: &[u8]) -> Option { + // For the reverse case, we don't use a prefilter. It's plausible that + // perhaps we should, but it's a lot of additional code to do it, and + // it's not clear that it's actually worth it. If you have a really + // compelling use case for this, please file an issue. + match self.0.shift { + Shift::Small { period } => { + self.rfind_small_imp(haystack, needle, period) + } + Shift::Large { shift } => { + self.rfind_large_imp(haystack, needle, shift) + } + } + } + + #[inline(always)] + fn rfind_small_imp( + &self, + haystack: &[u8], + needle: &[u8], + period: usize, + ) -> Option { + let nlen = needle.len(); + let mut pos = haystack.len(); + let mut shift = nlen; + let first_byte = match needle.first() { + None => return Some(pos), + Some(&first_byte) => first_byte, + }; + while pos >= nlen { + if !self.0.byteset.contains(haystack[pos - nlen]) { + pos -= nlen; + shift = nlen; + continue; + } + let mut i = cmp::min(self.0.critical_pos, shift); + while i > 0 && needle[i - 1] == haystack[pos - nlen + i - 1] { + i -= 1; + } + if i > 0 || first_byte != haystack[pos - nlen] { + pos -= self.0.critical_pos - i + 1; + shift = nlen; + } else { + let mut j = self.0.critical_pos; + while j < shift && needle[j] == haystack[pos - nlen + j] { + j += 1; + } + if j >= shift { + return Some(pos - nlen); + } + pos -= period; + shift = period; + } + } + None + } + + #[inline(always)] + fn rfind_large_imp( + &self, + haystack: &[u8], + needle: &[u8], + shift: usize, + ) -> Option { + let nlen = needle.len(); + let mut pos = haystack.len(); + let first_byte = match needle.first() { + None => return Some(pos), + Some(&first_byte) => first_byte, + }; + while pos >= nlen { + if !self.0.byteset.contains(haystack[pos - nlen]) { + pos -= nlen; + continue; + } + let mut i = self.0.critical_pos; + while i > 0 && needle[i - 1] == haystack[pos - nlen + i - 1] { + i -= 1; + } + if i > 0 || first_byte != haystack[pos - nlen] { + pos -= self.0.critical_pos - i + 1; + } else { + let mut j = self.0.critical_pos; + while j < nlen && needle[j] == haystack[pos - nlen + j] { + j += 1; + } + if j == nlen { + return Some(pos - nlen); + } + pos -= shift; + } + } + None + } +} + +/// A representation of the amount we're allowed to shift by during Two-Way +/// search. +/// +/// When computing a critical factorization of the needle, we find the position +/// of the critical factorization by finding the needle's maximal (or minimal) +/// suffix, along with the period of that suffix. It turns out that the period +/// of that suffix is a lower bound on the period of the needle itself. +/// +/// This lower bound is equivalent to the actual period of the needle in +/// some cases. To describe that case, we denote the needle as `x` where +/// `x = uv` and `v` is the lexicographic maximal suffix of `v`. The lower +/// bound given here is always the period of `v`, which is `<= period(x)`. The +/// case where `period(v) == period(x)` occurs when `len(u) < (len(x) / 2)` and +/// where `u` is a suffix of `v[0..period(v)]`. +/// +/// This case is important because the search algorithm for when the +/// periods are equivalent is slightly different than the search algorithm +/// for when the periods are not equivalent. In particular, when they aren't +/// equivalent, we know that the period of the needle is no less than half its +/// length. In this case, we shift by an amount less than or equal to the +/// period of the needle (determined by the maximum length of the components +/// of the critical factorization of `x`, i.e., `max(len(u), len(v))`).. +/// +/// The above two cases are represented by the variants below. Each entails +/// a different instantiation of the Two-Way search algorithm. +/// +/// N.B. If we could find a way to compute the exact period in all cases, +/// then we could collapse this case analysis and simplify the algorithm. The +/// Two-Way paper suggests this is possible, but more reading is required to +/// grok why the authors didn't pursue that path. +#[derive(Clone, Copy, Debug)] +enum Shift { + Small { period: usize }, + Large { shift: usize }, +} + +impl Shift { + /// Compute the shift for a given needle in the forward direction. + /// + /// This requires a lower bound on the period and a critical position. + /// These can be computed by extracting both the minimal and maximal + /// lexicographic suffixes, and choosing the right-most starting position. + /// The lower bound on the period is then the period of the chosen suffix. + fn forward( + needle: &[u8], + period_lower_bound: usize, + critical_pos: usize, + ) -> Shift { + let large = cmp::max(critical_pos, needle.len() - critical_pos); + if critical_pos * 2 >= needle.len() { + return Shift::Large { shift: large }; + } + + let (u, v) = needle.split_at(critical_pos); + if !is_suffix(&v[..period_lower_bound], u) { + return Shift::Large { shift: large }; + } + Shift::Small { period: period_lower_bound } + } + + /// Compute the shift for a given needle in the reverse direction. + /// + /// This requires a lower bound on the period and a critical position. + /// These can be computed by extracting both the minimal and maximal + /// lexicographic suffixes, and choosing the left-most starting position. + /// The lower bound on the period is then the period of the chosen suffix. + fn reverse( + needle: &[u8], + period_lower_bound: usize, + critical_pos: usize, + ) -> Shift { + let large = cmp::max(critical_pos, needle.len() - critical_pos); + if (needle.len() - critical_pos) * 2 >= needle.len() { + return Shift::Large { shift: large }; + } + + let (v, u) = needle.split_at(critical_pos); + if !is_prefix(&v[v.len() - period_lower_bound..], u) { + return Shift::Large { shift: large }; + } + Shift::Small { period: period_lower_bound } + } +} + +/// A suffix extracted from a needle along with its period. +#[derive(Debug)] +struct Suffix { + /// The starting position of this suffix. + /// + /// If this is a forward suffix, then `&bytes[pos..]` can be used. If this + /// is a reverse suffix, then `&bytes[..pos]` can be used. That is, for + /// forward suffixes, this is an inclusive starting position, where as for + /// reverse suffixes, this is an exclusive ending position. + pos: usize, + /// The period of this suffix. + /// + /// Note that this is NOT necessarily the period of the string from which + /// this suffix comes from. (It is always less than or equal to the period + /// of the original string.) + period: usize, +} + +impl Suffix { + fn forward(needle: &[u8], kind: SuffixKind) -> Suffix { + // suffix represents our maximal (or minimal) suffix, along with + // its period. + let mut suffix = Suffix { pos: 0, period: 1 }; + // The start of a suffix in `needle` that we are considering as a + // more maximal (or minimal) suffix than what's in `suffix`. + let mut candidate_start = 1; + // The current offset of our suffixes that we're comparing. + // + // When the characters at this offset are the same, then we mush on + // to the next position since no decision is possible. When the + // candidate's character is greater (or lesser) than the corresponding + // character than our current maximal (or minimal) suffix, then the + // current suffix is changed over to the candidate and we restart our + // search. Otherwise, the candidate suffix is no good and we restart + // our search on the next candidate. + // + // The three cases above correspond to the three cases in the loop + // below. + let mut offset = 0; + + while candidate_start + offset < needle.len() { + let current = needle[suffix.pos + offset]; + let candidate = needle[candidate_start + offset]; + match kind.cmp(current, candidate) { + SuffixOrdering::Accept => { + suffix = Suffix { pos: candidate_start, period: 1 }; + candidate_start += 1; + offset = 0; + } + SuffixOrdering::Skip => { + candidate_start += offset + 1; + offset = 0; + suffix.period = candidate_start - suffix.pos; + } + SuffixOrdering::Push => { + if offset + 1 == suffix.period { + candidate_start += suffix.period; + offset = 0; + } else { + offset += 1; + } + } + } + } + suffix + } + + fn reverse(needle: &[u8], kind: SuffixKind) -> Suffix { + // See the comments in `forward` for how this works. + let mut suffix = Suffix { pos: needle.len(), period: 1 }; + if needle.len() == 1 { + return suffix; + } + let mut candidate_start = match needle.len().checked_sub(1) { + None => return suffix, + Some(candidate_start) => candidate_start, + }; + let mut offset = 0; + + while offset < candidate_start { + let current = needle[suffix.pos - offset - 1]; + let candidate = needle[candidate_start - offset - 1]; + match kind.cmp(current, candidate) { + SuffixOrdering::Accept => { + suffix = Suffix { pos: candidate_start, period: 1 }; + candidate_start -= 1; + offset = 0; + } + SuffixOrdering::Skip => { + candidate_start -= offset + 1; + offset = 0; + suffix.period = suffix.pos - candidate_start; + } + SuffixOrdering::Push => { + if offset + 1 == suffix.period { + candidate_start -= suffix.period; + offset = 0; + } else { + offset += 1; + } + } + } + } + suffix + } +} + +/// The kind of suffix to extract. +#[derive(Clone, Copy, Debug)] +enum SuffixKind { + /// Extract the smallest lexicographic suffix from a string. + /// + /// Technically, this doesn't actually pick the smallest lexicographic + /// suffix. e.g., Given the choice between `a` and `aa`, this will choose + /// the latter over the former, even though `a < aa`. The reasoning for + /// this isn't clear from the paper, but it still smells like a minimal + /// suffix. + Minimal, + /// Extract the largest lexicographic suffix from a string. + /// + /// Unlike `Minimal`, this really does pick the maximum suffix. e.g., Given + /// the choice between `z` and `zz`, this will choose the latter over the + /// former. + Maximal, +} + +/// The result of comparing corresponding bytes between two suffixes. +#[derive(Clone, Copy, Debug)] +enum SuffixOrdering { + /// This occurs when the given candidate byte indicates that the candidate + /// suffix is better than the current maximal (or minimal) suffix. That is, + /// the current candidate suffix should supplant the current maximal (or + /// minimal) suffix. + Accept, + /// This occurs when the given candidate byte excludes the candidate suffix + /// from being better than the current maximal (or minimal) suffix. That + /// is, the current candidate suffix should be dropped and the next one + /// should be considered. + Skip, + /// This occurs when no decision to accept or skip the candidate suffix + /// can be made, e.g., when corresponding bytes are equivalent. In this + /// case, the next corresponding bytes should be compared. + Push, +} + +impl SuffixKind { + /// Returns true if and only if the given candidate byte indicates that + /// it should replace the current suffix as the maximal (or minimal) + /// suffix. + fn cmp(self, current: u8, candidate: u8) -> SuffixOrdering { + use self::SuffixOrdering::*; + + match self { + SuffixKind::Minimal if candidate < current => Accept, + SuffixKind::Minimal if candidate > current => Skip, + SuffixKind::Minimal => Push, + SuffixKind::Maximal if candidate > current => Accept, + SuffixKind::Maximal if candidate < current => Skip, + SuffixKind::Maximal => Push, + } + } +} + +/// A bitset used to track whether a particular byte exists in a needle or not. +/// +/// Namely, bit 'i' is set if and only if byte%64==i for any byte in the +/// needle. If a particular byte in the haystack is NOT in this set, then one +/// can conclude that it is also not in the needle, and thus, one can advance +/// in the haystack by needle.len() bytes. +#[derive(Clone, Copy, Debug)] +struct ApproximateByteSet(u64); + +impl ApproximateByteSet { + /// Create a new set from the given needle. + fn new(needle: &[u8]) -> ApproximateByteSet { + let mut bits = 0; + for &b in needle { + bits |= 1 << (b % 64); + } + ApproximateByteSet(bits) + } + + /// Return true if and only if the given byte might be in this set. This + /// may return a false positive, but will never return a false negative. + #[inline(always)] + fn contains(&self, byte: u8) -> bool { + self.0 & (1 << (byte % 64)) != 0 + } +} + +#[cfg(test)] +mod tests { + use alloc::vec::Vec; + + use super::*; + + /// Convenience wrapper for computing the suffix as a byte string. + fn get_suffix_forward(needle: &[u8], kind: SuffixKind) -> (&[u8], usize) { + let s = Suffix::forward(needle, kind); + (&needle[s.pos..], s.period) + } + + /// Convenience wrapper for computing the reverse suffix as a byte string. + fn get_suffix_reverse(needle: &[u8], kind: SuffixKind) -> (&[u8], usize) { + let s = Suffix::reverse(needle, kind); + (&needle[..s.pos], s.period) + } + + /// Return all of the non-empty suffixes in the given byte string. + fn suffixes(bytes: &[u8]) -> Vec<&[u8]> { + (0..bytes.len()).map(|i| &bytes[i..]).collect() + } + + /// Return the lexicographically maximal suffix of the given byte string. + fn naive_maximal_suffix_forward(needle: &[u8]) -> &[u8] { + let mut sufs = suffixes(needle); + sufs.sort(); + sufs.pop().unwrap() + } + + /// Return the lexicographically maximal suffix of the reverse of the given + /// byte string. + fn naive_maximal_suffix_reverse(needle: &[u8]) -> Vec { + let mut reversed = needle.to_vec(); + reversed.reverse(); + let mut got = naive_maximal_suffix_forward(&reversed).to_vec(); + got.reverse(); + got + } + + define_substring_forward_quickcheck!(|h, n| Some( + Finder::new(n).find(h, n) + )); + define_substring_reverse_quickcheck!(|h, n| Some( + FinderRev::new(n).rfind(h, n) + )); + + #[test] + fn forward() { + crate::tests::substring::Runner::new() + .fwd(|h, n| Some(Finder::new(n).find(h, n))) + .run(); + } + + #[test] + fn reverse() { + crate::tests::substring::Runner::new() + .rev(|h, n| Some(FinderRev::new(n).rfind(h, n))) + .run(); + } + + #[test] + fn suffix_forward() { + macro_rules! assert_suffix_min { + ($given:expr, $expected:expr, $period:expr) => { + let (got_suffix, got_period) = + get_suffix_forward($given.as_bytes(), SuffixKind::Minimal); + let got_suffix = core::str::from_utf8(got_suffix).unwrap(); + assert_eq!(($expected, $period), (got_suffix, got_period)); + }; + } + + macro_rules! assert_suffix_max { + ($given:expr, $expected:expr, $period:expr) => { + let (got_suffix, got_period) = + get_suffix_forward($given.as_bytes(), SuffixKind::Maximal); + let got_suffix = core::str::from_utf8(got_suffix).unwrap(); + assert_eq!(($expected, $period), (got_suffix, got_period)); + }; + } + + assert_suffix_min!("a", "a", 1); + assert_suffix_max!("a", "a", 1); + + assert_suffix_min!("ab", "ab", 2); + assert_suffix_max!("ab", "b", 1); + + assert_suffix_min!("ba", "a", 1); + assert_suffix_max!("ba", "ba", 2); + + assert_suffix_min!("abc", "abc", 3); + assert_suffix_max!("abc", "c", 1); + + assert_suffix_min!("acb", "acb", 3); + assert_suffix_max!("acb", "cb", 2); + + assert_suffix_min!("cba", "a", 1); + assert_suffix_max!("cba", "cba", 3); + + assert_suffix_min!("abcabc", "abcabc", 3); + assert_suffix_max!("abcabc", "cabc", 3); + + assert_suffix_min!("abcabcabc", "abcabcabc", 3); + assert_suffix_max!("abcabcabc", "cabcabc", 3); + + assert_suffix_min!("abczz", "abczz", 5); + assert_suffix_max!("abczz", "zz", 1); + + assert_suffix_min!("zzabc", "abc", 3); + assert_suffix_max!("zzabc", "zzabc", 5); + + assert_suffix_min!("aaa", "aaa", 1); + assert_suffix_max!("aaa", "aaa", 1); + + assert_suffix_min!("foobar", "ar", 2); + assert_suffix_max!("foobar", "r", 1); + } + + #[test] + fn suffix_reverse() { + macro_rules! assert_suffix_min { + ($given:expr, $expected:expr, $period:expr) => { + let (got_suffix, got_period) = + get_suffix_reverse($given.as_bytes(), SuffixKind::Minimal); + let got_suffix = core::str::from_utf8(got_suffix).unwrap(); + assert_eq!(($expected, $period), (got_suffix, got_period)); + }; + } + + macro_rules! assert_suffix_max { + ($given:expr, $expected:expr, $period:expr) => { + let (got_suffix, got_period) = + get_suffix_reverse($given.as_bytes(), SuffixKind::Maximal); + let got_suffix = core::str::from_utf8(got_suffix).unwrap(); + assert_eq!(($expected, $period), (got_suffix, got_period)); + }; + } + + assert_suffix_min!("a", "a", 1); + assert_suffix_max!("a", "a", 1); + + assert_suffix_min!("ab", "a", 1); + assert_suffix_max!("ab", "ab", 2); + + assert_suffix_min!("ba", "ba", 2); + assert_suffix_max!("ba", "b", 1); + + assert_suffix_min!("abc", "a", 1); + assert_suffix_max!("abc", "abc", 3); + + assert_suffix_min!("acb", "a", 1); + assert_suffix_max!("acb", "ac", 2); + + assert_suffix_min!("cba", "cba", 3); + assert_suffix_max!("cba", "c", 1); + + assert_suffix_min!("abcabc", "abca", 3); + assert_suffix_max!("abcabc", "abcabc", 3); + + assert_suffix_min!("abcabcabc", "abcabca", 3); + assert_suffix_max!("abcabcabc", "abcabcabc", 3); + + assert_suffix_min!("abczz", "a", 1); + assert_suffix_max!("abczz", "abczz", 5); + + assert_suffix_min!("zzabc", "zza", 3); + assert_suffix_max!("zzabc", "zz", 1); + + assert_suffix_min!("aaa", "aaa", 1); + assert_suffix_max!("aaa", "aaa", 1); + } + + #[cfg(not(miri))] + quickcheck::quickcheck! { + fn qc_suffix_forward_maximal(bytes: Vec) -> bool { + if bytes.is_empty() { + return true; + } + + let (got, _) = get_suffix_forward(&bytes, SuffixKind::Maximal); + let expected = naive_maximal_suffix_forward(&bytes); + got == expected + } + + fn qc_suffix_reverse_maximal(bytes: Vec) -> bool { + if bytes.is_empty() { + return true; + } + + let (got, _) = get_suffix_reverse(&bytes, SuffixKind::Maximal); + let expected = naive_maximal_suffix_reverse(&bytes); + expected == got + } + } + + // This is a regression test caught by quickcheck that exercised a bug in + // the reverse small period handling. The bug was that we were using 'if j + // == shift' to determine if a match occurred, but the correct guard is 'if + // j >= shift', which matches the corresponding guard in the forward impl. + #[test] + fn regression_rev_small_period() { + let rfind = |h, n| FinderRev::new(n).rfind(h, n); + let haystack = "ababaz"; + let needle = "abab"; + assert_eq!(Some(0), rfind(haystack.as_bytes(), needle.as_bytes())); + } +} diff --git a/third_party/crates/memchr-2.8.3/src/arch/generic/memchr.rs b/third_party/crates/memchr-2.8.3/src/arch/generic/memchr.rs new file mode 100644 index 0000000..d5501d4 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/generic/memchr.rs @@ -0,0 +1,1220 @@ +/*! +Generic crate-internal routines for the `memchr` family of functions. +*/ + +// What follows is a vector algorithm generic over the specific vector +// type to detect the position of one, two or three needles in a haystack. +// From what I know, this is a "classic" algorithm, although I don't +// believe it has been published in any peer reviewed journal. I believe +// it can be found in places like glibc and Go's standard library. It +// appears to be well known and is elaborated on in more detail here: +// https://gms.tf/stdfind-and-memchr-optimizations.html +// +// While the routine below is fairly long and perhaps intimidating, the basic +// idea is actually very simple and can be expressed straight-forwardly in +// pseudo code. The pseudo code below is written for 128 bit vectors, but the +// actual code below works for anything that implements the Vector trait. +// +// needle = (n1 << 15) | (n1 << 14) | ... | (n1 << 1) | n1 +// // Note: shift amount is in bytes +// +// while i <= haystack.len() - 16: +// // A 16 byte vector. Each byte in chunk corresponds to a byte in +// // the haystack. +// chunk = haystack[i:i+16] +// // Compare bytes in needle with bytes in chunk. The result is a 16 +// // byte chunk where each byte is 0xFF if the corresponding bytes +// // in needle and chunk were equal, or 0x00 otherwise. +// eqs = cmpeq(needle, chunk) +// // Return a 32 bit integer where the most significant 16 bits +// // are always 0 and the lower 16 bits correspond to whether the +// // most significant bit in the correspond byte in `eqs` is set. +// // In other words, `mask as u16` has bit i set if and only if +// // needle[i] == chunk[i]. +// mask = movemask(eqs) +// +// // Mask is 0 if there is no match, and non-zero otherwise. +// if mask != 0: +// // trailing_zeros tells us the position of the least significant +// // bit that is set. +// return i + trailing_zeros(mask) +// +// // haystack length may not be a multiple of 16, so search the rest. +// while i < haystack.len(): +// if haystack[i] == n1: +// return i +// +// // No match found. +// return NULL +// +// In fact, we could loosely translate the above code to Rust line-for-line +// and it would be a pretty fast algorithm. But, we pull out all the stops +// to go as fast as possible: +// +// 1. We use aligned loads. That is, we do some finagling to make sure our +// primary loop not only proceeds in increments of 16 bytes, but that +// the address of haystack's pointer that we dereference is aligned to +// 16 bytes. 16 is a magic number here because it is the size of SSE2 +// 128-bit vector. (For the AVX2 algorithm, 32 is the magic number.) +// Therefore, to get aligned loads, our pointer's address must be evenly +// divisible by 16. +// 2. Our primary loop proceeds 64 bytes at a time instead of 16. It's +// kind of like loop unrolling, but we combine the equality comparisons +// using a vector OR such that we only need to extract a single mask to +// determine whether a match exists or not. If so, then we do some +// book-keeping to determine the precise location but otherwise mush on. +// 3. We use our "chunk" comparison routine in as many places as possible, +// even if it means using unaligned loads. In particular, if haystack +// starts with an unaligned address, then we do an unaligned load to +// search the first 16 bytes. We then start our primary loop at the +// smallest subsequent aligned address, which will actually overlap with +// previously searched bytes. But we're OK with that. We do a similar +// dance at the end of our primary loop. Finally, to avoid a +// byte-at-a-time loop at the end, we do a final 16 byte unaligned load +// that may overlap with a previous load. This is OK because it converts +// a loop into a small number of very fast vector instructions. The overlap +// is OK because we know the place where the overlap occurs does not +// contain a match. +// +// And that's pretty all there is to it. Note that since the below is +// generic and since it's meant to be inlined into routines with a +// `#[target_feature(enable = "...")]` annotation, we must mark all routines as +// both unsafe and `#[inline(always)]`. +// +// The fact that the code below is generic does somewhat inhibit us. For +// example, I've noticed that introducing an unlineable `#[cold]` function to +// handle the match case in the loop generates tighter assembly, but there is +// no way to do this in the generic code below because the generic code doesn't +// know what `target_feature` annotation to apply to the unlineable function. +// We could make such functions part of the `Vector` trait, but we instead live +// with the slightly sub-optimal codegen for now since it doesn't seem to have +// a noticeable perf difference. + +use crate::{ + ext::Pointer, + vector::{MoveMask, Vector}, +}; + +/// Finds all occurrences of a single byte in a haystack. +#[derive(Clone, Copy, Debug)] +pub(crate) struct One { + s1: u8, + v1: V, +} + +impl One { + /// The number of bytes we examine per each iteration of our search loop. + const LOOP_SIZE: usize = 4 * V::BYTES; + + /// Create a new searcher that finds occurrences of the byte given. + #[inline(always)] + pub(crate) unsafe fn new(needle: u8) -> One { + One { s1: needle, v1: V::splat(needle) } + } + + /// Returns the needle given to `One::new`. + #[inline(always)] + pub(crate) fn needle1(&self) -> u8 { + self.s1 + } + + /// Return a pointer to the first occurrence of the needle in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// # Safety + /// + /// * It must be the case that `start < end` and that the distance between + /// them is at least equal to `V::BYTES`. That is, it must always be valid + /// to do at least an unaligned load of `V` at `start`. + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + #[inline(always)] + pub(crate) unsafe fn find_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + // If we want to support vectors bigger than 256 bits, we probably + // need to move up to using a u64 for the masks used below. Currently + // they are 32 bits, which means we're SOL for vectors that need masks + // bigger than 32 bits. Overall unclear until there's a use case. + debug_assert!(V::BYTES <= 32, "vector cannot be bigger than 32 bytes"); + + let topos = V::Mask::first_offset; + let len = end.distance(start); + debug_assert!( + len >= V::BYTES, + "haystack has length {}, but must be at least {}", + len, + V::BYTES + ); + + // Search a possibly unaligned chunk at `start`. This covers any part + // of the haystack prior to where aligned loads can start. + if let Some(cur) = self.search_chunk(start, topos) { + return Some(cur); + } + // Set `cur` to the first V-aligned pointer greater than `start`. + let mut cur = start.add(V::BYTES - (start.as_usize() & V::ALIGN)); + debug_assert!(cur > start && end.sub(V::BYTES) >= start); + if len >= Self::LOOP_SIZE { + while cur <= end.sub(Self::LOOP_SIZE) { + debug_assert_eq!(0, cur.as_usize() % V::BYTES); + + let a = V::load_aligned(cur); + let b = V::load_aligned(cur.add(1 * V::BYTES)); + let c = V::load_aligned(cur.add(2 * V::BYTES)); + let d = V::load_aligned(cur.add(3 * V::BYTES)); + let eqa = self.v1.cmpeq(a); + let eqb = self.v1.cmpeq(b); + let eqc = self.v1.cmpeq(c); + let eqd = self.v1.cmpeq(d); + let or1 = eqa.or(eqb); + let or2 = eqc.or(eqd); + let or3 = or1.or(or2); + if or3.movemask_will_have_non_zero() { + let mask = eqa.movemask(); + if mask.has_non_zero() { + return Some(cur.add(topos(mask))); + } + + let mask = eqb.movemask(); + if mask.has_non_zero() { + return Some(cur.add(1 * V::BYTES).add(topos(mask))); + } + + let mask = eqc.movemask(); + if mask.has_non_zero() { + return Some(cur.add(2 * V::BYTES).add(topos(mask))); + } + + let mask = eqd.movemask(); + debug_assert!(mask.has_non_zero()); + return Some(cur.add(3 * V::BYTES).add(topos(mask))); + } + cur = cur.add(Self::LOOP_SIZE); + } + } + // Handle any leftovers after the aligned loop above. We use unaligned + // loads here, but I believe we are guaranteed that they are aligned + // since `cur` is aligned. + while cur <= end.sub(V::BYTES) { + debug_assert!(end.distance(cur) >= V::BYTES); + if let Some(cur) = self.search_chunk(cur, topos) { + return Some(cur); + } + cur = cur.add(V::BYTES); + } + // Finally handle any remaining bytes less than the size of V. In this + // case, our pointer may indeed be unaligned and the load may overlap + // with the previous one. But that's okay since we know the previous + // load didn't lead to a match (otherwise we wouldn't be here). + if cur < end { + debug_assert!(end.distance(cur) < V::BYTES); + cur = cur.sub(V::BYTES - end.distance(cur)); + debug_assert_eq!(end.distance(cur), V::BYTES); + return self.search_chunk(cur, topos); + } + None + } + + /// Return a pointer to the last occurrence of the needle in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// # Safety + /// + /// * It must be the case that `start < end` and that the distance between + /// them is at least equal to `V::BYTES`. That is, it must always be valid + /// to do at least an unaligned load of `V` at `start`. + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + #[inline(always)] + pub(crate) unsafe fn rfind_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + // If we want to support vectors bigger than 256 bits, we probably + // need to move up to using a u64 for the masks used below. Currently + // they are 32 bits, which means we're SOL for vectors that need masks + // bigger than 32 bits. Overall unclear until there's a use case. + debug_assert!(V::BYTES <= 32, "vector cannot be bigger than 32 bytes"); + + let topos = V::Mask::last_offset; + let len = end.distance(start); + debug_assert!( + len >= V::BYTES, + "haystack has length {}, but must be at least {}", + len, + V::BYTES + ); + + if let Some(cur) = self.search_chunk(end.sub(V::BYTES), topos) { + return Some(cur); + } + let mut cur = end.sub(end.as_usize() & V::ALIGN); + debug_assert!(start <= cur && cur <= end); + if len >= Self::LOOP_SIZE { + while cur >= start.add(Self::LOOP_SIZE) { + debug_assert_eq!(0, cur.as_usize() % V::BYTES); + + cur = cur.sub(Self::LOOP_SIZE); + let a = V::load_aligned(cur); + let b = V::load_aligned(cur.add(1 * V::BYTES)); + let c = V::load_aligned(cur.add(2 * V::BYTES)); + let d = V::load_aligned(cur.add(3 * V::BYTES)); + let eqa = self.v1.cmpeq(a); + let eqb = self.v1.cmpeq(b); + let eqc = self.v1.cmpeq(c); + let eqd = self.v1.cmpeq(d); + let or1 = eqa.or(eqb); + let or2 = eqc.or(eqd); + let or3 = or1.or(or2); + if or3.movemask_will_have_non_zero() { + let mask = eqd.movemask(); + if mask.has_non_zero() { + return Some(cur.add(3 * V::BYTES).add(topos(mask))); + } + + let mask = eqc.movemask(); + if mask.has_non_zero() { + return Some(cur.add(2 * V::BYTES).add(topos(mask))); + } + + let mask = eqb.movemask(); + if mask.has_non_zero() { + return Some(cur.add(1 * V::BYTES).add(topos(mask))); + } + + let mask = eqa.movemask(); + debug_assert!(mask.has_non_zero()); + return Some(cur.add(topos(mask))); + } + } + } + while cur >= start.add(V::BYTES) { + debug_assert!(cur.distance(start) >= V::BYTES); + cur = cur.sub(V::BYTES); + if let Some(cur) = self.search_chunk(cur, topos) { + return Some(cur); + } + } + if cur > start { + debug_assert!(cur.distance(start) < V::BYTES); + return self.search_chunk(start, topos); + } + None + } + + /// Return a count of all matching bytes in the given haystack. + /// + /// # Safety + /// + /// * It must be the case that `start < end` and that the distance between + /// them is at least equal to `V::BYTES`. That is, it must always be valid + /// to do at least an unaligned load of `V` at `start`. + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + #[inline(always)] + pub(crate) unsafe fn count_raw( + &self, + start: *const u8, + end: *const u8, + ) -> usize { + debug_assert!(V::BYTES <= 32, "vector cannot be bigger than 32 bytes"); + + let confirm = |b| b == self.needle1(); + let len = end.distance(start); + debug_assert!( + len >= V::BYTES, + "haystack has length {}, but must be at least {}", + len, + V::BYTES + ); + + // Set `cur` to the first V-aligned pointer greater than `start`. + let mut cur = start.add(V::BYTES - (start.as_usize() & V::ALIGN)); + // Count any matching bytes before we start our aligned loop. + let mut count = count_byte_by_byte(start, cur, confirm); + debug_assert!(cur > start && end.sub(V::BYTES) >= start); + if len >= Self::LOOP_SIZE { + while cur <= end.sub(Self::LOOP_SIZE) { + debug_assert_eq!(0, cur.as_usize() % V::BYTES); + + let a = V::load_aligned(cur); + let b = V::load_aligned(cur.add(1 * V::BYTES)); + let c = V::load_aligned(cur.add(2 * V::BYTES)); + let d = V::load_aligned(cur.add(3 * V::BYTES)); + let eqa = self.v1.cmpeq(a); + let eqb = self.v1.cmpeq(b); + let eqc = self.v1.cmpeq(c); + let eqd = self.v1.cmpeq(d); + count += eqa.movemask().count_ones(); + count += eqb.movemask().count_ones(); + count += eqc.movemask().count_ones(); + count += eqd.movemask().count_ones(); + cur = cur.add(Self::LOOP_SIZE); + } + } + // Handle any leftovers after the aligned loop above. We use unaligned + // loads here, but I believe we are guaranteed that they are aligned + // since `cur` is aligned. + while cur <= end.sub(V::BYTES) { + debug_assert!(end.distance(cur) >= V::BYTES); + let chunk = V::load_unaligned(cur); + count += self.v1.cmpeq(chunk).movemask().count_ones(); + cur = cur.add(V::BYTES); + } + // And finally count any leftovers that weren't caught above. + count += count_byte_by_byte(cur, end, confirm); + count + } + + /// Search `V::BYTES` starting at `cur` via an unaligned load. + /// + /// `mask_to_offset` should be a function that converts a `movemask` to + /// an offset such that `cur.add(offset)` corresponds to a pointer to the + /// match location if one is found. Generally it is expected to use either + /// `mask_to_first_offset` or `mask_to_last_offset`, depending on whether + /// one is implementing a forward or reverse search, respectively. + /// + /// # Safety + /// + /// `cur` must be a valid pointer and it must be valid to do an unaligned + /// load of size `V::BYTES` at `cur`. + #[inline(always)] + unsafe fn search_chunk( + &self, + cur: *const u8, + mask_to_offset: impl Fn(V::Mask) -> usize, + ) -> Option<*const u8> { + let chunk = V::load_unaligned(cur); + let mask = self.v1.cmpeq(chunk).movemask(); + if mask.has_non_zero() { + Some(cur.add(mask_to_offset(mask))) + } else { + None + } + } +} + +/// Finds all occurrences of two bytes in a haystack. +/// +/// That is, this reports matches of one of two possible bytes. For example, +/// searching for `a` or `b` in `afoobar` would report matches at offsets `0`, +/// `4` and `5`. +#[derive(Clone, Copy, Debug)] +pub(crate) struct Two { + s1: u8, + s2: u8, + v1: V, + v2: V, +} + +impl Two { + /// The number of bytes we examine per each iteration of our search loop. + const LOOP_SIZE: usize = 2 * V::BYTES; + + /// Create a new searcher that finds occurrences of the byte given. + #[inline(always)] + pub(crate) unsafe fn new(needle1: u8, needle2: u8) -> Two { + Two { + s1: needle1, + s2: needle2, + v1: V::splat(needle1), + v2: V::splat(needle2), + } + } + + /// Returns the first needle given to `Two::new`. + #[inline(always)] + pub(crate) fn needle1(&self) -> u8 { + self.s1 + } + + /// Returns the second needle given to `Two::new`. + #[inline(always)] + pub(crate) fn needle2(&self) -> u8 { + self.s2 + } + + /// Return a pointer to the first occurrence of one of the needles in the + /// given haystack. If no such occurrence exists, then `None` is returned. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// # Safety + /// + /// * It must be the case that `start < end` and that the distance between + /// them is at least equal to `V::BYTES`. That is, it must always be valid + /// to do at least an unaligned load of `V` at `start`. + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + #[inline(always)] + pub(crate) unsafe fn find_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + // If we want to support vectors bigger than 256 bits, we probably + // need to move up to using a u64 for the masks used below. Currently + // they are 32 bits, which means we're SOL for vectors that need masks + // bigger than 32 bits. Overall unclear until there's a use case. + debug_assert!(V::BYTES <= 32, "vector cannot be bigger than 32 bytes"); + + let topos = V::Mask::first_offset; + let len = end.distance(start); + debug_assert!( + len >= V::BYTES, + "haystack has length {}, but must be at least {}", + len, + V::BYTES + ); + + // Search a possibly unaligned chunk at `start`. This covers any part + // of the haystack prior to where aligned loads can start. + if let Some(cur) = self.search_chunk(start, topos) { + return Some(cur); + } + // Set `cur` to the first V-aligned pointer greater than `start`. + let mut cur = start.add(V::BYTES - (start.as_usize() & V::ALIGN)); + debug_assert!(cur > start && end.sub(V::BYTES) >= start); + if len >= Self::LOOP_SIZE { + while cur <= end.sub(Self::LOOP_SIZE) { + debug_assert_eq!(0, cur.as_usize() % V::BYTES); + + let a = V::load_aligned(cur); + let b = V::load_aligned(cur.add(V::BYTES)); + let eqa1 = self.v1.cmpeq(a); + let eqb1 = self.v1.cmpeq(b); + let eqa2 = self.v2.cmpeq(a); + let eqb2 = self.v2.cmpeq(b); + let or1 = eqa1.or(eqb1); + let or2 = eqa2.or(eqb2); + let or3 = or1.or(or2); + if or3.movemask_will_have_non_zero() { + let mask = eqa1.movemask().or(eqa2.movemask()); + if mask.has_non_zero() { + return Some(cur.add(topos(mask))); + } + + let mask = eqb1.movemask().or(eqb2.movemask()); + debug_assert!(mask.has_non_zero()); + return Some(cur.add(V::BYTES).add(topos(mask))); + } + cur = cur.add(Self::LOOP_SIZE); + } + } + // Handle any leftovers after the aligned loop above. We use unaligned + // loads here, but I believe we are guaranteed that they are aligned + // since `cur` is aligned. + while cur <= end.sub(V::BYTES) { + debug_assert!(end.distance(cur) >= V::BYTES); + if let Some(cur) = self.search_chunk(cur, topos) { + return Some(cur); + } + cur = cur.add(V::BYTES); + } + // Finally handle any remaining bytes less than the size of V. In this + // case, our pointer may indeed be unaligned and the load may overlap + // with the previous one. But that's okay since we know the previous + // load didn't lead to a match (otherwise we wouldn't be here). + if cur < end { + debug_assert!(end.distance(cur) < V::BYTES); + cur = cur.sub(V::BYTES - end.distance(cur)); + debug_assert_eq!(end.distance(cur), V::BYTES); + return self.search_chunk(cur, topos); + } + None + } + + /// Return a pointer to the last occurrence of the needle in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// # Safety + /// + /// * It must be the case that `start < end` and that the distance between + /// them is at least equal to `V::BYTES`. That is, it must always be valid + /// to do at least an unaligned load of `V` at `start`. + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + #[inline(always)] + pub(crate) unsafe fn rfind_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + // If we want to support vectors bigger than 256 bits, we probably + // need to move up to using a u64 for the masks used below. Currently + // they are 32 bits, which means we're SOL for vectors that need masks + // bigger than 32 bits. Overall unclear until there's a use case. + debug_assert!(V::BYTES <= 32, "vector cannot be bigger than 32 bytes"); + + let topos = V::Mask::last_offset; + let len = end.distance(start); + debug_assert!( + len >= V::BYTES, + "haystack has length {}, but must be at least {}", + len, + V::BYTES + ); + + if let Some(cur) = self.search_chunk(end.sub(V::BYTES), topos) { + return Some(cur); + } + let mut cur = end.sub(end.as_usize() & V::ALIGN); + debug_assert!(start <= cur && cur <= end); + if len >= Self::LOOP_SIZE { + while cur >= start.add(Self::LOOP_SIZE) { + debug_assert_eq!(0, cur.as_usize() % V::BYTES); + + cur = cur.sub(Self::LOOP_SIZE); + let a = V::load_aligned(cur); + let b = V::load_aligned(cur.add(V::BYTES)); + let eqa1 = self.v1.cmpeq(a); + let eqb1 = self.v1.cmpeq(b); + let eqa2 = self.v2.cmpeq(a); + let eqb2 = self.v2.cmpeq(b); + let or1 = eqa1.or(eqb1); + let or2 = eqa2.or(eqb2); + let or3 = or1.or(or2); + if or3.movemask_will_have_non_zero() { + let mask = eqb1.movemask().or(eqb2.movemask()); + if mask.has_non_zero() { + return Some(cur.add(V::BYTES).add(topos(mask))); + } + + let mask = eqa1.movemask().or(eqa2.movemask()); + debug_assert!(mask.has_non_zero()); + return Some(cur.add(topos(mask))); + } + } + } + while cur >= start.add(V::BYTES) { + debug_assert!(cur.distance(start) >= V::BYTES); + cur = cur.sub(V::BYTES); + if let Some(cur) = self.search_chunk(cur, topos) { + return Some(cur); + } + } + if cur > start { + debug_assert!(cur.distance(start) < V::BYTES); + return self.search_chunk(start, topos); + } + None + } + + /// Search `V::BYTES` starting at `cur` via an unaligned load. + /// + /// `mask_to_offset` should be a function that converts a `movemask` to + /// an offset such that `cur.add(offset)` corresponds to a pointer to the + /// match location if one is found. Generally it is expected to use either + /// `mask_to_first_offset` or `mask_to_last_offset`, depending on whether + /// one is implementing a forward or reverse search, respectively. + /// + /// # Safety + /// + /// `cur` must be a valid pointer and it must be valid to do an unaligned + /// load of size `V::BYTES` at `cur`. + #[inline(always)] + unsafe fn search_chunk( + &self, + cur: *const u8, + mask_to_offset: impl Fn(V::Mask) -> usize, + ) -> Option<*const u8> { + let chunk = V::load_unaligned(cur); + let eq1 = self.v1.cmpeq(chunk); + let eq2 = self.v2.cmpeq(chunk); + let mask = eq1.or(eq2).movemask(); + if mask.has_non_zero() { + let mask1 = eq1.movemask(); + let mask2 = eq2.movemask(); + Some(cur.add(mask_to_offset(mask1.or(mask2)))) + } else { + None + } + } +} + +/// Finds all occurrences of two bytes in a haystack. +/// +/// That is, this reports matches of one of two possible bytes. For example, +/// searching for `a` or `b` in `afoobar` would report matches at offsets `0`, +/// `4` and `5`. +#[derive(Clone, Copy, Debug)] +pub(crate) struct Three { + s1: u8, + s2: u8, + s3: u8, + v1: V, + v2: V, + v3: V, +} + +impl Three { + /// The number of bytes we examine per each iteration of our search loop. + const LOOP_SIZE: usize = 2 * V::BYTES; + + /// Create a new searcher that finds occurrences of the byte given. + #[inline(always)] + pub(crate) unsafe fn new( + needle1: u8, + needle2: u8, + needle3: u8, + ) -> Three { + Three { + s1: needle1, + s2: needle2, + s3: needle3, + v1: V::splat(needle1), + v2: V::splat(needle2), + v3: V::splat(needle3), + } + } + + /// Returns the first needle given to `Three::new`. + #[inline(always)] + pub(crate) fn needle1(&self) -> u8 { + self.s1 + } + + /// Returns the second needle given to `Three::new`. + #[inline(always)] + pub(crate) fn needle2(&self) -> u8 { + self.s2 + } + + /// Returns the third needle given to `Three::new`. + #[inline(always)] + pub(crate) fn needle3(&self) -> u8 { + self.s3 + } + + /// Return a pointer to the first occurrence of one of the needles in the + /// given haystack. If no such occurrence exists, then `None` is returned. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// # Safety + /// + /// * It must be the case that `start < end` and that the distance between + /// them is at least equal to `V::BYTES`. That is, it must always be valid + /// to do at least an unaligned load of `V` at `start`. + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + #[inline(always)] + pub(crate) unsafe fn find_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + // If we want to support vectors bigger than 256 bits, we probably + // need to move up to using a u64 for the masks used below. Currently + // they are 32 bits, which means we're SOL for vectors that need masks + // bigger than 32 bits. Overall unclear until there's a use case. + debug_assert!(V::BYTES <= 32, "vector cannot be bigger than 32 bytes"); + + let topos = V::Mask::first_offset; + let len = end.distance(start); + debug_assert!( + len >= V::BYTES, + "haystack has length {}, but must be at least {}", + len, + V::BYTES + ); + + // Search a possibly unaligned chunk at `start`. This covers any part + // of the haystack prior to where aligned loads can start. + if let Some(cur) = self.search_chunk(start, topos) { + return Some(cur); + } + // Set `cur` to the first V-aligned pointer greater than `start`. + let mut cur = start.add(V::BYTES - (start.as_usize() & V::ALIGN)); + debug_assert!(cur > start && end.sub(V::BYTES) >= start); + if len >= Self::LOOP_SIZE { + while cur <= end.sub(Self::LOOP_SIZE) { + debug_assert_eq!(0, cur.as_usize() % V::BYTES); + + let a = V::load_aligned(cur); + let b = V::load_aligned(cur.add(V::BYTES)); + let eqa1 = self.v1.cmpeq(a); + let eqb1 = self.v1.cmpeq(b); + let eqa2 = self.v2.cmpeq(a); + let eqb2 = self.v2.cmpeq(b); + let eqa3 = self.v3.cmpeq(a); + let eqb3 = self.v3.cmpeq(b); + let or1 = eqa1.or(eqb1); + let or2 = eqa2.or(eqb2); + let or3 = eqa3.or(eqb3); + let or4 = or1.or(or2); + let or5 = or3.or(or4); + if or5.movemask_will_have_non_zero() { + let mask = eqa1 + .movemask() + .or(eqa2.movemask()) + .or(eqa3.movemask()); + if mask.has_non_zero() { + return Some(cur.add(topos(mask))); + } + + let mask = eqb1 + .movemask() + .or(eqb2.movemask()) + .or(eqb3.movemask()); + debug_assert!(mask.has_non_zero()); + return Some(cur.add(V::BYTES).add(topos(mask))); + } + cur = cur.add(Self::LOOP_SIZE); + } + } + // Handle any leftovers after the aligned loop above. We use unaligned + // loads here, but I believe we are guaranteed that they are aligned + // since `cur` is aligned. + while cur <= end.sub(V::BYTES) { + debug_assert!(end.distance(cur) >= V::BYTES); + if let Some(cur) = self.search_chunk(cur, topos) { + return Some(cur); + } + cur = cur.add(V::BYTES); + } + // Finally handle any remaining bytes less than the size of V. In this + // case, our pointer may indeed be unaligned and the load may overlap + // with the previous one. But that's okay since we know the previous + // load didn't lead to a match (otherwise we wouldn't be here). + if cur < end { + debug_assert!(end.distance(cur) < V::BYTES); + cur = cur.sub(V::BYTES - end.distance(cur)); + debug_assert_eq!(end.distance(cur), V::BYTES); + return self.search_chunk(cur, topos); + } + None + } + + /// Return a pointer to the last occurrence of the needle in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// # Safety + /// + /// * It must be the case that `start < end` and that the distance between + /// them is at least equal to `V::BYTES`. That is, it must always be valid + /// to do at least an unaligned load of `V` at `start`. + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + #[inline(always)] + pub(crate) unsafe fn rfind_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + // If we want to support vectors bigger than 256 bits, we probably + // need to move up to using a u64 for the masks used below. Currently + // they are 32 bits, which means we're SOL for vectors that need masks + // bigger than 32 bits. Overall unclear until there's a use case. + debug_assert!(V::BYTES <= 32, "vector cannot be bigger than 32 bytes"); + + let topos = V::Mask::last_offset; + let len = end.distance(start); + debug_assert!( + len >= V::BYTES, + "haystack has length {}, but must be at least {}", + len, + V::BYTES + ); + + if let Some(cur) = self.search_chunk(end.sub(V::BYTES), topos) { + return Some(cur); + } + let mut cur = end.sub(end.as_usize() & V::ALIGN); + debug_assert!(start <= cur && cur <= end); + if len >= Self::LOOP_SIZE { + while cur >= start.add(Self::LOOP_SIZE) { + debug_assert_eq!(0, cur.as_usize() % V::BYTES); + + cur = cur.sub(Self::LOOP_SIZE); + let a = V::load_aligned(cur); + let b = V::load_aligned(cur.add(V::BYTES)); + let eqa1 = self.v1.cmpeq(a); + let eqb1 = self.v1.cmpeq(b); + let eqa2 = self.v2.cmpeq(a); + let eqb2 = self.v2.cmpeq(b); + let eqa3 = self.v3.cmpeq(a); + let eqb3 = self.v3.cmpeq(b); + let or1 = eqa1.or(eqb1); + let or2 = eqa2.or(eqb2); + let or3 = eqa3.or(eqb3); + let or4 = or1.or(or2); + let or5 = or3.or(or4); + if or5.movemask_will_have_non_zero() { + let mask = eqb1 + .movemask() + .or(eqb2.movemask()) + .or(eqb3.movemask()); + if mask.has_non_zero() { + return Some(cur.add(V::BYTES).add(topos(mask))); + } + + let mask = eqa1 + .movemask() + .or(eqa2.movemask()) + .or(eqa3.movemask()); + debug_assert!(mask.has_non_zero()); + return Some(cur.add(topos(mask))); + } + } + } + while cur >= start.add(V::BYTES) { + debug_assert!(cur.distance(start) >= V::BYTES); + cur = cur.sub(V::BYTES); + if let Some(cur) = self.search_chunk(cur, topos) { + return Some(cur); + } + } + if cur > start { + debug_assert!(cur.distance(start) < V::BYTES); + return self.search_chunk(start, topos); + } + None + } + + /// Search `V::BYTES` starting at `cur` via an unaligned load. + /// + /// `mask_to_offset` should be a function that converts a `movemask` to + /// an offset such that `cur.add(offset)` corresponds to a pointer to the + /// match location if one is found. Generally it is expected to use either + /// `mask_to_first_offset` or `mask_to_last_offset`, depending on whether + /// one is implementing a forward or reverse search, respectively. + /// + /// # Safety + /// + /// `cur` must be a valid pointer and it must be valid to do an unaligned + /// load of size `V::BYTES` at `cur`. + #[inline(always)] + unsafe fn search_chunk( + &self, + cur: *const u8, + mask_to_offset: impl Fn(V::Mask) -> usize, + ) -> Option<*const u8> { + let chunk = V::load_unaligned(cur); + let eq1 = self.v1.cmpeq(chunk); + let eq2 = self.v2.cmpeq(chunk); + let eq3 = self.v3.cmpeq(chunk); + let mask = eq1.or(eq2).or(eq3).movemask(); + if mask.has_non_zero() { + let mask1 = eq1.movemask(); + let mask2 = eq2.movemask(); + let mask3 = eq3.movemask(); + Some(cur.add(mask_to_offset(mask1.or(mask2).or(mask3)))) + } else { + None + } + } +} + +/// An iterator over all occurrences of a set of bytes in a haystack. +/// +/// This iterator implements the routines necessary to provide a +/// `DoubleEndedIterator` impl, which means it can also be used to find +/// occurrences in reverse order. +/// +/// The lifetime parameters are as follows: +/// +/// * `'h` refers to the lifetime of the haystack being searched. +/// +/// This type is intended to be used to implement all iterators for the +/// `memchr` family of functions. It handles a tiny bit of marginally tricky +/// raw pointer math, but otherwise expects the caller to provide `find_raw` +/// and `rfind_raw` routines for each call of `next` and `next_back`, +/// respectively. +#[derive(Clone, Debug)] +pub(crate) struct Iter<'h> { + /// The original starting point into the haystack. We use this to convert + /// pointers to offsets. + original_start: *const u8, + /// The current starting point into the haystack. That is, where the next + /// search will begin. + start: *const u8, + /// The current ending point into the haystack. That is, where the next + /// reverse search will begin. + end: *const u8, + /// A marker for tracking the lifetime of the start/cur_start/cur_end + /// pointers above, which all point into the haystack. + haystack: core::marker::PhantomData<&'h [u8]>, +} + +// SAFETY: Iter contains no shared references to anything that performs any +// interior mutations. Also, the lifetime guarantees that Iter will not outlive +// the haystack. +unsafe impl<'h> Send for Iter<'h> {} + +// SAFETY: Iter perform no interior mutations, therefore no explicit +// synchronization is necessary. Also, the lifetime guarantees that Iter will +// not outlive the haystack. +unsafe impl<'h> Sync for Iter<'h> {} + +impl<'h> Iter<'h> { + /// Create a new generic memchr iterator. + #[inline(always)] + pub(crate) fn new(haystack: &'h [u8]) -> Iter<'h> { + Iter { + original_start: haystack.as_ptr(), + start: haystack.as_ptr(), + end: haystack.as_ptr().wrapping_add(haystack.len()), + haystack: core::marker::PhantomData, + } + } + + /// Returns the next occurrence in the forward direction. + /// + /// # Safety + /// + /// Callers must ensure that if a pointer is returned from the closure + /// provided, then it must be greater than or equal to the start pointer + /// and less than the end pointer. + #[inline(always)] + pub(crate) unsafe fn next( + &mut self, + mut find_raw: impl FnMut(*const u8, *const u8) -> Option<*const u8>, + ) -> Option { + // SAFETY: Pointers are derived directly from the same &[u8] haystack. + // We only ever modify start/end corresponding to a matching offset + // found between start and end. Thus all changes to start/end maintain + // our safety requirements. + // + // The only other assumption we rely on is that the pointer returned + // by `find_raw` satisfies `self.start <= found < self.end`, and that + // safety contract is forwarded to the caller. + let found = find_raw(self.start, self.end)?; + let result = found.distance(self.original_start); + self.start = found.add(1); + Some(result) + } + + /// Returns the number of remaining elements in this iterator. + #[inline(always)] + pub(crate) fn count( + self, + mut count_raw: impl FnMut(*const u8, *const u8) -> usize, + ) -> usize { + // SAFETY: Pointers are derived directly from the same &[u8] haystack. + // We only ever modify start/end corresponding to a matching offset + // found between start and end. Thus all changes to start/end maintain + // our safety requirements. + count_raw(self.start, self.end) + } + + /// Returns the next occurrence in reverse. + /// + /// # Safety + /// + /// Callers must ensure that if a pointer is returned from the closure + /// provided, then it must be greater than or equal to the start pointer + /// and less than the end pointer. + #[inline(always)] + pub(crate) unsafe fn next_back( + &mut self, + mut rfind_raw: impl FnMut(*const u8, *const u8) -> Option<*const u8>, + ) -> Option { + // SAFETY: Pointers are derived directly from the same &[u8] haystack. + // We only ever modify start/end corresponding to a matching offset + // found between start and end. Thus all changes to start/end maintain + // our safety requirements. + // + // The only other assumption we rely on is that the pointer returned + // by `rfind_raw` satisfies `self.start <= found < self.end`, and that + // safety contract is forwarded to the caller. + let found = rfind_raw(self.start, self.end)?; + let result = found.distance(self.original_start); + self.end = found; + Some(result) + } + + /// Provides an implementation of `Iterator::size_hint`. + #[inline(always)] + pub(crate) fn size_hint(&self) -> (usize, Option) { + (0, Some(self.end.as_usize().saturating_sub(self.start.as_usize()))) + } +} + +/// Search a slice using a function that operates on raw pointers. +/// +/// Given a function to search a contiguous sequence of memory for the location +/// of a non-empty set of bytes, this will execute that search on a slice of +/// bytes. The pointer returned by the given function will be converted to an +/// offset relative to the starting point of the given slice. That is, if a +/// match is found, the offset returned by this routine is guaranteed to be a +/// valid index into `haystack`. +/// +/// Callers may use this for a forward or reverse search. +/// +/// # Safety +/// +/// Callers must ensure that if a pointer is returned by `find_raw`, then the +/// pointer must be greater than or equal to the starting pointer and less than +/// the end pointer. +#[inline(always)] +pub(crate) unsafe fn search_slice_with_raw( + haystack: &[u8], + mut find_raw: impl FnMut(*const u8, *const u8) -> Option<*const u8>, +) -> Option { + // SAFETY: We rely on `find_raw` to return a correct and valid pointer, but + // otherwise, `start` and `end` are valid due to the guarantees provided by + // a &[u8]. + let start = haystack.as_ptr(); + let end = start.add(haystack.len()); + let found = find_raw(start, end)?; + let idx = found.distance(start); + // Required by safety invariant required for find_raw + // this lets the compiler know the returned index is in bounds for the slice + if idx >= haystack.len() { + core::hint::unreachable_unchecked(); + } + Some(idx) +} + +/// Performs a forward byte-at-a-time loop until either `ptr >= end_ptr` or +/// until `confirm(*ptr)` returns `true`. If the former occurs, then `None` is +/// returned. If the latter occurs, then the pointer at which `confirm` returns +/// `true` is returned. +/// +/// # Safety +/// +/// Callers must provide valid pointers and they must satisfy `start_ptr <= +/// ptr` and `ptr <= end_ptr`. +#[inline(always)] +pub(crate) unsafe fn fwd_byte_by_byte bool>( + start: *const u8, + end: *const u8, + confirm: F, +) -> Option<*const u8> { + debug_assert!(start <= end); + let mut ptr = start; + while ptr < end { + if confirm(*ptr) { + return Some(ptr); + } + ptr = ptr.offset(1); + } + None +} + +/// Performs a reverse byte-at-a-time loop until either `ptr < start_ptr` or +/// until `confirm(*ptr)` returns `true`. If the former occurs, then `None` is +/// returned. If the latter occurs, then the pointer at which `confirm` returns +/// `true` is returned. +/// +/// # Safety +/// +/// Callers must provide valid pointers and they must satisfy `start_ptr <= +/// ptr` and `ptr <= end_ptr`. +#[inline(always)] +pub(crate) unsafe fn rev_byte_by_byte bool>( + start: *const u8, + end: *const u8, + confirm: F, +) -> Option<*const u8> { + debug_assert!(start <= end); + + let mut ptr = end; + while ptr > start { + ptr = ptr.offset(-1); + if confirm(*ptr) { + return Some(ptr); + } + } + None +} + +/// Performs a forward byte-at-a-time loop until `ptr >= end_ptr` and returns +/// the number of times `confirm(*ptr)` returns `true`. +/// +/// # Safety +/// +/// Callers must provide valid pointers and they must satisfy `start_ptr <= +/// ptr` and `ptr <= end_ptr`. +#[inline(always)] +pub(crate) unsafe fn count_byte_by_byte bool>( + start: *const u8, + end: *const u8, + confirm: F, +) -> usize { + debug_assert!(start <= end); + let mut ptr = start; + let mut count = 0; + while ptr < end { + if confirm(*ptr) { + count += 1; + } + ptr = ptr.offset(1); + } + count +} diff --git a/third_party/crates/memchr-2.8.3/src/arch/generic/mod.rs b/third_party/crates/memchr-2.8.3/src/arch/generic/mod.rs new file mode 100644 index 0000000..63ee3f0 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/generic/mod.rs @@ -0,0 +1,14 @@ +/*! +This module defines "generic" routines that can be specialized to specific +architectures. + +We don't expose this module primarily because it would require exposing all +of the internal infrastructure required to write these generic routines. +That infrastructure should be treated as an implementation detail so that +it is allowed to evolve. Instead, what we expose are architecture specific +instantiations of these generic implementations. The generic code just lets us +write the code once (usually). +*/ + +pub(crate) mod memchr; +pub(crate) mod packedpair; diff --git a/third_party/crates/memchr-2.8.3/src/arch/generic/packedpair.rs b/third_party/crates/memchr-2.8.3/src/arch/generic/packedpair.rs new file mode 100644 index 0000000..45d088c --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/generic/packedpair.rs @@ -0,0 +1,317 @@ +/*! +Generic crate-internal routines for the "packed pair" SIMD algorithm. + +The "packed pair" algorithm is based on the [generic SIMD] algorithm. The main +difference is that it (by default) uses a background distribution of byte +frequencies to heuristically select the pair of bytes to search for. + +[generic SIMD]: http://0x80.pl/articles/simd-strfind.html#first-and-last +*/ + +use crate::{ + arch::all::{is_equal_raw, packedpair::Pair}, + ext::Pointer, + vector::{MoveMask, Vector}, +}; + +/// A generic architecture dependent "packed pair" finder. +/// +/// This finder picks two bytes that it believes have high predictive power +/// for indicating an overall match of a needle. Depending on whether +/// `Finder::find` or `Finder::find_prefilter` is used, it reports offsets +/// where the needle matches or could match. In the prefilter case, candidates +/// are reported whenever the [`Pair`] of bytes given matches. +/// +/// This is architecture dependent because it uses specific vector operations +/// to look for occurrences of the pair of bytes. +/// +/// This type is not meant to be exported and is instead meant to be used as +/// the implementation for architecture specific facades. Why? Because it's a +/// bit of a quirky API that requires `inline(always)` annotations. And pretty +/// much everything has safety obligations due (at least) to the caller needing +/// to inline calls into routines marked with +/// `#[target_feature(enable = "...")]`. +#[derive(Clone, Copy, Debug)] +pub(crate) struct Finder { + pair: Pair, + v1: V, + v2: V, + min_haystack_len: usize, +} + +impl Finder { + /// Create a new pair searcher. The searcher returned can either report + /// exact matches of `needle` or act as a prefilter and report candidate + /// positions of `needle`. + /// + /// # Safety + /// + /// Callers must ensure that whatever vector type this routine is called + /// with is supported by the current environment. + /// + /// Callers must also ensure that `needle.len() >= 2`. + #[inline(always)] + pub(crate) unsafe fn new(needle: &[u8], pair: Pair) -> Finder { + let max_index = pair.index1().max(pair.index2()); + let min_haystack_len = + core::cmp::max(needle.len(), usize::from(max_index) + V::BYTES); + let v1 = V::splat(needle[usize::from(pair.index1())]); + let v2 = V::splat(needle[usize::from(pair.index2())]); + Finder { pair, v1, v2, min_haystack_len } + } + + /// Searches the given haystack for the given needle. The needle given + /// should be the same as the needle that this finder was initialized + /// with. + /// + /// # Panics + /// + /// When `haystack.len()` is less than [`Finder::min_haystack_len`]. + /// + /// # Safety + /// + /// Since this is meant to be used with vector functions, callers need to + /// specialize this inside of a function with a `target_feature` attribute. + /// Therefore, callers must ensure that whatever target feature is being + /// used supports the vector functions that this function is specialized + /// for. (For the specific vector functions used, see the Vector trait + /// implementations.) + #[inline(always)] + pub(crate) unsafe fn find( + &self, + haystack: &[u8], + needle: &[u8], + ) -> Option { + assert!( + haystack.len() >= self.min_haystack_len, + "haystack too small, should be at least {} but got {}", + self.min_haystack_len, + haystack.len(), + ); + + let all = V::Mask::all_zeros_except_least_significant(0); + let start = haystack.as_ptr(); + let end = start.add(haystack.len()); + let max = end.sub(self.min_haystack_len); + let mut cur = start; + + // N.B. I did experiment with unrolling the loop to deal with size(V) + // bytes at a time and 2*size(V) bytes at a time. The double unroll + // was marginally faster while the quadruple unroll was unambiguously + // slower. In the end, I decided the complexity from unrolling wasn't + // worth it. I used the memmem/krate/prebuilt/huge-en/ benchmarks to + // compare. + while cur <= max { + if let Some(chunki) = self.find_in_chunk(needle, cur, end, all) { + return Some(matched(start, cur, chunki)); + } + cur = cur.add(V::BYTES); + } + if cur < end { + let remaining = end.distance(cur); + debug_assert!( + remaining < self.min_haystack_len, + "remaining bytes should be smaller than the minimum haystack \ + length of {}, but there are {} bytes remaining", + self.min_haystack_len, + remaining, + ); + if remaining < needle.len() { + return None; + } + debug_assert!( + max < cur, + "after main loop, cur should have exceeded max", + ); + let overlap = cur.distance(max); + debug_assert!( + overlap > 0, + "overlap ({}) must always be non-zero", + overlap, + ); + debug_assert!( + overlap < V::BYTES, + "overlap ({}) cannot possibly be >= than a vector ({})", + overlap, + V::BYTES, + ); + // The mask has all of its bits set except for the first N least + // significant bits, where N=overlap. This way, any matches that + // occur in find_in_chunk within the overlap are automatically + // ignored. + let mask = V::Mask::all_zeros_except_least_significant(overlap); + cur = max; + let m = self.find_in_chunk(needle, cur, end, mask); + if let Some(chunki) = m { + return Some(matched(start, cur, chunki)); + } + } + None + } + + /// Searches the given haystack for offsets that represent candidate + /// matches of the `needle` given to this finder's constructor. The offsets + /// returned, if they are a match, correspond to the starting offset of + /// `needle` in the given `haystack`. + /// + /// # Panics + /// + /// When `haystack.len()` is less than [`Finder::min_haystack_len`]. + /// + /// # Safety + /// + /// Since this is meant to be used with vector functions, callers need to + /// specialize this inside of a function with a `target_feature` attribute. + /// Therefore, callers must ensure that whatever target feature is being + /// used supports the vector functions that this function is specialized + /// for. (For the specific vector functions used, see the Vector trait + /// implementations.) + #[inline(always)] + pub(crate) unsafe fn find_prefilter( + &self, + haystack: &[u8], + ) -> Option { + assert!( + haystack.len() >= self.min_haystack_len, + "haystack too small, should be at least {} but got {}", + self.min_haystack_len, + haystack.len(), + ); + + let start = haystack.as_ptr(); + let end = start.add(haystack.len()); + let max = end.sub(self.min_haystack_len); + let mut cur = start; + + // N.B. I did experiment with unrolling the loop to deal with size(V) + // bytes at a time and 2*size(V) bytes at a time. The double unroll + // was marginally faster while the quadruple unroll was unambiguously + // slower. In the end, I decided the complexity from unrolling wasn't + // worth it. I used the memmem/krate/prebuilt/huge-en/ benchmarks to + // compare. + while cur <= max { + if let Some(chunki) = self.find_prefilter_in_chunk(cur) { + return Some(matched(start, cur, chunki)); + } + cur = cur.add(V::BYTES); + } + if cur < end { + // This routine immediately quits if a candidate match is found. + // That means that if we're here, no candidate matches have been + // found at or before 'ptr'. Thus, we don't need to mask anything + // out even though we might technically search part of the haystack + // that we've already searched (because we know it can't match). + cur = max; + if let Some(chunki) = self.find_prefilter_in_chunk(cur) { + return Some(matched(start, cur, chunki)); + } + } + None + } + + /// Search for an occurrence of our byte pair from the needle in the chunk + /// pointed to by cur, with the end of the haystack pointed to by end. + /// When an occurrence is found, memcmp is run to check if a match occurs + /// at the corresponding position. + /// + /// `mask` should have bits set corresponding the positions in the chunk + /// in which matches are considered. This is only used for the last vector + /// load where the beginning of the vector might have overlapped with the + /// last load in the main loop. The mask lets us avoid visiting positions + /// that have already been discarded as matches. + /// + /// # Safety + /// + /// It must be safe to do an unaligned read of size(V) bytes starting at + /// both (cur + self.index1) and (cur + self.index2). It must also be safe + /// to do unaligned loads on cur up to (end - needle.len()). + #[inline(always)] + unsafe fn find_in_chunk( + &self, + needle: &[u8], + cur: *const u8, + end: *const u8, + mask: V::Mask, + ) -> Option { + let index1 = usize::from(self.pair.index1()); + let index2 = usize::from(self.pair.index2()); + let chunk1 = V::load_unaligned(cur.add(index1)); + let chunk2 = V::load_unaligned(cur.add(index2)); + let eq1 = chunk1.cmpeq(self.v1); + let eq2 = chunk2.cmpeq(self.v2); + + let mut offsets = eq1.and(eq2).movemask().and(mask); + while offsets.has_non_zero() { + let offset = offsets.first_offset(); + let cur = cur.add(offset); + if end.distance(cur) < needle.len() { + return None; + } + if is_equal_raw(needle.as_ptr(), cur, needle.len()) { + return Some(offset); + } + offsets = offsets.clear_least_significant_bit(); + } + None + } + + /// Search for an occurrence of our byte pair from the needle in the chunk + /// pointed to by cur, with the end of the haystack pointed to by end. + /// When an occurrence is found, memcmp is run to check if a match occurs + /// at the corresponding position. + /// + /// # Safety + /// + /// It must be safe to do an unaligned read of size(V) bytes starting at + /// both (cur + self.index1) and (cur + self.index2). It must also be safe + /// to do unaligned reads on cur up to (end - needle.len()). + #[inline(always)] + unsafe fn find_prefilter_in_chunk(&self, cur: *const u8) -> Option { + let index1 = usize::from(self.pair.index1()); + let index2 = usize::from(self.pair.index2()); + let chunk1 = V::load_unaligned(cur.add(index1)); + let chunk2 = V::load_unaligned(cur.add(index2)); + let eq1 = chunk1.cmpeq(self.v1); + let eq2 = chunk2.cmpeq(self.v2); + + let offsets = eq1.and(eq2).movemask(); + if !offsets.has_non_zero() { + return None; + } + Some(offsets.first_offset()) + } + + /// Returns the pair of offsets (into the needle) used to check as a + /// predicate before confirming whether a needle exists at a particular + /// position. + #[inline] + pub(crate) fn pair(&self) -> &Pair { + &self.pair + } + + /// Returns the minimum haystack length that this `Finder` can search. + /// + /// Providing a haystack to this `Finder` shorter than this length is + /// guaranteed to result in a panic. + #[inline(always)] + pub(crate) fn min_haystack_len(&self) -> usize { + self.min_haystack_len + } +} + +/// Accepts a chunk-relative offset and returns a haystack relative offset. +/// +/// This used to be marked `#[cold]` and `#[inline(never)]`, but I couldn't +/// observe a consistent measureable difference between that and just inlining +/// it. So we go with inlining it. +/// +/// # Safety +/// +/// Same at `ptr::offset_from` in addition to `cur >= start`. +#[inline(always)] +unsafe fn matched(start: *const u8, cur: *const u8, chunki: usize) -> usize { + cur.distance(start) + chunki +} + +// If you're looking for tests, those are run for each instantiation of the +// above code. So for example, see arch::x86_64::sse2::packedpair. diff --git a/third_party/crates/memchr-2.8.3/src/arch/mod.rs b/third_party/crates/memchr-2.8.3/src/arch/mod.rs new file mode 100644 index 0000000..10332b6 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/mod.rs @@ -0,0 +1,16 @@ +/*! +A module with low-level architecture dependent routines. + +These routines are useful as primitives for tasks not covered by the higher +level crate API. +*/ + +pub mod all; +pub(crate) mod generic; + +#[cfg(target_arch = "aarch64")] +pub mod aarch64; +#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))] +pub mod wasm32; +#[cfg(target_arch = "x86_64")] +pub mod x86_64; diff --git a/third_party/crates/memchr-2.8.3/src/arch/wasm32/memchr.rs b/third_party/crates/memchr-2.8.3/src/arch/wasm32/memchr.rs new file mode 100644 index 0000000..55c1c1b --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/wasm32/memchr.rs @@ -0,0 +1,124 @@ +/*! +Wrapper routines for `memchr` and friends. + +These routines choose the best implementation at compile time. (This is +different from `x86_64` because it is expected that `simd128` is almost always +available for `wasm32` targets.) +*/ + +macro_rules! defraw { + ($ty:ident, $find:ident, $start:ident, $end:ident, $($needles:ident),+) => {{ + use crate::arch::wasm32::simd128::memchr::$ty; + + debug!("chose simd128 for {}", stringify!($ty)); + debug_assert!($ty::is_available()); + // SAFETY: We know that wasm memchr is always available whenever + // code is compiled for `wasm32` with the `simd128` target feature + // enabled. + $ty::new_unchecked($($needles),+).$find($start, $end) + }} +} + +/// memchr, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `One::find_raw`. +#[inline(always)] +pub(crate) unsafe fn memchr_raw( + n1: u8, + start: *const u8, + end: *const u8, +) -> Option<*const u8> { + defraw!(One, find_raw, start, end, n1) +} + +/// memrchr, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `One::rfind_raw`. +#[inline(always)] +pub(crate) unsafe fn memrchr_raw( + n1: u8, + start: *const u8, + end: *const u8, +) -> Option<*const u8> { + defraw!(One, rfind_raw, start, end, n1) +} + +/// memchr2, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `Two::find_raw`. +#[inline(always)] +pub(crate) unsafe fn memchr2_raw( + n1: u8, + n2: u8, + start: *const u8, + end: *const u8, +) -> Option<*const u8> { + defraw!(Two, find_raw, start, end, n1, n2) +} + +/// memrchr2, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `Two::rfind_raw`. +#[inline(always)] +pub(crate) unsafe fn memrchr2_raw( + n1: u8, + n2: u8, + start: *const u8, + end: *const u8, +) -> Option<*const u8> { + defraw!(Two, rfind_raw, start, end, n1, n2) +} + +/// memchr3, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `Three::find_raw`. +#[inline(always)] +pub(crate) unsafe fn memchr3_raw( + n1: u8, + n2: u8, + n3: u8, + start: *const u8, + end: *const u8, +) -> Option<*const u8> { + defraw!(Three, find_raw, start, end, n1, n2, n3) +} + +/// memrchr3, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `Three::rfind_raw`. +#[inline(always)] +pub(crate) unsafe fn memrchr3_raw( + n1: u8, + n2: u8, + n3: u8, + start: *const u8, + end: *const u8, +) -> Option<*const u8> { + defraw!(Three, rfind_raw, start, end, n1, n2, n3) +} + +/// Count all matching bytes, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `One::count_raw`. +#[inline(always)] +pub(crate) unsafe fn count_raw( + n1: u8, + start: *const u8, + end: *const u8, +) -> usize { + defraw!(One, count_raw, start, end, n1) +} diff --git a/third_party/crates/memchr-2.8.3/src/arch/wasm32/mod.rs b/third_party/crates/memchr-2.8.3/src/arch/wasm32/mod.rs new file mode 100644 index 0000000..209f876 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/wasm32/mod.rs @@ -0,0 +1,7 @@ +/*! +Vector algorithms for the `wasm32` target. +*/ + +pub mod simd128; + +pub(crate) mod memchr; diff --git a/third_party/crates/memchr-2.8.3/src/arch/wasm32/simd128/memchr.rs b/third_party/crates/memchr-2.8.3/src/arch/wasm32/simd128/memchr.rs new file mode 100644 index 0000000..fa314c9 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/wasm32/simd128/memchr.rs @@ -0,0 +1,1020 @@ +/*! +This module defines 128-bit vector implementations of `memchr` and friends. + +The main types in this module are [`One`], [`Two`] and [`Three`]. They are for +searching for one, two or three distinct bytes, respectively, in a haystack. +Each type also has corresponding double ended iterators. These searchers are +typically much faster than scalar routines accomplishing the same task. + +The `One` searcher also provides a [`One::count`] routine for efficiently +counting the number of times a single byte occurs in a haystack. This is +useful, for example, for counting the number of lines in a haystack. This +routine exists because it is usually faster, especially with a high match +count, then using [`One::find`] repeatedly. ([`OneIter`] specializes its +`Iterator::count` implementation to use this routine.) + +Only one, two and three bytes are supported because three bytes is about +the point where one sees diminishing returns. Beyond this point and it's +probably (but not necessarily) better to just use a simple `[bool; 256]` array +or similar. However, it depends mightily on the specific work-load and the +expected match frequency. +*/ + +use core::arch::wasm32::v128; + +use crate::{arch::generic::memchr as generic, ext::Pointer, vector::Vector}; + +/// Finds all occurrences of a single byte in a haystack. +#[derive(Clone, Copy, Debug)] +pub struct One(generic::One); + +impl One { + /// Create a new searcher that finds occurrences of the needle byte given. + /// + /// This particular searcher is specialized to use simd128 vector + /// instructions that typically make it quite fast. + /// + /// If simd128 is unavailable in the current environment, then `None` is + /// returned. + #[inline] + pub fn new(needle: u8) -> Option { + if One::is_available() { + // SAFETY: we check that simd128 is available above. + unsafe { Some(One::new_unchecked(needle)) } + } else { + None + } + } + + /// Create a new finder specific to simd128 vectors and routines without + /// checking that simd128 is available. + /// + /// # Safety + /// + /// Callers must guarantee that it is safe to execute `simd128` + /// instructions in the current environment. + #[target_feature(enable = "simd128")] + #[inline] + pub unsafe fn new_unchecked(needle: u8) -> One { + One(generic::One::new(needle)) + } + + /// Returns true when this implementation is available in the current + /// environment. + /// + /// When this is true, it is guaranteed that [`One::new`] will return + /// a `Some` value. Similarly, when it is false, it is guaranteed that + /// `One::new` will return a `None` value. + /// + /// Note also that for the lifetime of a single program, if this returns + /// true then it will always return true. + #[inline] + pub fn is_available() -> bool { + #[cfg(target_feature = "simd128")] + { + true + } + #[cfg(not(target_feature = "simd128"))] + { + false + } + } + + /// Return the first occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value is `haystack.len() - 1`. + #[inline] + pub fn find(&self, haystack: &[u8]) -> Option { + // SAFETY: `find_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.find_raw(s, e) + }) + } + } + + /// Return the last occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value is `haystack.len() - 1`. + #[inline] + pub fn rfind(&self, haystack: &[u8]) -> Option { + // SAFETY: `rfind_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.rfind_raw(s, e) + }) + } + } + + /// Counts all occurrences of this byte in the given haystack. + #[inline] + pub fn count(&self, haystack: &[u8]) -> usize { + // SAFETY: All of our pointers are derived directly from a borrowed + // slice, which is guaranteed to be valid. + unsafe { + let start = haystack.as_ptr(); + let end = start.add(haystack.len()); + self.count_raw(start, end) + } + } + + /// Like `find`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn find_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + if end.distance(start) < v128::BYTES { + // SAFETY: We require the caller to pass valid start/end pointers. + return generic::fwd_byte_by_byte(start, end, |b| { + b == self.0.needle1() + }); + } + // SAFETY: Building a `One` means it's safe to call 'simd128' routines. + // Also, we've checked that our haystack is big enough to run on the + // vector routine. Pointer validity is caller's responsibility. + self.find_raw_impl(start, end) + } + + /// Like `rfind`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn rfind_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + if end.distance(start) < v128::BYTES { + // SAFETY: We require the caller to pass valid start/end pointers. + return generic::rev_byte_by_byte(start, end, |b| { + b == self.0.needle1() + }); + } + // SAFETY: Building a `One` means it's safe to call 'simd128' routines. + // Also, we've checked that our haystack is big enough to run on the + // vector routine. Pointer validity is caller's responsibility. + self.rfind_raw_impl(start, end) + } + + /// Counts all occurrences of this byte in the given haystack represented + /// by raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn count_raw(&self, start: *const u8, end: *const u8) -> usize { + if start >= end { + return 0; + } + if end.distance(start) < v128::BYTES { + // SAFETY: We require the caller to pass valid start/end pointers. + return generic::count_byte_by_byte(start, end, |b| { + b == self.0.needle1() + }); + } + // SAFETY: Building a `One` means it's safe to call 'simd128' routines. + // Also, we've checked that our haystack is big enough to run on the + // vector routine. Pointer validity is caller's responsibility. + self.count_raw_impl(start, end) + } + + /// Execute a search using simd128 vectors and routines. + /// + /// # Safety + /// + /// Same as [`One::find_raw`], except the distance between `start` and + /// `end` must be at least the size of a simd128 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `One`, which can only be constructed + /// when it is safe to call `simd128` routines.) + #[target_feature(enable = "simd128")] + #[inline] + unsafe fn find_raw_impl( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.0.find_raw(start, end) + } + + /// Execute a search using simd128 vectors and routines. + /// + /// # Safety + /// + /// Same as [`One::rfind_raw`], except the distance between `start` and + /// `end` must be at least the size of a simd128 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `One`, which can only be constructed + /// when it is safe to call `simd128` routines.) + #[target_feature(enable = "simd128")] + #[inline] + unsafe fn rfind_raw_impl( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.0.rfind_raw(start, end) + } + + /// Execute a count using simd128 vectors and routines. + /// + /// # Safety + /// + /// Same as [`One::count_raw`], except the distance between `start` and + /// `end` must be at least the size of a simd128 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `One`, which can only be constructed + /// when it is safe to call `simd128` routines.) + #[target_feature(enable = "simd128")] + #[inline] + unsafe fn count_raw_impl( + &self, + start: *const u8, + end: *const u8, + ) -> usize { + self.0.count_raw(start, end) + } + + /// Returns an iterator over all occurrences of the needle byte in the + /// given haystack. + /// + /// The iterator returned implements `DoubleEndedIterator`. This means it + /// can also be used to find occurrences in reverse order. + #[inline] + pub fn iter<'a, 'h>(&'a self, haystack: &'h [u8]) -> OneIter<'a, 'h> { + OneIter { searcher: self, it: generic::Iter::new(haystack) } + } +} + +/// An iterator over all occurrences of a single byte in a haystack. +/// +/// This iterator implements `DoubleEndedIterator`, which means it can also be +/// used to find occurrences in reverse order. +/// +/// This iterator is created by the [`One::iter`] method. +/// +/// The lifetime parameters are as follows: +/// +/// * `'a` refers to the lifetime of the underlying [`One`] searcher. +/// * `'h` refers to the lifetime of the haystack being searched. +#[derive(Clone, Debug)] +pub struct OneIter<'a, 'h> { + searcher: &'a One, + it: generic::Iter<'h>, +} + +impl<'a, 'h> Iterator for OneIter<'a, 'h> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'find_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next(|s, e| self.searcher.find_raw(s, e)) } + } + + #[inline] + fn count(self) -> usize { + self.it.count(|s, e| { + // SAFETY: We rely on our generic iterator to return valid start + // and end pointers. + unsafe { self.searcher.count_raw(s, e) } + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, 'h> DoubleEndedIterator for OneIter<'a, 'h> { + #[inline] + fn next_back(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'rfind_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next_back(|s, e| self.searcher.rfind_raw(s, e)) } + } +} + +impl<'a, 'h> core::iter::FusedIterator for OneIter<'a, 'h> {} + +/// Finds all occurrences of two bytes in a haystack. +/// +/// That is, this reports matches of one of two possible bytes. For example, +/// searching for `a` or `b` in `afoobar` would report matches at offsets `0`, +/// `4` and `5`. +#[derive(Clone, Copy, Debug)] +pub struct Two(generic::Two); + +impl Two { + /// Create a new searcher that finds occurrences of the needle bytes given. + /// + /// This particular searcher is specialized to use simd128 vector + /// instructions that typically make it quite fast. + /// + /// If simd128 is unavailable in the current environment, then `None` is + /// returned. + #[inline] + pub fn new(needle1: u8, needle2: u8) -> Option { + if Two::is_available() { + // SAFETY: we check that simd128 is available above. + unsafe { Some(Two::new_unchecked(needle1, needle2)) } + } else { + None + } + } + + /// Create a new finder specific to simd128 vectors and routines without + /// checking that simd128 is available. + /// + /// # Safety + /// + /// Callers must guarantee that it is safe to execute `simd128` + /// instructions in the current environment. + #[target_feature(enable = "simd128")] + #[inline] + pub unsafe fn new_unchecked(needle1: u8, needle2: u8) -> Two { + Two(generic::Two::new(needle1, needle2)) + } + + /// Returns true when this implementation is available in the current + /// environment. + /// + /// When this is true, it is guaranteed that [`Two::new`] will return + /// a `Some` value. Similarly, when it is false, it is guaranteed that + /// `Two::new` will return a `None` value. + /// + /// Note also that for the lifetime of a single program, if this returns + /// true then it will always return true. + #[inline] + pub fn is_available() -> bool { + #[cfg(target_feature = "simd128")] + { + true + } + #[cfg(not(target_feature = "simd128"))] + { + false + } + } + + /// Return the first occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value is `haystack.len() - 1`. + #[inline] + pub fn find(&self, haystack: &[u8]) -> Option { + // SAFETY: `find_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.find_raw(s, e) + }) + } + } + + /// Return the last occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value is `haystack.len() - 1`. + #[inline] + pub fn rfind(&self, haystack: &[u8]) -> Option { + // SAFETY: `rfind_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.rfind_raw(s, e) + }) + } + } + + /// Like `find`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn find_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + if end.distance(start) < v128::BYTES { + // SAFETY: We require the caller to pass valid start/end pointers. + return generic::fwd_byte_by_byte(start, end, |b| { + b == self.0.needle1() || b == self.0.needle2() + }); + } + // SAFETY: Building a `Two` means it's safe to call 'simd128' routines. + // Also, we've checked that our haystack is big enough to run on the + // vector routine. Pointer validity is caller's responsibility. + self.find_raw_impl(start, end) + } + + /// Like `rfind`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn rfind_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + if end.distance(start) < v128::BYTES { + // SAFETY: We require the caller to pass valid start/end pointers. + return generic::rev_byte_by_byte(start, end, |b| { + b == self.0.needle1() || b == self.0.needle2() + }); + } + // SAFETY: Building a `Two` means it's safe to call 'simd128' routines. + // Also, we've checked that our haystack is big enough to run on the + // vector routine. Pointer validity is caller's responsibility. + self.rfind_raw_impl(start, end) + } + + /// Execute a search using simd128 vectors and routines. + /// + /// # Safety + /// + /// Same as [`Two::find_raw`], except the distance between `start` and + /// `end` must be at least the size of a simd128 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Two`, which can only be constructed + /// when it is safe to call `simd128` routines.) + #[target_feature(enable = "simd128")] + #[inline] + unsafe fn find_raw_impl( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.0.find_raw(start, end) + } + + /// Execute a search using simd128 vectors and routines. + /// + /// # Safety + /// + /// Same as [`Two::rfind_raw`], except the distance between `start` and + /// `end` must be at least the size of a simd128 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Two`, which can only be constructed + /// when it is safe to call `simd128` routines.) + #[target_feature(enable = "simd128")] + #[inline] + unsafe fn rfind_raw_impl( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.0.rfind_raw(start, end) + } + + /// Returns an iterator over all occurrences of the needle bytes in the + /// given haystack. + /// + /// The iterator returned implements `DoubleEndedIterator`. This means it + /// can also be used to find occurrences in reverse order. + #[inline] + pub fn iter<'a, 'h>(&'a self, haystack: &'h [u8]) -> TwoIter<'a, 'h> { + TwoIter { searcher: self, it: generic::Iter::new(haystack) } + } +} + +/// An iterator over all occurrences of two possible bytes in a haystack. +/// +/// This iterator implements `DoubleEndedIterator`, which means it can also be +/// used to find occurrences in reverse order. +/// +/// This iterator is created by the [`Two::iter`] method. +/// +/// The lifetime parameters are as follows: +/// +/// * `'a` refers to the lifetime of the underlying [`Two`] searcher. +/// * `'h` refers to the lifetime of the haystack being searched. +#[derive(Clone, Debug)] +pub struct TwoIter<'a, 'h> { + searcher: &'a Two, + it: generic::Iter<'h>, +} + +impl<'a, 'h> Iterator for TwoIter<'a, 'h> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'find_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next(|s, e| self.searcher.find_raw(s, e)) } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, 'h> DoubleEndedIterator for TwoIter<'a, 'h> { + #[inline] + fn next_back(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'rfind_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next_back(|s, e| self.searcher.rfind_raw(s, e)) } + } +} + +impl<'a, 'h> core::iter::FusedIterator for TwoIter<'a, 'h> {} + +/// Finds all occurrences of three bytes in a haystack. +/// +/// That is, this reports matches of one of three possible bytes. For example, +/// searching for `a`, `b` or `o` in `afoobar` would report matches at offsets +/// `0`, `2`, `3`, `4` and `5`. +#[derive(Clone, Copy, Debug)] +pub struct Three(generic::Three); + +impl Three { + /// Create a new searcher that finds occurrences of the needle bytes given. + /// + /// This particular searcher is specialized to use simd128 vector + /// instructions that typically make it quite fast. + /// + /// If simd128 is unavailable in the current environment, then `None` is + /// returned. + #[inline] + pub fn new(needle1: u8, needle2: u8, needle3: u8) -> Option { + if Three::is_available() { + // SAFETY: we check that simd128 is available above. + unsafe { Some(Three::new_unchecked(needle1, needle2, needle3)) } + } else { + None + } + } + + /// Create a new finder specific to simd128 vectors and routines without + /// checking that simd128 is available. + /// + /// # Safety + /// + /// Callers must guarantee that it is safe to execute `simd128` + /// instructions in the current environment. + #[target_feature(enable = "simd128")] + #[inline] + pub unsafe fn new_unchecked( + needle1: u8, + needle2: u8, + needle3: u8, + ) -> Three { + Three(generic::Three::new(needle1, needle2, needle3)) + } + + /// Returns true when this implementation is available in the current + /// environment. + /// + /// When this is true, it is guaranteed that [`Three::new`] will return + /// a `Some` value. Similarly, when it is false, it is guaranteed that + /// `Three::new` will return a `None` value. + /// + /// Note also that for the lifetime of a single program, if this returns + /// true then it will always return true. + #[inline] + pub fn is_available() -> bool { + #[cfg(target_feature = "simd128")] + { + true + } + #[cfg(not(target_feature = "simd128"))] + { + false + } + } + + /// Return the first occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value is `haystack.len() - 1`. + #[inline] + pub fn find(&self, haystack: &[u8]) -> Option { + // SAFETY: `find_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.find_raw(s, e) + }) + } + } + + /// Return the last occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value is `haystack.len() - 1`. + #[inline] + pub fn rfind(&self, haystack: &[u8]) -> Option { + // SAFETY: `rfind_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.rfind_raw(s, e) + }) + } + } + + /// Like `find`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn find_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + if end.distance(start) < v128::BYTES { + // SAFETY: We require the caller to pass valid start/end pointers. + return generic::fwd_byte_by_byte(start, end, |b| { + b == self.0.needle1() + || b == self.0.needle2() + || b == self.0.needle3() + }); + } + // SAFETY: Building a `Three` means it's safe to call 'simd128' + // routines. Also, we've checked that our haystack is big enough to run + // on the vector routine. Pointer validity is caller's responsibility. + self.find_raw_impl(start, end) + } + + /// Like `rfind`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn rfind_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + if end.distance(start) < v128::BYTES { + // SAFETY: We require the caller to pass valid start/end pointers. + return generic::rev_byte_by_byte(start, end, |b| { + b == self.0.needle1() + || b == self.0.needle2() + || b == self.0.needle3() + }); + } + // SAFETY: Building a `Three` means it's safe to call 'simd128' + // routines. Also, we've checked that our haystack is big enough to run + // on the vector routine. Pointer validity is caller's responsibility. + self.rfind_raw_impl(start, end) + } + + /// Execute a search using simd128 vectors and routines. + /// + /// # Safety + /// + /// Same as [`Three::find_raw`], except the distance between `start` and + /// `end` must be at least the size of a simd128 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Three`, which can only be constructed + /// when it is safe to call `simd128` routines.) + #[target_feature(enable = "simd128")] + #[inline] + unsafe fn find_raw_impl( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.0.find_raw(start, end) + } + + /// Execute a search using simd128 vectors and routines. + /// + /// # Safety + /// + /// Same as [`Three::rfind_raw`], except the distance between `start` and + /// `end` must be at least the size of a simd128 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Three`, which can only be constructed + /// when it is safe to call `simd128` routines.) + #[target_feature(enable = "simd128")] + #[inline] + unsafe fn rfind_raw_impl( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.0.rfind_raw(start, end) + } + + /// Returns an iterator over all occurrences of the needle byte in the + /// given haystack. + /// + /// The iterator returned implements `DoubleEndedIterator`. This means it + /// can also be used to find occurrences in reverse order. + #[inline] + pub fn iter<'a, 'h>(&'a self, haystack: &'h [u8]) -> ThreeIter<'a, 'h> { + ThreeIter { searcher: self, it: generic::Iter::new(haystack) } + } +} + +/// An iterator over all occurrences of three possible bytes in a haystack. +/// +/// This iterator implements `DoubleEndedIterator`, which means it can also be +/// used to find occurrences in reverse order. +/// +/// This iterator is created by the [`Three::iter`] method. +/// +/// The lifetime parameters are as follows: +/// +/// * `'a` refers to the lifetime of the underlying [`Three`] searcher. +/// * `'h` refers to the lifetime of the haystack being searched. +#[derive(Clone, Debug)] +pub struct ThreeIter<'a, 'h> { + searcher: &'a Three, + it: generic::Iter<'h>, +} + +impl<'a, 'h> Iterator for ThreeIter<'a, 'h> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'find_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next(|s, e| self.searcher.find_raw(s, e)) } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, 'h> DoubleEndedIterator for ThreeIter<'a, 'h> { + #[inline] + fn next_back(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'rfind_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next_back(|s, e| self.searcher.rfind_raw(s, e)) } + } +} + +impl<'a, 'h> core::iter::FusedIterator for ThreeIter<'a, 'h> {} + +#[cfg(test)] +mod tests { + use super::*; + + define_memchr_quickcheck!(super); + + #[test] + fn forward_one() { + crate::tests::memchr::Runner::new(1).forward_iter( + |haystack, needles| { + Some(One::new(needles[0])?.iter(haystack).collect()) + }, + ) + } + + #[test] + fn reverse_one() { + crate::tests::memchr::Runner::new(1).reverse_iter( + |haystack, needles| { + Some(One::new(needles[0])?.iter(haystack).rev().collect()) + }, + ) + } + + #[test] + fn count_one() { + crate::tests::memchr::Runner::new(1).count_iter(|haystack, needles| { + Some(One::new(needles[0])?.iter(haystack).count()) + }) + } + + #[test] + fn forward_two() { + crate::tests::memchr::Runner::new(2).forward_iter( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + Some(Two::new(n1, n2)?.iter(haystack).collect()) + }, + ) + } + + #[test] + fn reverse_two() { + crate::tests::memchr::Runner::new(2).reverse_iter( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + Some(Two::new(n1, n2)?.iter(haystack).rev().collect()) + }, + ) + } + + #[test] + fn forward_three() { + crate::tests::memchr::Runner::new(3).forward_iter( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + let n3 = needles.get(2).copied()?; + Some(Three::new(n1, n2, n3)?.iter(haystack).collect()) + }, + ) + } + + #[test] + fn reverse_three() { + crate::tests::memchr::Runner::new(3).reverse_iter( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + let n3 = needles.get(2).copied()?; + Some(Three::new(n1, n2, n3)?.iter(haystack).rev().collect()) + }, + ) + } +} diff --git a/third_party/crates/memchr-2.8.3/src/arch/wasm32/simd128/mod.rs b/third_party/crates/memchr-2.8.3/src/arch/wasm32/simd128/mod.rs new file mode 100644 index 0000000..b55d1f0 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/wasm32/simd128/mod.rs @@ -0,0 +1,6 @@ +/*! +Algorithms for the `wasm32` target using 128-bit vectors via simd128. +*/ + +pub mod memchr; +pub mod packedpair; diff --git a/third_party/crates/memchr-2.8.3/src/arch/wasm32/simd128/packedpair.rs b/third_party/crates/memchr-2.8.3/src/arch/wasm32/simd128/packedpair.rs new file mode 100644 index 0000000..e8cf745 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/wasm32/simd128/packedpair.rs @@ -0,0 +1,228 @@ +/*! +A 128-bit vector implementation of the "packed pair" SIMD algorithm. + +The "packed pair" algorithm is based on the [generic SIMD] algorithm. The main +difference is that it (by default) uses a background distribution of byte +frequencies to heuristically select the pair of bytes to search for. + +[generic SIMD]: http://0x80.pl/articles/simd-strfind.html#first-and-last +*/ + +use core::arch::wasm32::v128; + +use crate::arch::{all::packedpair::Pair, generic::packedpair}; + +/// A "packed pair" finder that uses 128-bit vector operations. +/// +/// This finder picks two bytes that it believes have high predictive power +/// for indicating an overall match of a needle. Depending on whether +/// `Finder::find` or `Finder::find_prefilter` is used, it reports offsets +/// where the needle matches or could match. In the prefilter case, candidates +/// are reported whenever the [`Pair`] of bytes given matches. +#[derive(Clone, Copy, Debug)] +pub struct Finder(packedpair::Finder); + +impl Finder { + /// Create a new pair searcher. The searcher returned can either report + /// exact matches of `needle` or act as a prefilter and report candidate + /// positions of `needle`. + /// + /// If simd128 is unavailable in the current environment or if a [`Pair`] + /// could not be constructed from the needle given, then `None` is + /// returned. + #[inline] + pub fn new(needle: &[u8]) -> Option { + Finder::with_pair(needle, Pair::new(needle)?) + } + + /// Create a new "packed pair" finder using the pair of bytes given. + /// + /// This constructor permits callers to control precisely which pair of + /// bytes is used as a predicate. + /// + /// If simd128 is unavailable in the current environment, then `None` is + /// returned. + #[inline] + pub fn with_pair(needle: &[u8], pair: Pair) -> Option { + if Finder::is_available() { + // SAFETY: we check that simd128 is available above. We are also + // guaranteed to have needle.len() > 1 because we have a valid + // Pair. + unsafe { Some(Finder::with_pair_impl(needle, pair)) } + } else { + None + } + } + + /// Create a new `Finder` specific to simd128 vectors and routines. + /// + /// # Safety + /// + /// Same as the safety for `packedpair::Finder::new`, and callers must also + /// ensure that simd128 is available. + #[target_feature(enable = "simd128")] + #[inline] + unsafe fn with_pair_impl(needle: &[u8], pair: Pair) -> Finder { + let finder = packedpair::Finder::::new(needle, pair); + Finder(finder) + } + + /// Returns true when this implementation is available in the current + /// environment. + /// + /// When this is true, it is guaranteed that [`Finder::with_pair`] will + /// return a `Some` value. Similarly, when it is false, it is guaranteed + /// that `Finder::with_pair` will return a `None` value. Notice that this + /// does not guarantee that [`Finder::new`] will return a `Finder`. Namely, + /// even when `Finder::is_available` is true, it is not guaranteed that a + /// valid [`Pair`] can be found from the needle given. + /// + /// Note also that for the lifetime of a single program, if this returns + /// true then it will always return true. + #[inline] + pub fn is_available() -> bool { + // We used to gate on `cfg(target_feature = "simd128")` here, but + // we've since required the feature to be enabled at compile time to + // even include this module at all. Therefore, it is always enabled + // in this context. See the linked issue for why this was changed. + // + // Ref: https://github.com/BurntSushi/memchr/issues/144 + true + } + + /// Execute a search using wasm32 v128 vectors and routines. + /// + /// # Panics + /// + /// When `haystack.len()` is less than [`Finder::min_haystack_len`]. + #[inline] + pub fn find(&self, haystack: &[u8], needle: &[u8]) -> Option { + self.find_impl(haystack, needle) + } + + /// Execute a search using wasm32 v128 vectors and routines. + /// + /// # Panics + /// + /// When `haystack.len()` is less than [`Finder::min_haystack_len`]. + #[inline] + pub fn find_prefilter(&self, haystack: &[u8]) -> Option { + self.find_prefilter_impl(haystack) + } + + /// Execute a search using wasm32 v128 vectors and routines. + /// + /// # Panics + /// + /// When `haystack.len()` is less than [`Finder::min_haystack_len`]. + /// + /// # Safety + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Finder`, which can only be constructed + /// when it is safe to call `simd128` routines.) + #[target_feature(enable = "simd128")] + #[inline] + fn find_impl(&self, haystack: &[u8], needle: &[u8]) -> Option { + // SAFETY: The target feature safety obligation is automatically + // fulfilled by virtue of being a method on `Finder`, which can only be + // constructed when it is safe to call `simd128` routines. + unsafe { self.0.find(haystack, needle) } + } + + /// Execute a prefilter search using wasm32 v128 vectors and routines. + /// + /// # Panics + /// + /// When `haystack.len()` is less than [`Finder::min_haystack_len`]. + /// + /// # Safety + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Finder`, which can only be constructed + /// when it is safe to call `simd128` routines.) + #[target_feature(enable = "simd128")] + #[inline] + fn find_prefilter_impl(&self, haystack: &[u8]) -> Option { + // SAFETY: The target feature safety obligation is automatically + // fulfilled by virtue of being a method on `Finder`, which can only be + // constructed when it is safe to call `simd128` routines. + unsafe { self.0.find_prefilter(haystack) } + } + + /// Returns the pair of offsets (into the needle) used to check as a + /// predicate before confirming whether a needle exists at a particular + /// position. + #[inline] + pub fn pair(&self) -> &Pair { + self.0.pair() + } + + /// Returns the minimum haystack length that this `Finder` can search. + /// + /// Using a haystack with length smaller than this in a search will result + /// in a panic. The reason for this restriction is that this finder is + /// meant to be a low-level component that is part of a larger substring + /// strategy. In that sense, it avoids trying to handle all cases and + /// instead only handles the cases that it can handle very well. + #[inline] + pub fn min_haystack_len(&self) -> usize { + self.0.min_haystack_len() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn find(haystack: &[u8], needle: &[u8]) -> Option> { + let f = Finder::new(needle)?; + if haystack.len() < f.min_haystack_len() { + return None; + } + Some(f.find(haystack, needle)) + } + + define_substring_forward_quickcheck!(find); + + #[test] + fn forward_substring() { + crate::tests::substring::Runner::new().fwd(find).run() + } + + #[test] + fn forward_packedpair() { + fn find( + haystack: &[u8], + needle: &[u8], + index1: u8, + index2: u8, + ) -> Option> { + let pair = Pair::with_indices(needle, index1, index2)?; + let f = Finder::with_pair(needle, pair)?; + if haystack.len() < f.min_haystack_len() { + return None; + } + Some(f.find(haystack, needle)) + } + crate::tests::packedpair::Runner::new().fwd(find).run() + } + + #[test] + fn forward_packedpair_prefilter() { + fn find( + haystack: &[u8], + needle: &[u8], + index1: u8, + index2: u8, + ) -> Option> { + let pair = Pair::with_indices(needle, index1, index2)?; + let f = Finder::with_pair(needle, pair)?; + if haystack.len() < f.min_haystack_len() { + return None; + } + Some(f.find_prefilter(haystack)) + } + crate::tests::packedpair::Runner::new().fwd(find).run() + } +} diff --git a/third_party/crates/memchr-2.8.3/src/arch/x86_64/avx2/memchr.rs b/third_party/crates/memchr-2.8.3/src/arch/x86_64/avx2/memchr.rs new file mode 100644 index 0000000..59f8c7f --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/x86_64/avx2/memchr.rs @@ -0,0 +1,1352 @@ +/*! +This module defines 256-bit vector implementations of `memchr` and friends. + +The main types in this module are [`One`], [`Two`] and [`Three`]. They are for +searching for one, two or three distinct bytes, respectively, in a haystack. +Each type also has corresponding double ended iterators. These searchers are +typically much faster than scalar routines accomplishing the same task. + +The `One` searcher also provides a [`One::count`] routine for efficiently +counting the number of times a single byte occurs in a haystack. This is +useful, for example, for counting the number of lines in a haystack. This +routine exists because it is usually faster, especially with a high match +count, then using [`One::find`] repeatedly. ([`OneIter`] specializes its +`Iterator::count` implementation to use this routine.) + +Only one, two and three bytes are supported because three bytes is about +the point where one sees diminishing returns. Beyond this point and it's +probably (but not necessarily) better to just use a simple `[bool; 256]` array +or similar. However, it depends mightily on the specific work-load and the +expected match frequency. +*/ + +use core::arch::x86_64::{__m128i, __m256i}; + +use crate::{arch::generic::memchr as generic, ext::Pointer, vector::Vector}; + +/// Finds all occurrences of a single byte in a haystack. +#[derive(Clone, Copy, Debug)] +pub struct One { + /// Used for haystacks less than 32 bytes. + sse2: generic::One<__m128i>, + /// Used for haystacks bigger than 32 bytes. + avx2: generic::One<__m256i>, +} + +impl One { + /// Create a new searcher that finds occurrences of the needle byte given. + /// + /// This particular searcher is specialized to use AVX2 vector instructions + /// that typically make it quite fast. (SSE2 is used for haystacks that + /// are too short to accommodate an AVX2 vector.) + /// + /// If either SSE2 or AVX2 is unavailable in the current environment, then + /// `None` is returned. + #[inline] + pub fn new(needle: u8) -> Option { + if One::is_available() { + // SAFETY: we check that sse2 and avx2 are available above. + unsafe { Some(One::new_unchecked(needle)) } + } else { + None + } + } + + /// Create a new finder specific to AVX2 vectors and routines without + /// checking that either SSE2 or AVX2 is available. + /// + /// # Safety + /// + /// Callers must guarantee that it is safe to execute both `sse2` and + /// `avx2` instructions in the current environment. + /// + /// Note that it is a common misconception that if one compiles for an + /// `x86_64` target, then they therefore automatically have access to SSE2 + /// instructions. While this is almost always the case, it isn't true in + /// 100% of cases. + #[target_feature(enable = "sse2", enable = "avx2")] + #[inline] + pub unsafe fn new_unchecked(needle: u8) -> One { + One { + sse2: generic::One::new(needle), + avx2: generic::One::new(needle), + } + } + + /// Returns true when this implementation is available in the current + /// environment. + /// + /// When this is true, it is guaranteed that [`One::new`] will return + /// a `Some` value. Similarly, when it is false, it is guaranteed that + /// `One::new` will return a `None` value. + /// + /// Note also that for the lifetime of a single program, if this returns + /// true then it will always return true. + #[inline] + pub fn is_available() -> bool { + #[cfg(not(target_feature = "sse2"))] + { + false + } + #[cfg(target_feature = "sse2")] + { + #[cfg(target_feature = "avx2")] + { + true + } + #[cfg(not(target_feature = "avx2"))] + { + #[cfg(feature = "std")] + { + std::is_x86_feature_detected!("avx2") + } + #[cfg(not(feature = "std"))] + { + false + } + } + } + } + + /// Return the first occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value is `haystack.len() - 1`. + #[inline] + pub fn find(&self, haystack: &[u8]) -> Option { + // SAFETY: `find_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.find_raw(s, e) + }) + } + } + + /// Return the last occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value is `haystack.len() - 1`. + #[inline] + pub fn rfind(&self, haystack: &[u8]) -> Option { + // SAFETY: `find_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.rfind_raw(s, e) + }) + } + } + + /// Counts all occurrences of this byte in the given haystack. + #[inline] + pub fn count(&self, haystack: &[u8]) -> usize { + // SAFETY: All of our pointers are derived directly from a borrowed + // slice, which is guaranteed to be valid. + unsafe { + let start = haystack.as_ptr(); + let end = start.add(haystack.len()); + self.count_raw(start, end) + } + } + + /// Like `find`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn find_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + let len = end.distance(start); + if len < __m256i::BYTES { + return if len < __m128i::BYTES { + // SAFETY: We require the caller to pass valid start/end + // pointers. + generic::fwd_byte_by_byte(start, end, |b| { + b == self.sse2.needle1() + }) + } else { + // SAFETY: We require the caller to pass valid start/end + // pointers. + self.find_raw_sse2(start, end) + }; + } + // SAFETY: Building a `One` means it's safe to call both 'sse2' and + // 'avx2' routines. Also, we've checked that our haystack is big + // enough to run on the vector routine. Pointer validity is caller's + // responsibility. + // + // Note that we could call `self.avx2.find_raw` directly here. But that + // means we'd have to annotate this routine with `target_feature`. + // Which is fine, because this routine is `unsafe` anyway and the + // `target_feature` obligation is met by virtue of building a `One`. + // The real problem is that a routine with a `target_feature` + // annotation generally can't be inlined into caller code unless + // the caller code has the same target feature annotations. Namely, + // the common case (at time of writing) is for calling code to not + // have the `avx2` target feature enabled *at compile time*. Without + // `target_feature` on this routine, it can be inlined which will + // handle some of the short-haystack cases above without touching the + // architecture specific code. + self.find_raw_avx2(start, end) + } + + /// Like `rfind`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn rfind_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + let len = end.distance(start); + if len < __m256i::BYTES { + return if len < __m128i::BYTES { + // SAFETY: We require the caller to pass valid start/end + // pointers. + generic::rev_byte_by_byte(start, end, |b| { + b == self.sse2.needle1() + }) + } else { + // SAFETY: We require the caller to pass valid start/end + // pointers. + self.rfind_raw_sse2(start, end) + }; + } + // SAFETY: Building a `One` means it's safe to call both 'sse2' and + // 'avx2' routines. Also, we've checked that our haystack is big + // enough to run on the vector routine. Pointer validity is caller's + // responsibility. + // + // See note in forward routine above for why we don't just call + // `self.avx2.rfind_raw` directly here. + self.rfind_raw_avx2(start, end) + } + + /// Counts all occurrences of this byte in the given haystack represented + /// by raw pointers. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `0` will always be returned. + #[inline] + pub unsafe fn count_raw(&self, start: *const u8, end: *const u8) -> usize { + if start >= end { + return 0; + } + let len = end.distance(start); + if len < __m256i::BYTES { + return if len < __m128i::BYTES { + // SAFETY: We require the caller to pass valid start/end + // pointers. + generic::count_byte_by_byte(start, end, |b| { + b == self.sse2.needle1() + }) + } else { + // SAFETY: We require the caller to pass valid start/end + // pointers. + self.count_raw_sse2(start, end) + }; + } + // SAFETY: Building a `One` means it's safe to call both 'sse2' and + // 'avx2' routines. Also, we've checked that our haystack is big + // enough to run on the vector routine. Pointer validity is caller's + // responsibility. + self.count_raw_avx2(start, end) + } + + /// Execute a search using SSE2 vectors and routines. + /// + /// # Safety + /// + /// Same as [`One::find_raw`], except the distance between `start` and + /// `end` must be at least the size of an SSE2 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `One`, which can only be constructed + /// when it is safe to call `sse2`/`avx2` routines.) + #[target_feature(enable = "sse2")] + #[inline] + unsafe fn find_raw_sse2( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.sse2.find_raw(start, end) + } + + /// Execute a search using SSE2 vectors and routines. + /// + /// # Safety + /// + /// Same as [`One::rfind_raw`], except the distance between `start` and + /// `end` must be at least the size of an SSE2 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `One`, which can only be constructed + /// when it is safe to call `sse2`/`avx2` routines.) + #[target_feature(enable = "sse2")] + #[inline] + unsafe fn rfind_raw_sse2( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.sse2.rfind_raw(start, end) + } + + /// Execute a count using SSE2 vectors and routines. + /// + /// # Safety + /// + /// Same as [`One::count_raw`], except the distance between `start` and + /// `end` must be at least the size of an SSE2 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `One`, which can only be constructed + /// when it is safe to call `sse2`/`avx2` routines.) + #[target_feature(enable = "sse2")] + #[inline] + unsafe fn count_raw_sse2( + &self, + start: *const u8, + end: *const u8, + ) -> usize { + self.sse2.count_raw(start, end) + } + + /// Execute a search using AVX2 vectors and routines. + /// + /// # Safety + /// + /// Same as [`One::find_raw`], except the distance between `start` and + /// `end` must be at least the size of an AVX2 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `One`, which can only be constructed + /// when it is safe to call `sse2`/`avx2` routines.) + #[target_feature(enable = "avx2")] + #[inline] + unsafe fn find_raw_avx2( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.avx2.find_raw(start, end) + } + + /// Execute a search using AVX2 vectors and routines. + /// + /// # Safety + /// + /// Same as [`One::rfind_raw`], except the distance between `start` and + /// `end` must be at least the size of an AVX2 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `One`, which can only be constructed + /// when it is safe to call `sse2`/`avx2` routines.) + #[target_feature(enable = "avx2")] + #[inline] + unsafe fn rfind_raw_avx2( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.avx2.rfind_raw(start, end) + } + + /// Execute a count using AVX2 vectors and routines. + /// + /// # Safety + /// + /// Same as [`One::count_raw`], except the distance between `start` and + /// `end` must be at least the size of an AVX2 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `One`, which can only be constructed + /// when it is safe to call `sse2`/`avx2` routines.) + #[target_feature(enable = "avx2")] + #[inline] + unsafe fn count_raw_avx2( + &self, + start: *const u8, + end: *const u8, + ) -> usize { + self.avx2.count_raw(start, end) + } + + /// Returns an iterator over all occurrences of the needle byte in the + /// given haystack. + /// + /// The iterator returned implements `DoubleEndedIterator`. This means it + /// can also be used to find occurrences in reverse order. + #[inline] + pub fn iter<'a, 'h>(&'a self, haystack: &'h [u8]) -> OneIter<'a, 'h> { + OneIter { searcher: self, it: generic::Iter::new(haystack) } + } +} + +/// An iterator over all occurrences of a single byte in a haystack. +/// +/// This iterator implements `DoubleEndedIterator`, which means it can also be +/// used to find occurrences in reverse order. +/// +/// This iterator is created by the [`One::iter`] method. +/// +/// The lifetime parameters are as follows: +/// +/// * `'a` refers to the lifetime of the underlying [`One`] searcher. +/// * `'h` refers to the lifetime of the haystack being searched. +#[derive(Clone, Debug)] +pub struct OneIter<'a, 'h> { + searcher: &'a One, + it: generic::Iter<'h>, +} + +impl<'a, 'h> Iterator for OneIter<'a, 'h> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'find_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next(|s, e| self.searcher.find_raw(s, e)) } + } + + #[inline] + fn count(self) -> usize { + self.it.count(|s, e| { + // SAFETY: We rely on our generic iterator to return valid start + // and end pointers. + unsafe { self.searcher.count_raw(s, e) } + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, 'h> DoubleEndedIterator for OneIter<'a, 'h> { + #[inline] + fn next_back(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'rfind_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next_back(|s, e| self.searcher.rfind_raw(s, e)) } + } +} + +impl<'a, 'h> core::iter::FusedIterator for OneIter<'a, 'h> {} + +/// Finds all occurrences of two bytes in a haystack. +/// +/// That is, this reports matches of one of two possible bytes. For example, +/// searching for `a` or `b` in `afoobar` would report matches at offsets `0`, +/// `4` and `5`. +#[derive(Clone, Copy, Debug)] +pub struct Two { + /// Used for haystacks less than 32 bytes. + sse2: generic::Two<__m128i>, + /// Used for haystacks bigger than 32 bytes. + avx2: generic::Two<__m256i>, +} + +impl Two { + /// Create a new searcher that finds occurrences of the needle bytes given. + /// + /// This particular searcher is specialized to use AVX2 vector instructions + /// that typically make it quite fast. (SSE2 is used for haystacks that + /// are too short to accommodate an AVX2 vector.) + /// + /// If either SSE2 or AVX2 is unavailable in the current environment, then + /// `None` is returned. + #[inline] + pub fn new(needle1: u8, needle2: u8) -> Option { + if Two::is_available() { + // SAFETY: we check that sse2 and avx2 are available above. + unsafe { Some(Two::new_unchecked(needle1, needle2)) } + } else { + None + } + } + + /// Create a new finder specific to AVX2 vectors and routines without + /// checking that either SSE2 or AVX2 is available. + /// + /// # Safety + /// + /// Callers must guarantee that it is safe to execute both `sse2` and + /// `avx2` instructions in the current environment. + /// + /// Note that it is a common misconception that if one compiles for an + /// `x86_64` target, then they therefore automatically have access to SSE2 + /// instructions. While this is almost always the case, it isn't true in + /// 100% of cases. + #[target_feature(enable = "sse2", enable = "avx2")] + #[inline] + pub unsafe fn new_unchecked(needle1: u8, needle2: u8) -> Two { + Two { + sse2: generic::Two::new(needle1, needle2), + avx2: generic::Two::new(needle1, needle2), + } + } + + /// Returns true when this implementation is available in the current + /// environment. + /// + /// When this is true, it is guaranteed that [`Two::new`] will return + /// a `Some` value. Similarly, when it is false, it is guaranteed that + /// `Two::new` will return a `None` value. + /// + /// Note also that for the lifetime of a single program, if this returns + /// true then it will always return true. + #[inline] + pub fn is_available() -> bool { + #[cfg(not(target_feature = "sse2"))] + { + false + } + #[cfg(target_feature = "sse2")] + { + #[cfg(target_feature = "avx2")] + { + true + } + #[cfg(not(target_feature = "avx2"))] + { + #[cfg(feature = "std")] + { + std::is_x86_feature_detected!("avx2") + } + #[cfg(not(feature = "std"))] + { + false + } + } + } + } + + /// Return the first occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value is `haystack.len() - 1`. + #[inline] + pub fn find(&self, haystack: &[u8]) -> Option { + // SAFETY: `find_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.find_raw(s, e) + }) + } + } + + /// Return the last occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value is `haystack.len() - 1`. + #[inline] + pub fn rfind(&self, haystack: &[u8]) -> Option { + // SAFETY: `find_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.rfind_raw(s, e) + }) + } + } + + /// Like `find`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn find_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + let len = end.distance(start); + if len < __m256i::BYTES { + return if len < __m128i::BYTES { + // SAFETY: We require the caller to pass valid start/end + // pointers. + generic::fwd_byte_by_byte(start, end, |b| { + b == self.sse2.needle1() || b == self.sse2.needle2() + }) + } else { + // SAFETY: We require the caller to pass valid start/end + // pointers. + self.find_raw_sse2(start, end) + }; + } + // SAFETY: Building a `Two` means it's safe to call both 'sse2' and + // 'avx2' routines. Also, we've checked that our haystack is big + // enough to run on the vector routine. Pointer validity is caller's + // responsibility. + // + // Note that we could call `self.avx2.find_raw` directly here. But that + // means we'd have to annotate this routine with `target_feature`. + // Which is fine, because this routine is `unsafe` anyway and the + // `target_feature` obligation is met by virtue of building a `Two`. + // The real problem is that a routine with a `target_feature` + // annotation generally can't be inlined into caller code unless + // the caller code has the same target feature annotations. Namely, + // the common case (at time of writing) is for calling code to not + // have the `avx2` target feature enabled *at compile time*. Without + // `target_feature` on this routine, it can be inlined which will + // handle some of the short-haystack cases above without touching the + // architecture specific code. + self.find_raw_avx2(start, end) + } + + /// Like `rfind`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn rfind_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + let len = end.distance(start); + if len < __m256i::BYTES { + return if len < __m128i::BYTES { + // SAFETY: We require the caller to pass valid start/end + // pointers. + generic::rev_byte_by_byte(start, end, |b| { + b == self.sse2.needle1() || b == self.sse2.needle2() + }) + } else { + // SAFETY: We require the caller to pass valid start/end + // pointers. + self.rfind_raw_sse2(start, end) + }; + } + // SAFETY: Building a `Two` means it's safe to call both 'sse2' and + // 'avx2' routines. Also, we've checked that our haystack is big + // enough to run on the vector routine. Pointer validity is caller's + // responsibility. + // + // See note in forward routine above for why we don't just call + // `self.avx2.rfind_raw` directly here. + self.rfind_raw_avx2(start, end) + } + + /// Execute a search using SSE2 vectors and routines. + /// + /// # Safety + /// + /// Same as [`Two::find_raw`], except the distance between `start` and + /// `end` must be at least the size of an SSE2 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Two`, which can only be constructed + /// when it is safe to call `sse2`/`avx2` routines.) + #[target_feature(enable = "sse2")] + #[inline] + unsafe fn find_raw_sse2( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.sse2.find_raw(start, end) + } + + /// Execute a search using SSE2 vectors and routines. + /// + /// # Safety + /// + /// Same as [`Two::rfind_raw`], except the distance between `start` and + /// `end` must be at least the size of an SSE2 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Two`, which can only be constructed + /// when it is safe to call `sse2`/`avx2` routines.) + #[target_feature(enable = "sse2")] + #[inline] + unsafe fn rfind_raw_sse2( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.sse2.rfind_raw(start, end) + } + + /// Execute a search using AVX2 vectors and routines. + /// + /// # Safety + /// + /// Same as [`Two::find_raw`], except the distance between `start` and + /// `end` must be at least the size of an AVX2 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Two`, which can only be constructed + /// when it is safe to call `sse2`/`avx2` routines.) + #[target_feature(enable = "avx2")] + #[inline] + unsafe fn find_raw_avx2( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.avx2.find_raw(start, end) + } + + /// Execute a search using AVX2 vectors and routines. + /// + /// # Safety + /// + /// Same as [`Two::rfind_raw`], except the distance between `start` and + /// `end` must be at least the size of an AVX2 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Two`, which can only be constructed + /// when it is safe to call `sse2`/`avx2` routines.) + #[target_feature(enable = "avx2")] + #[inline] + unsafe fn rfind_raw_avx2( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.avx2.rfind_raw(start, end) + } + + /// Returns an iterator over all occurrences of the needle bytes in the + /// given haystack. + /// + /// The iterator returned implements `DoubleEndedIterator`. This means it + /// can also be used to find occurrences in reverse order. + #[inline] + pub fn iter<'a, 'h>(&'a self, haystack: &'h [u8]) -> TwoIter<'a, 'h> { + TwoIter { searcher: self, it: generic::Iter::new(haystack) } + } +} + +/// An iterator over all occurrences of two possible bytes in a haystack. +/// +/// This iterator implements `DoubleEndedIterator`, which means it can also be +/// used to find occurrences in reverse order. +/// +/// This iterator is created by the [`Two::iter`] method. +/// +/// The lifetime parameters are as follows: +/// +/// * `'a` refers to the lifetime of the underlying [`Two`] searcher. +/// * `'h` refers to the lifetime of the haystack being searched. +#[derive(Clone, Debug)] +pub struct TwoIter<'a, 'h> { + searcher: &'a Two, + it: generic::Iter<'h>, +} + +impl<'a, 'h> Iterator for TwoIter<'a, 'h> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'find_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next(|s, e| self.searcher.find_raw(s, e)) } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, 'h> DoubleEndedIterator for TwoIter<'a, 'h> { + #[inline] + fn next_back(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'rfind_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next_back(|s, e| self.searcher.rfind_raw(s, e)) } + } +} + +impl<'a, 'h> core::iter::FusedIterator for TwoIter<'a, 'h> {} + +/// Finds all occurrences of three bytes in a haystack. +/// +/// That is, this reports matches of one of three possible bytes. For example, +/// searching for `a`, `b` or `o` in `afoobar` would report matches at offsets +/// `0`, `2`, `3`, `4` and `5`. +#[derive(Clone, Copy, Debug)] +pub struct Three { + /// Used for haystacks less than 32 bytes. + sse2: generic::Three<__m128i>, + /// Used for haystacks bigger than 32 bytes. + avx2: generic::Three<__m256i>, +} + +impl Three { + /// Create a new searcher that finds occurrences of the needle bytes given. + /// + /// This particular searcher is specialized to use AVX2 vector instructions + /// that typically make it quite fast. (SSE2 is used for haystacks that + /// are too short to accommodate an AVX2 vector.) + /// + /// If either SSE2 or AVX2 is unavailable in the current environment, then + /// `None` is returned. + #[inline] + pub fn new(needle1: u8, needle2: u8, needle3: u8) -> Option { + if Three::is_available() { + // SAFETY: we check that sse2 and avx2 are available above. + unsafe { Some(Three::new_unchecked(needle1, needle2, needle3)) } + } else { + None + } + } + + /// Create a new finder specific to AVX2 vectors and routines without + /// checking that either SSE2 or AVX2 is available. + /// + /// # Safety + /// + /// Callers must guarantee that it is safe to execute both `sse2` and + /// `avx2` instructions in the current environment. + /// + /// Note that it is a common misconception that if one compiles for an + /// `x86_64` target, then they therefore automatically have access to SSE2 + /// instructions. While this is almost always the case, it isn't true in + /// 100% of cases. + #[target_feature(enable = "sse2", enable = "avx2")] + #[inline] + pub unsafe fn new_unchecked( + needle1: u8, + needle2: u8, + needle3: u8, + ) -> Three { + Three { + sse2: generic::Three::new(needle1, needle2, needle3), + avx2: generic::Three::new(needle1, needle2, needle3), + } + } + + /// Returns true when this implementation is available in the current + /// environment. + /// + /// When this is true, it is guaranteed that [`Three::new`] will return + /// a `Some` value. Similarly, when it is false, it is guaranteed that + /// `Three::new` will return a `None` value. + /// + /// Note also that for the lifetime of a single program, if this returns + /// true then it will always return true. + #[inline] + pub fn is_available() -> bool { + #[cfg(not(target_feature = "sse2"))] + { + false + } + #[cfg(target_feature = "sse2")] + { + #[cfg(target_feature = "avx2")] + { + true + } + #[cfg(not(target_feature = "avx2"))] + { + #[cfg(feature = "std")] + { + std::is_x86_feature_detected!("avx2") + } + #[cfg(not(feature = "std"))] + { + false + } + } + } + } + + /// Return the first occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value is `haystack.len() - 1`. + #[inline] + pub fn find(&self, haystack: &[u8]) -> Option { + // SAFETY: `find_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.find_raw(s, e) + }) + } + } + + /// Return the last occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value is `haystack.len() - 1`. + #[inline] + pub fn rfind(&self, haystack: &[u8]) -> Option { + // SAFETY: `find_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.rfind_raw(s, e) + }) + } + } + + /// Like `find`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn find_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + let len = end.distance(start); + if len < __m256i::BYTES { + return if len < __m128i::BYTES { + // SAFETY: We require the caller to pass valid start/end + // pointers. + generic::fwd_byte_by_byte(start, end, |b| { + b == self.sse2.needle1() + || b == self.sse2.needle2() + || b == self.sse2.needle3() + }) + } else { + // SAFETY: We require the caller to pass valid start/end + // pointers. + self.find_raw_sse2(start, end) + }; + } + // SAFETY: Building a `Three` means it's safe to call both 'sse2' and + // 'avx2' routines. Also, we've checked that our haystack is big + // enough to run on the vector routine. Pointer validity is caller's + // responsibility. + // + // Note that we could call `self.avx2.find_raw` directly here. But that + // means we'd have to annotate this routine with `target_feature`. + // Which is fine, because this routine is `unsafe` anyway and the + // `target_feature` obligation is met by virtue of building a `Three`. + // The real problem is that a routine with a `target_feature` + // annotation generally can't be inlined into caller code unless + // the caller code has the same target feature annotations. Namely, + // the common case (at time of writing) is for calling code to not + // have the `avx2` target feature enabled *at compile time*. Without + // `target_feature` on this routine, it can be inlined which will + // handle some of the short-haystack cases above without touching the + // architecture specific code. + self.find_raw_avx2(start, end) + } + + /// Like `rfind`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn rfind_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + let len = end.distance(start); + if len < __m256i::BYTES { + return if len < __m128i::BYTES { + // SAFETY: We require the caller to pass valid start/end + // pointers. + generic::rev_byte_by_byte(start, end, |b| { + b == self.sse2.needle1() + || b == self.sse2.needle2() + || b == self.sse2.needle3() + }) + } else { + // SAFETY: We require the caller to pass valid start/end + // pointers. + self.rfind_raw_sse2(start, end) + }; + } + // SAFETY: Building a `Three` means it's safe to call both 'sse2' and + // 'avx2' routines. Also, we've checked that our haystack is big + // enough to run on the vector routine. Pointer validity is caller's + // responsibility. + // + // See note in forward routine above for why we don't just call + // `self.avx2.rfind_raw` directly here. + self.rfind_raw_avx2(start, end) + } + + /// Execute a search using SSE2 vectors and routines. + /// + /// # Safety + /// + /// Same as [`Three::find_raw`], except the distance between `start` and + /// `end` must be at least the size of an SSE2 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Three`, which can only be constructed + /// when it is safe to call `sse2`/`avx2` routines.) + #[target_feature(enable = "sse2")] + #[inline] + unsafe fn find_raw_sse2( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.sse2.find_raw(start, end) + } + + /// Execute a search using SSE2 vectors and routines. + /// + /// # Safety + /// + /// Same as [`Three::rfind_raw`], except the distance between `start` and + /// `end` must be at least the size of an SSE2 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Three`, which can only be constructed + /// when it is safe to call `sse2`/`avx2` routines.) + #[target_feature(enable = "sse2")] + #[inline] + unsafe fn rfind_raw_sse2( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.sse2.rfind_raw(start, end) + } + + /// Execute a search using AVX2 vectors and routines. + /// + /// # Safety + /// + /// Same as [`Three::find_raw`], except the distance between `start` and + /// `end` must be at least the size of an AVX2 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Three`, which can only be constructed + /// when it is safe to call `sse2`/`avx2` routines.) + #[target_feature(enable = "avx2")] + #[inline] + unsafe fn find_raw_avx2( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.avx2.find_raw(start, end) + } + + /// Execute a search using AVX2 vectors and routines. + /// + /// # Safety + /// + /// Same as [`Three::rfind_raw`], except the distance between `start` and + /// `end` must be at least the size of an AVX2 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Three`, which can only be constructed + /// when it is safe to call `sse2`/`avx2` routines.) + #[target_feature(enable = "avx2")] + #[inline] + unsafe fn rfind_raw_avx2( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.avx2.rfind_raw(start, end) + } + + /// Returns an iterator over all occurrences of the needle bytes in the + /// given haystack. + /// + /// The iterator returned implements `DoubleEndedIterator`. This means it + /// can also be used to find occurrences in reverse order. + #[inline] + pub fn iter<'a, 'h>(&'a self, haystack: &'h [u8]) -> ThreeIter<'a, 'h> { + ThreeIter { searcher: self, it: generic::Iter::new(haystack) } + } +} + +/// An iterator over all occurrences of three possible bytes in a haystack. +/// +/// This iterator implements `DoubleEndedIterator`, which means it can also be +/// used to find occurrences in reverse order. +/// +/// This iterator is created by the [`Three::iter`] method. +/// +/// The lifetime parameters are as follows: +/// +/// * `'a` refers to the lifetime of the underlying [`Three`] searcher. +/// * `'h` refers to the lifetime of the haystack being searched. +#[derive(Clone, Debug)] +pub struct ThreeIter<'a, 'h> { + searcher: &'a Three, + it: generic::Iter<'h>, +} + +impl<'a, 'h> Iterator for ThreeIter<'a, 'h> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'find_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next(|s, e| self.searcher.find_raw(s, e)) } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, 'h> DoubleEndedIterator for ThreeIter<'a, 'h> { + #[inline] + fn next_back(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'rfind_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next_back(|s, e| self.searcher.rfind_raw(s, e)) } + } +} + +impl<'a, 'h> core::iter::FusedIterator for ThreeIter<'a, 'h> {} + +#[cfg(test)] +mod tests { + use super::*; + + define_memchr_quickcheck!(super); + + #[test] + fn forward_one() { + crate::tests::memchr::Runner::new(1).forward_iter( + |haystack, needles| { + Some(One::new(needles[0])?.iter(haystack).collect()) + }, + ) + } + + #[test] + fn reverse_one() { + crate::tests::memchr::Runner::new(1).reverse_iter( + |haystack, needles| { + Some(One::new(needles[0])?.iter(haystack).rev().collect()) + }, + ) + } + + #[test] + fn count_one() { + crate::tests::memchr::Runner::new(1).count_iter(|haystack, needles| { + Some(One::new(needles[0])?.iter(haystack).count()) + }) + } + + #[test] + fn forward_two() { + crate::tests::memchr::Runner::new(2).forward_iter( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + Some(Two::new(n1, n2)?.iter(haystack).collect()) + }, + ) + } + + #[test] + fn reverse_two() { + crate::tests::memchr::Runner::new(2).reverse_iter( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + Some(Two::new(n1, n2)?.iter(haystack).rev().collect()) + }, + ) + } + + #[test] + fn forward_three() { + crate::tests::memchr::Runner::new(3).forward_iter( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + let n3 = needles.get(2).copied()?; + Some(Three::new(n1, n2, n3)?.iter(haystack).collect()) + }, + ) + } + + #[test] + fn reverse_three() { + crate::tests::memchr::Runner::new(3).reverse_iter( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + let n3 = needles.get(2).copied()?; + Some(Three::new(n1, n2, n3)?.iter(haystack).rev().collect()) + }, + ) + } +} diff --git a/third_party/crates/memchr-2.8.3/src/arch/x86_64/avx2/mod.rs b/third_party/crates/memchr-2.8.3/src/arch/x86_64/avx2/mod.rs new file mode 100644 index 0000000..ee4097d --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/x86_64/avx2/mod.rs @@ -0,0 +1,6 @@ +/*! +Algorithms for the `x86_64` target using 256-bit vectors via AVX2. +*/ + +pub mod memchr; +pub mod packedpair; diff --git a/third_party/crates/memchr-2.8.3/src/arch/x86_64/avx2/packedpair.rs b/third_party/crates/memchr-2.8.3/src/arch/x86_64/avx2/packedpair.rs new file mode 100644 index 0000000..efae7b6 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/x86_64/avx2/packedpair.rs @@ -0,0 +1,272 @@ +/*! +A 256-bit vector implementation of the "packed pair" SIMD algorithm. + +The "packed pair" algorithm is based on the [generic SIMD] algorithm. The main +difference is that it (by default) uses a background distribution of byte +frequencies to heuristically select the pair of bytes to search for. + +[generic SIMD]: http://0x80.pl/articles/simd-strfind.html#first-and-last +*/ + +use core::arch::x86_64::{__m128i, __m256i}; + +use crate::arch::{all::packedpair::Pair, generic::packedpair}; + +/// A "packed pair" finder that uses 256-bit vector operations. +/// +/// This finder picks two bytes that it believes have high predictive power +/// for indicating an overall match of a needle. Depending on whether +/// `Finder::find` or `Finder::find_prefilter` is used, it reports offsets +/// where the needle matches or could match. In the prefilter case, candidates +/// are reported whenever the [`Pair`] of bytes given matches. +#[derive(Clone, Copy, Debug)] +pub struct Finder { + sse2: packedpair::Finder<__m128i>, + avx2: packedpair::Finder<__m256i>, +} + +impl Finder { + /// Create a new pair searcher. The searcher returned can either report + /// exact matches of `needle` or act as a prefilter and report candidate + /// positions of `needle`. + /// + /// If AVX2 is unavailable in the current environment or if a [`Pair`] + /// could not be constructed from the needle given, then `None` is + /// returned. + #[inline] + pub fn new(needle: &[u8]) -> Option { + Finder::with_pair(needle, Pair::new(needle)?) + } + + /// Create a new "packed pair" finder using the pair of bytes given. + /// + /// This constructor permits callers to control precisely which pair of + /// bytes is used as a predicate. + /// + /// If AVX2 is unavailable in the current environment, then `None` is + /// returned. + #[inline] + pub fn with_pair(needle: &[u8], pair: Pair) -> Option { + if Finder::is_available() { + // SAFETY: we check that sse2/avx2 is available above. We are also + // guaranteed to have needle.len() > 1 because we have a valid + // Pair. + unsafe { Some(Finder::with_pair_impl(needle, pair)) } + } else { + None + } + } + + /// Create a new `Finder` specific to SSE2 vectors and routines. + /// + /// # Safety + /// + /// Same as the safety for `packedpair::Finder::new`, and callers must also + /// ensure that both SSE2 and AVX2 are available. + #[target_feature(enable = "sse2", enable = "avx2")] + #[inline] + unsafe fn with_pair_impl(needle: &[u8], pair: Pair) -> Finder { + let sse2 = packedpair::Finder::<__m128i>::new(needle, pair); + let avx2 = packedpair::Finder::<__m256i>::new(needle, pair); + Finder { sse2, avx2 } + } + + /// Returns true when this implementation is available in the current + /// environment. + /// + /// When this is true, it is guaranteed that [`Finder::with_pair`] will + /// return a `Some` value. Similarly, when it is false, it is guaranteed + /// that `Finder::with_pair` will return a `None` value. Notice that this + /// does not guarantee that [`Finder::new`] will return a `Finder`. Namely, + /// even when `Finder::is_available` is true, it is not guaranteed that a + /// valid [`Pair`] can be found from the needle given. + /// + /// Note also that for the lifetime of a single program, if this returns + /// true then it will always return true. + #[inline] + pub fn is_available() -> bool { + #[cfg(not(target_feature = "sse2"))] + { + false + } + #[cfg(target_feature = "sse2")] + { + #[cfg(target_feature = "avx2")] + { + true + } + #[cfg(not(target_feature = "avx2"))] + { + #[cfg(feature = "std")] + { + std::is_x86_feature_detected!("avx2") + } + #[cfg(not(feature = "std"))] + { + false + } + } + } + } + + /// Execute a search using AVX2 vectors and routines. + /// + /// # Panics + /// + /// When `haystack.len()` is less than [`Finder::min_haystack_len`]. + #[inline] + pub fn find(&self, haystack: &[u8], needle: &[u8]) -> Option { + // SAFETY: Building a `Finder` means it's safe to call 'sse2' routines. + unsafe { self.find_impl(haystack, needle) } + } + + /// Run this finder on the given haystack as a prefilter. + /// + /// If a candidate match is found, then an offset where the needle *could* + /// begin in the haystack is returned. + /// + /// # Panics + /// + /// When `haystack.len()` is less than [`Finder::min_haystack_len`]. + #[inline] + pub fn find_prefilter(&self, haystack: &[u8]) -> Option { + // SAFETY: Building a `Finder` means it's safe to call 'sse2' routines. + unsafe { self.find_prefilter_impl(haystack) } + } + + /// Execute a search using AVX2 vectors and routines. + /// + /// # Panics + /// + /// When `haystack.len()` is less than [`Finder::min_haystack_len`]. + /// + /// # Safety + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Finder`, which can only be constructed + /// when it is safe to call `sse2` and `avx2` routines.) + #[target_feature(enable = "sse2", enable = "avx2")] + #[inline] + unsafe fn find_impl( + &self, + haystack: &[u8], + needle: &[u8], + ) -> Option { + if haystack.len() < self.avx2.min_haystack_len() { + self.sse2.find(haystack, needle) + } else { + self.avx2.find(haystack, needle) + } + } + + /// Execute a prefilter search using AVX2 vectors and routines. + /// + /// # Panics + /// + /// When `haystack.len()` is less than [`Finder::min_haystack_len`]. + /// + /// # Safety + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Finder`, which can only be constructed + /// when it is safe to call `sse2` and `avx2` routines.) + #[target_feature(enable = "sse2", enable = "avx2")] + #[inline] + unsafe fn find_prefilter_impl(&self, haystack: &[u8]) -> Option { + if haystack.len() < self.avx2.min_haystack_len() { + self.sse2.find_prefilter(haystack) + } else { + self.avx2.find_prefilter(haystack) + } + } + + /// Returns the pair of offsets (into the needle) used to check as a + /// predicate before confirming whether a needle exists at a particular + /// position. + #[inline] + pub fn pair(&self) -> &Pair { + self.avx2.pair() + } + + /// Returns the minimum haystack length that this `Finder` can search. + /// + /// Using a haystack with length smaller than this in a search will result + /// in a panic. The reason for this restriction is that this finder is + /// meant to be a low-level component that is part of a larger substring + /// strategy. In that sense, it avoids trying to handle all cases and + /// instead only handles the cases that it can handle very well. + #[inline] + pub fn min_haystack_len(&self) -> usize { + // The caller doesn't need to care about AVX2's min_haystack_len + // since this implementation will automatically switch to the SSE2 + // implementation if the haystack is too short for AVX2. Therefore, the + // caller only needs to care about SSE2's min_haystack_len. + // + // This does assume that SSE2's min_haystack_len is less than or + // equal to AVX2's min_haystack_len. In practice, this is true and + // there is no way it could be false based on how this Finder is + // implemented. Namely, both SSE2 and AVX2 use the same `Pair`. If + // they used different pairs, then it's possible (although perhaps + // pathological) for SSE2's min_haystack_len to be bigger than AVX2's. + self.sse2.min_haystack_len() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn find(haystack: &[u8], needle: &[u8]) -> Option> { + let f = Finder::new(needle)?; + if haystack.len() < f.min_haystack_len() { + return None; + } + Some(f.find(haystack, needle)) + } + + define_substring_forward_quickcheck!(find); + + #[test] + fn forward_substring() { + crate::tests::substring::Runner::new().fwd(find).run() + } + + #[test] + fn forward_packedpair() { + fn find( + haystack: &[u8], + needle: &[u8], + index1: u8, + index2: u8, + ) -> Option> { + let pair = Pair::with_indices(needle, index1, index2)?; + let f = Finder::with_pair(needle, pair)?; + if haystack.len() < f.min_haystack_len() { + return None; + } + Some(f.find(haystack, needle)) + } + crate::tests::packedpair::Runner::new().fwd(find).run() + } + + #[test] + fn forward_packedpair_prefilter() { + fn find( + haystack: &[u8], + needle: &[u8], + index1: u8, + index2: u8, + ) -> Option> { + if !cfg!(target_feature = "sse2") { + return None; + } + let pair = Pair::with_indices(needle, index1, index2)?; + let f = Finder::with_pair(needle, pair)?; + if haystack.len() < f.min_haystack_len() { + return None; + } + Some(f.find_prefilter(haystack)) + } + crate::tests::packedpair::Runner::new().fwd(find).run() + } +} diff --git a/third_party/crates/memchr-2.8.3/src/arch/x86_64/memchr.rs b/third_party/crates/memchr-2.8.3/src/arch/x86_64/memchr.rs new file mode 100644 index 0000000..e12d0d3 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/x86_64/memchr.rs @@ -0,0 +1,339 @@ +/*! +Wrapper routines for `memchr` and friends. + +These routines efficiently dispatch to the best implementation based on what +the CPU supports. +*/ + +/// Provides a way to run a memchr-like function while amortizing the cost of +/// runtime CPU feature detection. +/// +/// This works by loading a function pointer from an atomic global. Initially, +/// this global is set to a function that does CPU feature detection. For +/// example, if AVX2 is enabled, then the AVX2 implementation is used. +/// Otherwise, at least on x86_64, the SSE2 implementation is used. (And +/// in some niche cases, if SSE2 isn't available, then the architecture +/// independent fallback implementation is used.) +/// +/// After the first call to this function, the atomic global is replaced with +/// the specific AVX2, SSE2 or fallback routine chosen. Subsequent calls then +/// will directly call the chosen routine instead of needing to go through the +/// CPU feature detection branching again. +/// +/// This particular macro is specifically written to provide the implementation +/// of functions with the following signature: +/// +/// ```ignore +/// fn memchr(needle1: u8, start: *const u8, end: *const u8) -> Option; +/// ``` +/// +/// Where you can also have `memchr2` and `memchr3`, but with `needle2` and +/// `needle3`, respectively. The `start` and `end` parameters correspond to the +/// start and end of the haystack, respectively. +/// +/// We use raw pointers here instead of the more obvious `haystack: &[u8]` so +/// that the function is compatible with our lower level iterator logic that +/// operates on raw pointers. We use this macro to implement "raw" memchr +/// routines with the signature above, and then define memchr routines using +/// regular slices on top of them. +/// +/// Note that we use `#[cfg(target_feature = "sse2")]` below even though +/// it shouldn't be strictly necessary because without it, it seems to +/// cause the compiler to blow up. I guess it can't handle a function +/// pointer being created with a sse target feature? Dunno. See the +/// `build-for-x86-64-but-non-sse-target` CI job if you want to experiment with +/// this. +/// +/// # Safety +/// +/// Primarily callers must ensure that `$fnty` is a correct function pointer +/// type and not something else. +/// +/// Callers must also ensure that `$memchrty::$memchrfind` corresponds to a +/// routine that returns a valid function pointer when a match is found. That +/// is, a pointer that is `>= start` and `< end`. +/// +/// Callers must also ensure that the `$hay_start` and `$hay_end` identifiers +/// correspond to valid pointers. +macro_rules! unsafe_ifunc { + ( + $memchrty:ident, + $memchrfind:ident, + $fnty:ty, + $retty:ty, + $hay_start:ident, + $hay_end:ident, + $($needle:ident),+ + ) => {{ + #![allow(unused_unsafe)] + + use core::sync::atomic::{AtomicPtr, Ordering}; + + type Fn = *mut (); + type RealFn = $fnty; + static FN: AtomicPtr<()> = AtomicPtr::new(detect as Fn); + + #[cfg(target_feature = "sse2")] + #[target_feature(enable = "sse2", enable = "avx2")] + unsafe fn find_avx2( + $($needle: u8),+, + $hay_start: *const u8, + $hay_end: *const u8, + ) -> $retty { + use crate::arch::x86_64::avx2::memchr::$memchrty; + $memchrty::new_unchecked($($needle),+) + .$memchrfind($hay_start, $hay_end) + } + + #[cfg(target_feature = "sse2")] + #[target_feature(enable = "sse2")] + unsafe fn find_sse2( + $($needle: u8),+, + $hay_start: *const u8, + $hay_end: *const u8, + ) -> $retty { + use crate::arch::x86_64::sse2::memchr::$memchrty; + $memchrty::new_unchecked($($needle),+) + .$memchrfind($hay_start, $hay_end) + } + + unsafe fn find_fallback( + $($needle: u8),+, + $hay_start: *const u8, + $hay_end: *const u8, + ) -> $retty { + use crate::arch::all::memchr::$memchrty; + $memchrty::new($($needle),+).$memchrfind($hay_start, $hay_end) + } + + unsafe fn detect( + $($needle: u8),+, + $hay_start: *const u8, + $hay_end: *const u8, + ) -> $retty { + let fun = { + #[cfg(not(target_feature = "sse2"))] + { + debug!( + "no sse2 feature available, using fallback for {}", + stringify!($memchrty), + ); + find_fallback as RealFn + } + #[cfg(target_feature = "sse2")] + { + use crate::arch::x86_64::{sse2, avx2}; + if avx2::memchr::$memchrty::is_available() { + debug!("chose AVX2 for {}", stringify!($memchrty)); + find_avx2 as RealFn + } else if sse2::memchr::$memchrty::is_available() { + debug!("chose SSE2 for {}", stringify!($memchrty)); + find_sse2 as RealFn + } else { + debug!("chose fallback for {}", stringify!($memchrty)); + find_fallback as RealFn + } + } + }; + FN.store(fun as Fn, Ordering::Relaxed); + // SAFETY: The only thing we need to uphold here is the + // `#[target_feature]` requirements. Since we check is_available + // above before using the corresponding implementation, we are + // guaranteed to only call code that is supported on the current + // CPU. + fun($($needle),+, $hay_start, $hay_end) + } + + // SAFETY: By virtue of the caller contract, RealFn is a function + // pointer, which is always safe to transmute with a *mut (). Also, + // since we use $memchrty::is_available, it is guaranteed to be safe + // to call $memchrty::$memchrfind. + unsafe { + let fun = FN.load(Ordering::Relaxed); + core::mem::transmute::(fun)( + $($needle),+, + $hay_start, + $hay_end, + ) + } + }}; +} + +// The routines below dispatch to AVX2, SSE2 or a fallback routine based on +// what's available in the current environment. The secret sauce here is that +// we only check for which one to use approximately once, and then "cache" that +// choice into a global function pointer. Subsequent invocations then just call +// the appropriate function directly. + +/// memchr, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `One::find_raw`. +#[inline(always)] +pub(crate) unsafe fn memchr_raw( + n1: u8, + start: *const u8, + end: *const u8, +) -> Option<*const u8> { + // SAFETY: We provide a valid function pointer type. + unsafe_ifunc!( + One, + find_raw, + unsafe fn(u8, *const u8, *const u8) -> Option<*const u8>, + Option<*const u8>, + start, + end, + n1 + ) +} + +/// memrchr, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `One::rfind_raw`. +#[inline(always)] +pub(crate) unsafe fn memrchr_raw( + n1: u8, + start: *const u8, + end: *const u8, +) -> Option<*const u8> { + // SAFETY: We provide a valid function pointer type. + unsafe_ifunc!( + One, + rfind_raw, + unsafe fn(u8, *const u8, *const u8) -> Option<*const u8>, + Option<*const u8>, + start, + end, + n1 + ) +} + +/// memchr2, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `Two::find_raw`. +#[inline(always)] +pub(crate) unsafe fn memchr2_raw( + n1: u8, + n2: u8, + start: *const u8, + end: *const u8, +) -> Option<*const u8> { + // SAFETY: We provide a valid function pointer type. + unsafe_ifunc!( + Two, + find_raw, + unsafe fn(u8, u8, *const u8, *const u8) -> Option<*const u8>, + Option<*const u8>, + start, + end, + n1, + n2 + ) +} + +/// memrchr2, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `Two::rfind_raw`. +#[inline(always)] +pub(crate) unsafe fn memrchr2_raw( + n1: u8, + n2: u8, + start: *const u8, + end: *const u8, +) -> Option<*const u8> { + // SAFETY: We provide a valid function pointer type. + unsafe_ifunc!( + Two, + rfind_raw, + unsafe fn(u8, u8, *const u8, *const u8) -> Option<*const u8>, + Option<*const u8>, + start, + end, + n1, + n2 + ) +} + +/// memchr3, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `Three::find_raw`. +#[inline(always)] +pub(crate) unsafe fn memchr3_raw( + n1: u8, + n2: u8, + n3: u8, + start: *const u8, + end: *const u8, +) -> Option<*const u8> { + // SAFETY: We provide a valid function pointer type. + unsafe_ifunc!( + Three, + find_raw, + unsafe fn(u8, u8, u8, *const u8, *const u8) -> Option<*const u8>, + Option<*const u8>, + start, + end, + n1, + n2, + n3 + ) +} + +/// memrchr3, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `Three::rfind_raw`. +#[inline(always)] +pub(crate) unsafe fn memrchr3_raw( + n1: u8, + n2: u8, + n3: u8, + start: *const u8, + end: *const u8, +) -> Option<*const u8> { + // SAFETY: We provide a valid function pointer type. + unsafe_ifunc!( + Three, + rfind_raw, + unsafe fn(u8, u8, u8, *const u8, *const u8) -> Option<*const u8>, + Option<*const u8>, + start, + end, + n1, + n2, + n3 + ) +} + +/// Count all matching bytes, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `One::count_raw`. +#[inline(always)] +pub(crate) unsafe fn count_raw( + n1: u8, + start: *const u8, + end: *const u8, +) -> usize { + // SAFETY: We provide a valid function pointer type. + unsafe_ifunc!( + One, + count_raw, + unsafe fn(u8, *const u8, *const u8) -> usize, + usize, + start, + end, + n1 + ) +} diff --git a/third_party/crates/memchr-2.8.3/src/arch/x86_64/mod.rs b/third_party/crates/memchr-2.8.3/src/arch/x86_64/mod.rs new file mode 100644 index 0000000..5dad721 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/x86_64/mod.rs @@ -0,0 +1,8 @@ +/*! +Vector algorithms for the `x86_64` target. +*/ + +pub mod avx2; +pub mod sse2; + +pub(crate) mod memchr; diff --git a/third_party/crates/memchr-2.8.3/src/arch/x86_64/sse2/memchr.rs b/third_party/crates/memchr-2.8.3/src/arch/x86_64/sse2/memchr.rs new file mode 100644 index 0000000..79572b8 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/x86_64/sse2/memchr.rs @@ -0,0 +1,1077 @@ +/*! +This module defines 128-bit vector implementations of `memchr` and friends. + +The main types in this module are [`One`], [`Two`] and [`Three`]. They are for +searching for one, two or three distinct bytes, respectively, in a haystack. +Each type also has corresponding double ended iterators. These searchers are +typically much faster than scalar routines accomplishing the same task. + +The `One` searcher also provides a [`One::count`] routine for efficiently +counting the number of times a single byte occurs in a haystack. This is +useful, for example, for counting the number of lines in a haystack. This +routine exists because it is usually faster, especially with a high match +count, than using [`One::find`] repeatedly. ([`OneIter`] specializes its +`Iterator::count` implementation to use this routine.) + +Only one, two and three bytes are supported because three bytes is about +the point where one sees diminishing returns. Beyond this point and it's +probably (but not necessarily) better to just use a simple `[bool; 256]` array +or similar. However, it depends mightily on the specific work-load and the +expected match frequency. +*/ + +use core::arch::x86_64::__m128i; + +use crate::{arch::generic::memchr as generic, ext::Pointer, vector::Vector}; + +/// Finds all occurrences of a single byte in a haystack. +#[derive(Clone, Copy, Debug)] +pub struct One(generic::One<__m128i>); + +impl One { + /// Create a new searcher that finds occurrences of the needle byte given. + /// + /// This particular searcher is specialized to use SSE2 vector instructions + /// that typically make it quite fast. + /// + /// If SSE2 is unavailable in the current environment, then `None` is + /// returned. + #[inline] + pub fn new(needle: u8) -> Option { + if One::is_available() { + // SAFETY: we check that sse2 is available above. + unsafe { Some(One::new_unchecked(needle)) } + } else { + None + } + } + + /// Create a new finder specific to SSE2 vectors and routines without + /// checking that SSE2 is available. + /// + /// # Safety + /// + /// Callers must guarantee that it is safe to execute `sse2` instructions + /// in the current environment. + /// + /// Note that it is a common misconception that if one compiles for an + /// `x86_64` target, then they therefore automatically have access to SSE2 + /// instructions. While this is almost always the case, it isn't true in + /// 100% of cases. + #[target_feature(enable = "sse2")] + #[inline] + pub unsafe fn new_unchecked(needle: u8) -> One { + One(generic::One::new(needle)) + } + + /// Returns true when this implementation is available in the current + /// environment. + /// + /// When this is true, it is guaranteed that [`One::new`] will return + /// a `Some` value. Similarly, when it is false, it is guaranteed that + /// `One::new` will return a `None` value. + /// + /// Note also that for the lifetime of a single program, if this returns + /// true then it will always return true. + #[inline] + pub fn is_available() -> bool { + #[cfg(target_feature = "sse2")] + { + true + } + #[cfg(not(target_feature = "sse2"))] + { + false + } + } + + /// Return the first occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value is `haystack.len() - 1`. + #[inline] + pub fn find(&self, haystack: &[u8]) -> Option { + // SAFETY: `find_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.find_raw(s, e) + }) + } + } + + /// Return the last occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value is `haystack.len() - 1`. + #[inline] + pub fn rfind(&self, haystack: &[u8]) -> Option { + // SAFETY: `rfind_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.rfind_raw(s, e) + }) + } + } + + /// Counts all occurrences of this byte in the given haystack. + #[inline] + pub fn count(&self, haystack: &[u8]) -> usize { + // SAFETY: All of our pointers are derived directly from a borrowed + // slice, which is guaranteed to be valid. + unsafe { + let start = haystack.as_ptr(); + let end = start.add(haystack.len()); + self.count_raw(start, end) + } + } + + /// Like `find`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn find_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + if end.distance(start) < __m128i::BYTES { + // SAFETY: We require the caller to pass valid start/end pointers. + return generic::fwd_byte_by_byte(start, end, |b| { + b == self.0.needle1() + }); + } + // SAFETY: Building a `One` means it's safe to call 'sse2' routines. + // Also, we've checked that our haystack is big enough to run on the + // vector routine. Pointer validity is caller's responsibility. + // + // Note that we could call `self.0.find_raw` directly here. But that + // means we'd have to annotate this routine with `target_feature`. + // Which is fine, because this routine is `unsafe` anyway and the + // `target_feature` obligation is met by virtue of building a `One`. + // The real problem is that a routine with a `target_feature` + // annotation generally can't be inlined into caller code unless the + // caller code has the same target feature annotations. Which is maybe + // okay for SSE2, but we do the same thing for AVX2 where caller code + // probably usually doesn't have AVX2 enabled. That means that this + // routine can be inlined which will handle some of the short-haystack + // cases above without touching the architecture specific code. + self.find_raw_impl(start, end) + } + + /// Like `rfind`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn rfind_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + if end.distance(start) < __m128i::BYTES { + // SAFETY: We require the caller to pass valid start/end pointers. + return generic::rev_byte_by_byte(start, end, |b| { + b == self.0.needle1() + }); + } + // SAFETY: Building a `One` means it's safe to call 'sse2' routines. + // Also, we've checked that our haystack is big enough to run on the + // vector routine. Pointer validity is caller's responsibility. + // + // See note in forward routine above for why we don't just call + // `self.0.rfind_raw` directly here. + self.rfind_raw_impl(start, end) + } + + /// Counts all occurrences of this byte in the given haystack represented + /// by raw pointers. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `0` will always be returned. + #[inline] + pub unsafe fn count_raw(&self, start: *const u8, end: *const u8) -> usize { + if start >= end { + return 0; + } + if end.distance(start) < __m128i::BYTES { + // SAFETY: We require the caller to pass valid start/end pointers. + return generic::count_byte_by_byte(start, end, |b| { + b == self.0.needle1() + }); + } + // SAFETY: Building a `One` means it's safe to call 'sse2' routines. + // Also, we've checked that our haystack is big enough to run on the + // vector routine. Pointer validity is caller's responsibility. + self.count_raw_impl(start, end) + } + + /// Execute a search using SSE2 vectors and routines. + /// + /// # Safety + /// + /// Same as [`One::find_raw`], except the distance between `start` and + /// `end` must be at least the size of an SSE2 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `One`, which can only be constructed + /// when it is safe to call `sse2` routines.) + #[target_feature(enable = "sse2")] + #[inline] + unsafe fn find_raw_impl( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.0.find_raw(start, end) + } + + /// Execute a search using SSE2 vectors and routines. + /// + /// # Safety + /// + /// Same as [`One::rfind_raw`], except the distance between `start` and + /// `end` must be at least the size of an SSE2 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `One`, which can only be constructed + /// when it is safe to call `sse2` routines.) + #[target_feature(enable = "sse2")] + #[inline] + unsafe fn rfind_raw_impl( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.0.rfind_raw(start, end) + } + + /// Execute a count using SSE2 vectors and routines. + /// + /// # Safety + /// + /// Same as [`One::count_raw`], except the distance between `start` and + /// `end` must be at least the size of an SSE2 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `One`, which can only be constructed + /// when it is safe to call `sse2` routines.) + #[target_feature(enable = "sse2")] + #[inline] + unsafe fn count_raw_impl( + &self, + start: *const u8, + end: *const u8, + ) -> usize { + self.0.count_raw(start, end) + } + + /// Returns an iterator over all occurrences of the needle byte in the + /// given haystack. + /// + /// The iterator returned implements `DoubleEndedIterator`. This means it + /// can also be used to find occurrences in reverse order. + #[inline] + pub fn iter<'a, 'h>(&'a self, haystack: &'h [u8]) -> OneIter<'a, 'h> { + OneIter { searcher: self, it: generic::Iter::new(haystack) } + } +} + +/// An iterator over all occurrences of a single byte in a haystack. +/// +/// This iterator implements `DoubleEndedIterator`, which means it can also be +/// used to find occurrences in reverse order. +/// +/// This iterator is created by the [`One::iter`] method. +/// +/// The lifetime parameters are as follows: +/// +/// * `'a` refers to the lifetime of the underlying [`One`] searcher. +/// * `'h` refers to the lifetime of the haystack being searched. +#[derive(Clone, Debug)] +pub struct OneIter<'a, 'h> { + searcher: &'a One, + it: generic::Iter<'h>, +} + +impl<'a, 'h> Iterator for OneIter<'a, 'h> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'find_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next(|s, e| self.searcher.find_raw(s, e)) } + } + + #[inline] + fn count(self) -> usize { + self.it.count(|s, e| { + // SAFETY: We rely on our generic iterator to return valid start + // and end pointers. + unsafe { self.searcher.count_raw(s, e) } + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, 'h> DoubleEndedIterator for OneIter<'a, 'h> { + #[inline] + fn next_back(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'rfind_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next_back(|s, e| self.searcher.rfind_raw(s, e)) } + } +} + +impl<'a, 'h> core::iter::FusedIterator for OneIter<'a, 'h> {} + +/// Finds all occurrences of two bytes in a haystack. +/// +/// That is, this reports matches of one of two possible bytes. For example, +/// searching for `a` or `b` in `afoobar` would report matches at offsets `0`, +/// `4` and `5`. +#[derive(Clone, Copy, Debug)] +pub struct Two(generic::Two<__m128i>); + +impl Two { + /// Create a new searcher that finds occurrences of the needle bytes given. + /// + /// This particular searcher is specialized to use SSE2 vector instructions + /// that typically make it quite fast. + /// + /// If SSE2 is unavailable in the current environment, then `None` is + /// returned. + #[inline] + pub fn new(needle1: u8, needle2: u8) -> Option { + if Two::is_available() { + // SAFETY: we check that sse2 is available above. + unsafe { Some(Two::new_unchecked(needle1, needle2)) } + } else { + None + } + } + + /// Create a new finder specific to SSE2 vectors and routines without + /// checking that SSE2 is available. + /// + /// # Safety + /// + /// Callers must guarantee that it is safe to execute `sse2` instructions + /// in the current environment. + /// + /// Note that it is a common misconception that if one compiles for an + /// `x86_64` target, then they therefore automatically have access to SSE2 + /// instructions. While this is almost always the case, it isn't true in + /// 100% of cases. + #[target_feature(enable = "sse2")] + #[inline] + pub unsafe fn new_unchecked(needle1: u8, needle2: u8) -> Two { + Two(generic::Two::new(needle1, needle2)) + } + + /// Returns true when this implementation is available in the current + /// environment. + /// + /// When this is true, it is guaranteed that [`Two::new`] will return + /// a `Some` value. Similarly, when it is false, it is guaranteed that + /// `Two::new` will return a `None` value. + /// + /// Note also that for the lifetime of a single program, if this returns + /// true then it will always return true. + #[inline] + pub fn is_available() -> bool { + #[cfg(target_feature = "sse2")] + { + true + } + #[cfg(not(target_feature = "sse2"))] + { + false + } + } + + /// Return the first occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value is `haystack.len() - 1`. + #[inline] + pub fn find(&self, haystack: &[u8]) -> Option { + // SAFETY: `find_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.find_raw(s, e) + }) + } + } + + /// Return the last occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value is `haystack.len() - 1`. + #[inline] + pub fn rfind(&self, haystack: &[u8]) -> Option { + // SAFETY: `rfind_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.rfind_raw(s, e) + }) + } + } + + /// Like `find`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn find_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + if end.distance(start) < __m128i::BYTES { + // SAFETY: We require the caller to pass valid start/end pointers. + return generic::fwd_byte_by_byte(start, end, |b| { + b == self.0.needle1() || b == self.0.needle2() + }); + } + // SAFETY: Building a `Two` means it's safe to call 'sse2' routines. + // Also, we've checked that our haystack is big enough to run on the + // vector routine. Pointer validity is caller's responsibility. + // + // Note that we could call `self.0.find_raw` directly here. But that + // means we'd have to annotate this routine with `target_feature`. + // Which is fine, because this routine is `unsafe` anyway and the + // `target_feature` obligation is met by virtue of building a `Two`. + // The real problem is that a routine with a `target_feature` + // annotation generally can't be inlined into caller code unless the + // caller code has the same target feature annotations. Which is maybe + // okay for SSE2, but we do the same thing for AVX2 where caller code + // probably usually doesn't have AVX2 enabled. That means that this + // routine can be inlined which will handle some of the short-haystack + // cases above without touching the architecture specific code. + self.find_raw_impl(start, end) + } + + /// Like `rfind`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn rfind_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + if end.distance(start) < __m128i::BYTES { + // SAFETY: We require the caller to pass valid start/end pointers. + return generic::rev_byte_by_byte(start, end, |b| { + b == self.0.needle1() || b == self.0.needle2() + }); + } + // SAFETY: Building a `Two` means it's safe to call 'sse2' routines. + // Also, we've checked that our haystack is big enough to run on the + // vector routine. Pointer validity is caller's responsibility. + // + // See note in forward routine above for why we don't just call + // `self.0.rfind_raw` directly here. + self.rfind_raw_impl(start, end) + } + + /// Execute a search using SSE2 vectors and routines. + /// + /// # Safety + /// + /// Same as [`Two::find_raw`], except the distance between `start` and + /// `end` must be at least the size of an SSE2 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Two`, which can only be constructed + /// when it is safe to call `sse2` routines.) + #[target_feature(enable = "sse2")] + #[inline] + unsafe fn find_raw_impl( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.0.find_raw(start, end) + } + + /// Execute a search using SSE2 vectors and routines. + /// + /// # Safety + /// + /// Same as [`Two::rfind_raw`], except the distance between `start` and + /// `end` must be at least the size of an SSE2 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Two`, which can only be constructed + /// when it is safe to call `sse2` routines.) + #[target_feature(enable = "sse2")] + #[inline] + unsafe fn rfind_raw_impl( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.0.rfind_raw(start, end) + } + + /// Returns an iterator over all occurrences of the needle bytes in the + /// given haystack. + /// + /// The iterator returned implements `DoubleEndedIterator`. This means it + /// can also be used to find occurrences in reverse order. + #[inline] + pub fn iter<'a, 'h>(&'a self, haystack: &'h [u8]) -> TwoIter<'a, 'h> { + TwoIter { searcher: self, it: generic::Iter::new(haystack) } + } +} + +/// An iterator over all occurrences of two possible bytes in a haystack. +/// +/// This iterator implements `DoubleEndedIterator`, which means it can also be +/// used to find occurrences in reverse order. +/// +/// This iterator is created by the [`Two::iter`] method. +/// +/// The lifetime parameters are as follows: +/// +/// * `'a` refers to the lifetime of the underlying [`Two`] searcher. +/// * `'h` refers to the lifetime of the haystack being searched. +#[derive(Clone, Debug)] +pub struct TwoIter<'a, 'h> { + searcher: &'a Two, + it: generic::Iter<'h>, +} + +impl<'a, 'h> Iterator for TwoIter<'a, 'h> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'find_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next(|s, e| self.searcher.find_raw(s, e)) } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, 'h> DoubleEndedIterator for TwoIter<'a, 'h> { + #[inline] + fn next_back(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'rfind_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next_back(|s, e| self.searcher.rfind_raw(s, e)) } + } +} + +impl<'a, 'h> core::iter::FusedIterator for TwoIter<'a, 'h> {} + +/// Finds all occurrences of three bytes in a haystack. +/// +/// That is, this reports matches of one of three possible bytes. For example, +/// searching for `a`, `b` or `o` in `afoobar` would report matches at offsets +/// `0`, `2`, `3`, `4` and `5`. +#[derive(Clone, Copy, Debug)] +pub struct Three(generic::Three<__m128i>); + +impl Three { + /// Create a new searcher that finds occurrences of the needle bytes given. + /// + /// This particular searcher is specialized to use SSE2 vector instructions + /// that typically make it quite fast. + /// + /// If SSE2 is unavailable in the current environment, then `None` is + /// returned. + #[inline] + pub fn new(needle1: u8, needle2: u8, needle3: u8) -> Option { + if Three::is_available() { + // SAFETY: we check that sse2 is available above. + unsafe { Some(Three::new_unchecked(needle1, needle2, needle3)) } + } else { + None + } + } + + /// Create a new finder specific to SSE2 vectors and routines without + /// checking that SSE2 is available. + /// + /// # Safety + /// + /// Callers must guarantee that it is safe to execute `sse2` instructions + /// in the current environment. + /// + /// Note that it is a common misconception that if one compiles for an + /// `x86_64` target, then they therefore automatically have access to SSE2 + /// instructions. While this is almost always the case, it isn't true in + /// 100% of cases. + #[target_feature(enable = "sse2")] + #[inline] + pub unsafe fn new_unchecked( + needle1: u8, + needle2: u8, + needle3: u8, + ) -> Three { + Three(generic::Three::new(needle1, needle2, needle3)) + } + + /// Returns true when this implementation is available in the current + /// environment. + /// + /// When this is true, it is guaranteed that [`Three::new`] will return + /// a `Some` value. Similarly, when it is false, it is guaranteed that + /// `Three::new` will return a `None` value. + /// + /// Note also that for the lifetime of a single program, if this returns + /// true then it will always return true. + #[inline] + pub fn is_available() -> bool { + #[cfg(target_feature = "sse2")] + { + true + } + #[cfg(not(target_feature = "sse2"))] + { + false + } + } + + /// Return the first occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value is `haystack.len() - 1`. + #[inline] + pub fn find(&self, haystack: &[u8]) -> Option { + // SAFETY: `find_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.find_raw(s, e) + }) + } + } + + /// Return the last occurrence of one of the needle bytes in the given + /// haystack. If no such occurrence exists, then `None` is returned. + /// + /// The occurrence is reported as an offset into `haystack`. Its maximum + /// value is `haystack.len() - 1`. + #[inline] + pub fn rfind(&self, haystack: &[u8]) -> Option { + // SAFETY: `rfind_raw` guarantees that if a pointer is returned, it + // falls within the bounds of the start and end pointers. + unsafe { + generic::search_slice_with_raw(haystack, |s, e| { + self.rfind_raw(s, e) + }) + } + } + + /// Like `find`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn find_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + if end.distance(start) < __m128i::BYTES { + // SAFETY: We require the caller to pass valid start/end pointers. + return generic::fwd_byte_by_byte(start, end, |b| { + b == self.0.needle1() + || b == self.0.needle2() + || b == self.0.needle3() + }); + } + // SAFETY: Building a `Three` means it's safe to call 'sse2' routines. + // Also, we've checked that our haystack is big enough to run on the + // vector routine. Pointer validity is caller's responsibility. + // + // Note that we could call `self.0.find_raw` directly here. But that + // means we'd have to annotate this routine with `target_feature`. + // Which is fine, because this routine is `unsafe` anyway and the + // `target_feature` obligation is met by virtue of building a `Three`. + // The real problem is that a routine with a `target_feature` + // annotation generally can't be inlined into caller code unless the + // caller code has the same target feature annotations. Which is maybe + // okay for SSE2, but we do the same thing for AVX2 where caller code + // probably usually doesn't have AVX2 enabled. That means that this + // routine can be inlined which will handle some of the short-haystack + // cases above without touching the architecture specific code. + self.find_raw_impl(start, end) + } + + /// Like `rfind`, but accepts and returns raw pointers. + /// + /// When a match is found, the pointer returned is guaranteed to be + /// `>= start` and `< end`. + /// + /// This routine is useful if you're already using raw pointers and would + /// like to avoid converting back to a slice before executing a search. + /// + /// # Safety + /// + /// * Both `start` and `end` must be valid for reads. + /// * Both `start` and `end` must point to an initialized value. + /// * Both `start` and `end` must point to the same allocated object and + /// must either be in bounds or at most one byte past the end of the + /// allocated object. + /// * Both `start` and `end` must be _derived from_ a pointer to the same + /// object. + /// * The distance between `start` and `end` must not overflow `isize`. + /// * The distance being in bounds must not rely on "wrapping around" the + /// address space. + /// + /// Note that callers may pass a pair of pointers such that `start >= end`. + /// In that case, `None` will always be returned. + #[inline] + pub unsafe fn rfind_raw( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + if start >= end { + return None; + } + if end.distance(start) < __m128i::BYTES { + // SAFETY: We require the caller to pass valid start/end pointers. + return generic::rev_byte_by_byte(start, end, |b| { + b == self.0.needle1() + || b == self.0.needle2() + || b == self.0.needle3() + }); + } + // SAFETY: Building a `Three` means it's safe to call 'sse2' routines. + // Also, we've checked that our haystack is big enough to run on the + // vector routine. Pointer validity is caller's responsibility. + // + // See note in forward routine above for why we don't just call + // `self.0.rfind_raw` directly here. + self.rfind_raw_impl(start, end) + } + + /// Execute a search using SSE2 vectors and routines. + /// + /// # Safety + /// + /// Same as [`Three::find_raw`], except the distance between `start` and + /// `end` must be at least the size of an SSE2 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Three`, which can only be constructed + /// when it is safe to call `sse2` routines.) + #[target_feature(enable = "sse2")] + #[inline] + unsafe fn find_raw_impl( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.0.find_raw(start, end) + } + + /// Execute a search using SSE2 vectors and routines. + /// + /// # Safety + /// + /// Same as [`Three::rfind_raw`], except the distance between `start` and + /// `end` must be at least the size of an SSE2 vector (in bytes). + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Three`, which can only be constructed + /// when it is safe to call `sse2` routines.) + #[target_feature(enable = "sse2")] + #[inline] + unsafe fn rfind_raw_impl( + &self, + start: *const u8, + end: *const u8, + ) -> Option<*const u8> { + self.0.rfind_raw(start, end) + } + + /// Returns an iterator over all occurrences of the needle byte in the + /// given haystack. + /// + /// The iterator returned implements `DoubleEndedIterator`. This means it + /// can also be used to find occurrences in reverse order. + #[inline] + pub fn iter<'a, 'h>(&'a self, haystack: &'h [u8]) -> ThreeIter<'a, 'h> { + ThreeIter { searcher: self, it: generic::Iter::new(haystack) } + } +} + +/// An iterator over all occurrences of three possible bytes in a haystack. +/// +/// This iterator implements `DoubleEndedIterator`, which means it can also be +/// used to find occurrences in reverse order. +/// +/// This iterator is created by the [`Three::iter`] method. +/// +/// The lifetime parameters are as follows: +/// +/// * `'a` refers to the lifetime of the underlying [`Three`] searcher. +/// * `'h` refers to the lifetime of the haystack being searched. +#[derive(Clone, Debug)] +pub struct ThreeIter<'a, 'h> { + searcher: &'a Three, + it: generic::Iter<'h>, +} + +impl<'a, 'h> Iterator for ThreeIter<'a, 'h> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'find_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next(|s, e| self.searcher.find_raw(s, e)) } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, 'h> DoubleEndedIterator for ThreeIter<'a, 'h> { + #[inline] + fn next_back(&mut self) -> Option { + // SAFETY: We rely on the generic iterator to provide valid start + // and end pointers, but we guarantee that any pointer returned by + // 'rfind_raw' falls within the bounds of the start and end pointer. + unsafe { self.it.next_back(|s, e| self.searcher.rfind_raw(s, e)) } + } +} + +impl<'a, 'h> core::iter::FusedIterator for ThreeIter<'a, 'h> {} + +#[cfg(test)] +mod tests { + use super::*; + + define_memchr_quickcheck!(super); + + #[test] + fn forward_one() { + crate::tests::memchr::Runner::new(1).forward_iter( + |haystack, needles| { + Some(One::new(needles[0])?.iter(haystack).collect()) + }, + ) + } + + #[test] + fn reverse_one() { + crate::tests::memchr::Runner::new(1).reverse_iter( + |haystack, needles| { + Some(One::new(needles[0])?.iter(haystack).rev().collect()) + }, + ) + } + + #[test] + fn count_one() { + crate::tests::memchr::Runner::new(1).count_iter(|haystack, needles| { + Some(One::new(needles[0])?.iter(haystack).count()) + }) + } + + #[test] + fn forward_two() { + crate::tests::memchr::Runner::new(2).forward_iter( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + Some(Two::new(n1, n2)?.iter(haystack).collect()) + }, + ) + } + + #[test] + fn reverse_two() { + crate::tests::memchr::Runner::new(2).reverse_iter( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + Some(Two::new(n1, n2)?.iter(haystack).rev().collect()) + }, + ) + } + + #[test] + fn forward_three() { + crate::tests::memchr::Runner::new(3).forward_iter( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + let n3 = needles.get(2).copied()?; + Some(Three::new(n1, n2, n3)?.iter(haystack).collect()) + }, + ) + } + + #[test] + fn reverse_three() { + crate::tests::memchr::Runner::new(3).reverse_iter( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + let n3 = needles.get(2).copied()?; + Some(Three::new(n1, n2, n3)?.iter(haystack).rev().collect()) + }, + ) + } +} diff --git a/third_party/crates/memchr-2.8.3/src/arch/x86_64/sse2/mod.rs b/third_party/crates/memchr-2.8.3/src/arch/x86_64/sse2/mod.rs new file mode 100644 index 0000000..bcb8307 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/x86_64/sse2/mod.rs @@ -0,0 +1,6 @@ +/*! +Algorithms for the `x86_64` target using 128-bit vectors via SSE2. +*/ + +pub mod memchr; +pub mod packedpair; diff --git a/third_party/crates/memchr-2.8.3/src/arch/x86_64/sse2/packedpair.rs b/third_party/crates/memchr-2.8.3/src/arch/x86_64/sse2/packedpair.rs new file mode 100644 index 0000000..75329c2 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/arch/x86_64/sse2/packedpair.rs @@ -0,0 +1,253 @@ +/*! +A 128-bit vector implementation of the "packed pair" SIMD algorithm. + +The "packed pair" algorithm is based on the [generic SIMD] algorithm. The main +difference is that it (by default) uses a background distribution of byte +frequencies to heuristically select the pair of bytes to search for. + +[generic SIMD]: http://0x80.pl/articles/simd-strfind.html#first-and-last +*/ + +use core::arch::x86_64::__m128i; + +use crate::arch::{all::packedpair::Pair, generic::packedpair}; + +/// A "packed pair" finder that uses 128-bit vector operations. +/// +/// This finder picks two bytes that it believes have high predictive power +/// for indicating an overall match of a needle. Depending on whether +/// `Finder::find` or `Finder::find_prefilter` is used, it reports offsets +/// where the needle matches or could match. In the prefilter case, candidates +/// are reported whenever the [`Pair`] of bytes given matches. +#[derive(Clone, Copy, Debug)] +pub struct Finder(packedpair::Finder<__m128i>); + +impl Finder { + /// Create a new pair searcher. The searcher returned can either report + /// exact matches of `needle` or act as a prefilter and report candidate + /// positions of `needle`. + /// + /// If SSE2 is unavailable in the current environment or if a [`Pair`] + /// could not be constructed from the needle given, then `None` is + /// returned. + #[inline] + pub fn new(needle: &[u8]) -> Option { + Finder::with_pair(needle, Pair::new(needle)?) + } + + /// Create a new "packed pair" finder using the pair of bytes given. + /// + /// This constructor permits callers to control precisely which pair of + /// bytes is used as a predicate. + /// + /// If SSE2 is unavailable in the current environment, then `None` is + /// returned. + #[inline] + pub fn with_pair(needle: &[u8], pair: Pair) -> Option { + if Finder::is_available() { + // SAFETY: we check that sse2 is available above. We are also + // guaranteed to have needle.len() > 1 because we have a valid + // Pair. + unsafe { Some(Finder::with_pair_impl(needle, pair)) } + } else { + None + } + } + + /// Create a new `Finder` specific to SSE2 vectors and routines. + /// + /// # Safety + /// + /// Same as the safety for `packedpair::Finder::new`, and callers must also + /// ensure that SSE2 is available. + #[target_feature(enable = "sse2")] + #[inline] + unsafe fn with_pair_impl(needle: &[u8], pair: Pair) -> Finder { + let finder = packedpair::Finder::<__m128i>::new(needle, pair); + Finder(finder) + } + + /// Returns true when this implementation is available in the current + /// environment. + /// + /// When this is true, it is guaranteed that [`Finder::with_pair`] will + /// return a `Some` value. Similarly, when it is false, it is guaranteed + /// that `Finder::with_pair` will return a `None` value. Notice that this + /// does not guarantee that [`Finder::new`] will return a `Finder`. Namely, + /// even when `Finder::is_available` is true, it is not guaranteed that a + /// valid [`Pair`] can be found from the needle given. + /// + /// Note also that for the lifetime of a single program, if this returns + /// true then it will always return true. + #[inline] + pub fn is_available() -> bool { + #[cfg(not(target_feature = "sse2"))] + { + false + } + #[cfg(target_feature = "sse2")] + { + true + } + } + + /// Execute a search using SSE2 vectors and routines. + /// + /// # Panics + /// + /// When `haystack.len()` is less than [`Finder::min_haystack_len`]. + #[inline] + pub fn find(&self, haystack: &[u8], needle: &[u8]) -> Option { + // SAFETY: Building a `Finder` means it's safe to call 'sse2' routines. + unsafe { self.find_impl(haystack, needle) } + } + + /// Run this finder on the given haystack as a prefilter. + /// + /// If a candidate match is found, then an offset where the needle *could* + /// begin in the haystack is returned. + /// + /// # Panics + /// + /// When `haystack.len()` is less than [`Finder::min_haystack_len`]. + #[inline] + pub fn find_prefilter(&self, haystack: &[u8]) -> Option { + // SAFETY: Building a `Finder` means it's safe to call 'sse2' routines. + unsafe { self.find_prefilter_impl(haystack) } + } + + /// Execute a search using SSE2 vectors and routines. + /// + /// # Panics + /// + /// When `haystack.len()` is less than [`Finder::min_haystack_len`]. + /// + /// # Safety + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Finder`, which can only be constructed + /// when it is safe to call `sse2` routines.) + #[target_feature(enable = "sse2")] + #[inline] + unsafe fn find_impl( + &self, + haystack: &[u8], + needle: &[u8], + ) -> Option { + self.0.find(haystack, needle) + } + + /// Execute a prefilter search using SSE2 vectors and routines. + /// + /// # Panics + /// + /// When `haystack.len()` is less than [`Finder::min_haystack_len`]. + /// + /// # Safety + /// + /// (The target feature safety obligation is automatically fulfilled by + /// virtue of being a method on `Finder`, which can only be constructed + /// when it is safe to call `sse2` routines.) + #[target_feature(enable = "sse2")] + #[inline] + unsafe fn find_prefilter_impl(&self, haystack: &[u8]) -> Option { + self.0.find_prefilter(haystack) + } + + /// Returns the pair of offsets (into the needle) used to check as a + /// predicate before confirming whether a needle exists at a particular + /// position. + #[inline] + pub fn pair(&self) -> &Pair { + self.0.pair() + } + + /// Returns the minimum haystack length that this `Finder` can search. + /// + /// Using a haystack with length smaller than this in a search will result + /// in a panic. The reason for this restriction is that this finder is + /// meant to be a low-level component that is part of a larger substring + /// strategy. In that sense, it avoids trying to handle all cases and + /// instead only handles the cases that it can handle very well. + #[inline] + pub fn min_haystack_len(&self) -> usize { + self.0.min_haystack_len() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn find(haystack: &[u8], needle: &[u8]) -> Option> { + let f = Finder::new(needle)?; + if haystack.len() < f.min_haystack_len() { + return None; + } + Some(f.find(haystack, needle)) + } + + define_substring_forward_quickcheck!(find); + + #[test] + fn forward_substring() { + crate::tests::substring::Runner::new().fwd(find).run() + } + + #[test] + fn forward_packedpair() { + fn find( + haystack: &[u8], + needle: &[u8], + index1: u8, + index2: u8, + ) -> Option> { + let pair = Pair::with_indices(needle, index1, index2)?; + let f = Finder::with_pair(needle, pair)?; + if haystack.len() < f.min_haystack_len() { + return None; + } + Some(f.find(haystack, needle)) + } + crate::tests::packedpair::Runner::new().fwd(find).run() + } + + #[test] + fn forward_packedpair_prefilter() { + fn find( + haystack: &[u8], + needle: &[u8], + index1: u8, + index2: u8, + ) -> Option> { + let pair = Pair::with_indices(needle, index1, index2)?; + let f = Finder::with_pair(needle, pair)?; + if haystack.len() < f.min_haystack_len() { + return None; + } + Some(f.find_prefilter(haystack)) + } + crate::tests::packedpair::Runner::new().fwd(find).run() + } + + // A demonstration of UB (caught under Miri) through some of memchr's + // lower level but public APIs. + // + // See: https://github.com/BurntSushi/memchr/issues/225 + #[test] + fn regression_undefined_behavior() { + let construct_needle: &[u8] = b"ab"; // length 2 → pair indices 0,1 + let pair = Pair::new(construct_needle).unwrap(); + let Some(finder) = Finder::with_pair(construct_needle, pair) else { + return; + }; + let mhl = finder.min_haystack_len(); // 17 + let mut haystack = alloc::vec![b'.'; mhl + 5]; + haystack[0] = b'a'; + // force entry into find_in_chunk inner branch + haystack[1] = b'b'; + // 122 > haystack.len()=22 + let long_needle = alloc::vec![b'X'; haystack.len() + 100]; + let _ = finder.find(&haystack, &long_needle); + } +} diff --git a/third_party/crates/memchr-2.8.3/src/cow.rs b/third_party/crates/memchr-2.8.3/src/cow.rs new file mode 100644 index 0000000..5306f97 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/cow.rs @@ -0,0 +1,109 @@ +use core::ops; + +/// A specialized copy-on-write byte string. +/// +/// The purpose of this type is to permit usage of a "borrowed or owned +/// byte string" in a way that keeps std/no-std compatibility. That is, in +/// no-std/alloc mode, this type devolves into a simple &[u8] with no owned +/// variant available. We can't just use a plain Cow because Cow is not in +/// core. +#[derive(Clone, Debug)] +pub struct CowBytes<'a>(Imp<'a>); + +// N.B. We don't use alloc::borrow::Cow here since we can get away with a +// Box<[u8]> for our use case, which is 1/3 smaller than the Vec that +// a Cow<[u8]> would use. +#[cfg(feature = "alloc")] +#[derive(Clone, Debug)] +enum Imp<'a> { + Borrowed(&'a [u8]), + Owned(alloc::boxed::Box<[u8]>), +} + +#[cfg(not(feature = "alloc"))] +#[derive(Clone, Debug)] +struct Imp<'a>(&'a [u8]); + +impl<'a> ops::Deref for CowBytes<'a> { + type Target = [u8]; + + #[inline(always)] + fn deref(&self) -> &[u8] { + self.as_slice() + } +} + +impl<'a> CowBytes<'a> { + /// Create a new borrowed CowBytes. + #[inline(always)] + pub(crate) fn new>(bytes: &'a B) -> CowBytes<'a> { + CowBytes(Imp::new(bytes.as_ref())) + } + + /// Create a new owned CowBytes. + #[cfg(feature = "alloc")] + #[inline(always)] + pub(crate) fn new_owned( + bytes: alloc::boxed::Box<[u8]>, + ) -> CowBytes<'static> { + CowBytes(Imp::Owned(bytes)) + } + + /// Return a borrowed byte string, regardless of whether this is an owned + /// or borrowed byte string internally. + #[inline(always)] + pub(crate) fn as_slice(&self) -> &[u8] { + self.0.as_slice() + } + + /// Return an owned version of this copy-on-write byte string. + /// + /// If this is already an owned byte string internally, then this is a + /// no-op. Otherwise, the internal byte string is copied. + #[cfg(feature = "alloc")] + #[inline(always)] + pub(crate) fn into_owned(self) -> CowBytes<'static> { + match self.0 { + Imp::Borrowed(b) => { + CowBytes::new_owned(alloc::boxed::Box::from(b)) + } + Imp::Owned(b) => CowBytes::new_owned(b), + } + } +} + +impl<'a> Imp<'a> { + #[inline(always)] + pub fn new(bytes: &'a [u8]) -> Imp<'a> { + #[cfg(feature = "alloc")] + { + Imp::Borrowed(bytes) + } + #[cfg(not(feature = "alloc"))] + { + Imp(bytes) + } + } + + #[cfg(feature = "alloc")] + #[inline(always)] + pub fn as_slice(&self) -> &[u8] { + #[cfg(feature = "alloc")] + { + match self { + Imp::Owned(ref x) => x, + Imp::Borrowed(x) => x, + } + } + #[cfg(not(feature = "alloc"))] + { + self.0 + } + } + + #[cfg(not(feature = "alloc"))] + #[inline(always)] + pub fn as_slice(&self) -> &[u8] { + self.0 + } +} diff --git a/third_party/crates/memchr-2.8.3/src/ext.rs b/third_party/crates/memchr-2.8.3/src/ext.rs new file mode 100644 index 0000000..802697a --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/ext.rs @@ -0,0 +1,54 @@ +/// A trait for adding some helper routines to pointers. +pub(crate) trait Pointer { + /// Returns the distance, in units of `T`, between `self` and `origin`. + /// + /// # Safety + /// + /// Same as `ptr::offset_from` in addition to `self >= origin`. + unsafe fn distance(self, origin: Self) -> usize; + + /// Casts this pointer to `usize`. + /// + /// Callers should not convert the `usize` back to a pointer if at all + /// possible. (And if you believe it's necessary, open an issue to discuss + /// why. Otherwise, it has the potential to violate pointer provenance.) + /// The purpose of this function is just to be able to do arithmetic, i.e., + /// computing offsets or alignments. + fn as_usize(self) -> usize; +} + +impl Pointer for *const T { + unsafe fn distance(self, origin: *const T) -> usize { + // TODO: Replace with `ptr::sub_ptr` once stabilized. + usize::try_from(self.offset_from(origin)).unwrap_unchecked() + } + + fn as_usize(self) -> usize { + self as usize + } +} + +impl Pointer for *mut T { + unsafe fn distance(self, origin: *mut T) -> usize { + (self as *const T).distance(origin as *const T) + } + + fn as_usize(self) -> usize { + (self as *const T).as_usize() + } +} + +/// A trait for adding some helper routines to raw bytes. +#[cfg(test)] +pub(crate) trait Byte { + /// Converts this byte to a `char` if it's ASCII. Otherwise panics. + fn to_char(self) -> char; +} + +#[cfg(test)] +impl Byte for u8 { + fn to_char(self) -> char { + assert!(self.is_ascii()); + char::from(self) + } +} diff --git a/third_party/crates/memchr-2.8.3/src/lib.rs b/third_party/crates/memchr-2.8.3/src/lib.rs new file mode 100644 index 0000000..b310516 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/lib.rs @@ -0,0 +1,221 @@ +/*! +This library provides heavily optimized routines for string search primitives. + +# Overview + +This section gives a brief high level overview of what this crate offers. + +* The top-level module provides routines for searching for 1, 2 or 3 bytes + in the forward or reverse direction. When searching for more than one byte, + positions are considered a match if the byte at that position matches any + of the bytes. +* The [`memmem`] sub-module provides forward and reverse substring search + routines. + +In all such cases, routines operate on `&[u8]` without regard to encoding. This +is exactly what you want when searching either UTF-8 or arbitrary bytes. + +# Example: using `memchr` + +This example shows how to use `memchr` to find the first occurrence of `z` in +a haystack: + +``` +use memchr::memchr; + +let haystack = b"foo bar baz quuz"; +assert_eq!(Some(10), memchr(b'z', haystack)); +``` + +# Example: matching one of three possible bytes + +This examples shows how to use `memrchr3` to find occurrences of `a`, `b` or +`c`, starting at the end of the haystack. + +``` +use memchr::memchr3_iter; + +let haystack = b"xyzaxyzbxyzc"; + +let mut it = memchr3_iter(b'a', b'b', b'c', haystack).rev(); +assert_eq!(Some(11), it.next()); +assert_eq!(Some(7), it.next()); +assert_eq!(Some(3), it.next()); +assert_eq!(None, it.next()); +``` + +# Example: iterating over substring matches + +This example shows how to use the [`memmem`] sub-module to find occurrences of +a substring in a haystack. + +``` +use memchr::memmem; + +let haystack = b"foo bar foo baz foo"; + +let mut it = memmem::find_iter(haystack, "foo"); +assert_eq!(Some(0), it.next()); +assert_eq!(Some(8), it.next()); +assert_eq!(Some(16), it.next()); +assert_eq!(None, it.next()); +``` + +# Example: repeating a search for the same needle + +It may be possible for the overhead of constructing a substring searcher to be +measurable in some workloads. In cases where the same needle is used to search +many haystacks, it is possible to do construction once and thus to avoid it for +subsequent searches. This can be done with a [`memmem::Finder`]: + +``` +use memchr::memmem; + +let finder = memmem::Finder::new("foo"); + +assert_eq!(Some(4), finder.find(b"baz foo quux")); +assert_eq!(None, finder.find(b"quux baz bar")); +``` + +# Why use this crate? + +At first glance, the APIs provided by this crate might seem weird. Why provide +a dedicated routine like `memchr` for something that could be implemented +clearly and trivially in one line: + +``` +fn memchr(needle: u8, haystack: &[u8]) -> Option { + haystack.iter().position(|&b| b == needle) +} +``` + +Or similarly, why does this crate provide substring search routines when Rust's +core library already provides them? + +``` +fn search(haystack: &str, needle: &str) -> Option { + haystack.find(needle) +} +``` + +The primary reason for both of them to exist is performance. When it comes to +performance, at a high level at least, there are two primary ways to look at +it: + +* **Throughput**: For this, think about it as, "given some very large haystack + and a byte that never occurs in that haystack, how long does it take to + search through it and determine that it, in fact, does not occur?" +* **Latency**: For this, think about it as, "given a tiny haystack---just a + few bytes---how long does it take to determine if a byte is in it?" + +The `memchr` routine in this crate has _slightly_ worse latency than the +solution presented above, however, its throughput can easily be over an +order of magnitude faster. This is a good general purpose trade off to make. +You rarely lose, but often gain big. + +**NOTE:** The name `memchr` comes from the corresponding routine in `libc`. A +key advantage of using this library is that its performance is not tied to its +quality of implementation in the `libc` you happen to be using, which can vary +greatly from platform to platform. + +But what about substring search? This one is a bit more complicated. The +primary reason for its existence is still indeed performance, but it's also +useful because Rust's core library doesn't actually expose any substring +search routine on arbitrary bytes. The only substring search routine that +exists works exclusively on valid UTF-8. + +So if you have valid UTF-8, is there a reason to use this over the standard +library substring search routine? Yes. This routine is faster on almost every +metric, including latency. The natural question then, is why isn't this +implementation in the standard library, even if only for searching on UTF-8? +The reason is that the implementation details for using SIMD in the standard +library haven't quite been worked out yet. + +**NOTE:** Currently, only `x86_64`, `wasm32` and `aarch64` targets have vector +accelerated implementations of `memchr` (and friends) and `memmem`. + +# Crate features + +* **std** - When enabled (the default), this will permit features specific to +the standard library. Currently, the only thing used from the standard library +is runtime SIMD CPU feature detection. This means that this feature must be +enabled to get AVX2 accelerated routines on `x86_64` targets without enabling +the `avx2` feature at compile time, for example. When `std` is not enabled, +this crate will still attempt to use SSE2 accelerated routines on `x86_64`. It +will also use AVX2 accelerated routines when the `avx2` feature is enabled at +compile time. In general, enable this feature if you can. +* **alloc** - When enabled (the default), APIs in this crate requiring some +kind of allocation will become available. For example, the +[`memmem::Finder::into_owned`](crate::memmem::Finder::into_owned) API and the +[`arch::all::shiftor`](crate::arch::all::shiftor) substring search +implementation. Otherwise, this crate is designed from the ground up to be +usable in core-only contexts, so the `alloc` feature doesn't add much +currently. Notably, disabling `std` but enabling `alloc` will **not** result +in the use of AVX2 on `x86_64` targets unless the `avx2` feature is enabled +at compile time. (With `std` enabled, AVX2 can be used even without the `avx2` +feature enabled at compile time by way of runtime CPU feature detection.) +* **logging** - When enabled (disabled by default), the `log` crate is used +to emit log messages about what kinds of `memchr` and `memmem` algorithms +are used. Namely, both `memchr` and `memmem` have a number of different +implementation choices depending on the target and CPU, and the log messages +can help show what specific implementations are being used. Generally, this is +useful for debugging performance issues. +* **libc** - **DEPRECATED**. Previously, this enabled the use of the target's +`memchr` function from whatever `libc` was linked into the program. This +feature is now a no-op because this crate's implementation of `memchr` should +now be sufficiently fast on a number of platforms that `libc` should no longer +be needed. (This feature is somewhat of a holdover from this crate's origins. +Originally, this crate was literally just a safe wrapper function around the +`memchr` function from `libc`.) +*/ + +#![deny(missing_docs)] +#![no_std] +// It's just not worth trying to squash all dead code warnings. Pretty +// unfortunate IMO. Not really sure how to fix this other than to either +// live with it or sprinkle a whole mess of `cfg` annotations everywhere. +#![cfg_attr( + not(any( + all(target_arch = "x86_64", target_feature = "sse2"), + all(target_arch = "wasm32", target_feature = "simd128"), + target_arch = "aarch64", + )), + allow(dead_code) +)] +// Same deal for miri. +#![cfg_attr(miri, allow(dead_code, unused_macros))] + +// Supporting 8-bit (or others) would be fine. If you need it, please submit a +// bug report at https://github.com/BurntSushi/memchr +#[cfg(not(any( + target_pointer_width = "16", + target_pointer_width = "32", + target_pointer_width = "64" +)))] +compile_error!("memchr currently not supported on non-{16,32,64}"); + +#[cfg(any(test, feature = "std"))] +extern crate std; + +#[cfg(any(test, feature = "alloc"))] +extern crate alloc; + +pub use crate::memchr::{ + memchr, memchr2, memchr2_iter, memchr3, memchr3_iter, memchr_iter, + memrchr, memrchr2, memrchr2_iter, memrchr3, memrchr3_iter, memrchr_iter, + Memchr, Memchr2, Memchr3, +}; + +#[macro_use] +mod macros; + +#[cfg(test)] +#[macro_use] +mod tests; + +pub mod arch; +mod cow; +mod ext; +mod memchr; +pub mod memmem; +mod vector; diff --git a/third_party/crates/memchr-2.8.3/src/macros.rs b/third_party/crates/memchr-2.8.3/src/macros.rs new file mode 100644 index 0000000..31b4ca3 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/macros.rs @@ -0,0 +1,20 @@ +// Some feature combinations result in some of these macros never being used. +// Which is fine. Just squash the warnings. +#![allow(unused_macros)] + +macro_rules! log { + ($($tt:tt)*) => { + #[cfg(feature = "logging")] + { + $($tt)* + } + } +} + +macro_rules! debug { + ($($tt:tt)*) => { log!(log::debug!($($tt)*)) } +} + +macro_rules! trace { + ($($tt:tt)*) => { log!(log::trace!($($tt)*)) } +} diff --git a/third_party/crates/memchr-2.8.3/src/memchr.rs b/third_party/crates/memchr-2.8.3/src/memchr.rs new file mode 100644 index 0000000..92a18bd --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/memchr.rs @@ -0,0 +1,903 @@ +use core::iter::Rev; + +use crate::arch::generic::memchr as generic; + +/// Search for the first occurrence of a byte in a slice. +/// +/// This returns the index corresponding to the first occurrence of `needle` in +/// `haystack`, or `None` if one is not found. If an index is returned, it is +/// guaranteed to be less than `haystack.len()`. +/// +/// While this is semantically the same as something like +/// `haystack.iter().position(|&b| b == needle)`, this routine will attempt to +/// use highly optimized vector operations that can be an order of magnitude +/// faster (or more). +/// +/// # Example +/// +/// This shows how to find the first position of a byte in a byte string. +/// +/// ``` +/// use memchr::memchr; +/// +/// let haystack = b"the quick brown fox"; +/// assert_eq!(memchr(b'k', haystack), Some(8)); +/// ``` +#[inline] +pub fn memchr(needle: u8, haystack: &[u8]) -> Option { + // SAFETY: memchr_raw, when a match is found, always returns a valid + // pointer between start and end. + unsafe { + generic::search_slice_with_raw(haystack, |start, end| { + memchr_raw(needle, start, end) + }) + } +} + +/// Search for the last occurrence of a byte in a slice. +/// +/// This returns the index corresponding to the last occurrence of `needle` in +/// `haystack`, or `None` if one is not found. If an index is returned, it is +/// guaranteed to be less than `haystack.len()`. +/// +/// While this is semantically the same as something like +/// `haystack.iter().rposition(|&b| b == needle)`, this routine will attempt to +/// use highly optimized vector operations that can be an order of magnitude +/// faster (or more). +/// +/// # Example +/// +/// This shows how to find the last position of a byte in a byte string. +/// +/// ``` +/// use memchr::memrchr; +/// +/// let haystack = b"the quick brown fox"; +/// assert_eq!(memrchr(b'o', haystack), Some(17)); +/// ``` +#[inline] +pub fn memrchr(needle: u8, haystack: &[u8]) -> Option { + // SAFETY: memrchr_raw, when a match is found, always returns a valid + // pointer between start and end. + unsafe { + generic::search_slice_with_raw(haystack, |start, end| { + memrchr_raw(needle, start, end) + }) + } +} + +/// Search for the first occurrence of two possible bytes in a haystack. +/// +/// This returns the index corresponding to the first occurrence of one of the +/// needle bytes in `haystack`, or `None` if one is not found. If an index is +/// returned, it is guaranteed to be less than `haystack.len()`. +/// +/// While this is semantically the same as something like +/// `haystack.iter().position(|&b| b == needle1 || b == needle2)`, this routine +/// will attempt to use highly optimized vector operations that can be an order +/// of magnitude faster (or more). +/// +/// # Example +/// +/// This shows how to find the first position of one of two possible bytes in a +/// haystack. +/// +/// ``` +/// use memchr::memchr2; +/// +/// let haystack = b"the quick brown fox"; +/// assert_eq!(memchr2(b'k', b'q', haystack), Some(4)); +/// ``` +#[inline] +pub fn memchr2(needle1: u8, needle2: u8, haystack: &[u8]) -> Option { + // SAFETY: memchr2_raw, when a match is found, always returns a valid + // pointer between start and end. + unsafe { + generic::search_slice_with_raw(haystack, |start, end| { + memchr2_raw(needle1, needle2, start, end) + }) + } +} + +/// Search for the last occurrence of two possible bytes in a haystack. +/// +/// This returns the index corresponding to the last occurrence of one of the +/// needle bytes in `haystack`, or `None` if one is not found. If an index is +/// returned, it is guaranteed to be less than `haystack.len()`. +/// +/// While this is semantically the same as something like +/// `haystack.iter().rposition(|&b| b == needle1 || b == needle2)`, this +/// routine will attempt to use highly optimized vector operations that can be +/// an order of magnitude faster (or more). +/// +/// # Example +/// +/// This shows how to find the last position of one of two possible bytes in a +/// haystack. +/// +/// ``` +/// use memchr::memrchr2; +/// +/// let haystack = b"the quick brown fox"; +/// assert_eq!(memrchr2(b'k', b'o', haystack), Some(17)); +/// ``` +#[inline] +pub fn memrchr2(needle1: u8, needle2: u8, haystack: &[u8]) -> Option { + // SAFETY: memrchr2_raw, when a match is found, always returns a valid + // pointer between start and end. + unsafe { + generic::search_slice_with_raw(haystack, |start, end| { + memrchr2_raw(needle1, needle2, start, end) + }) + } +} + +/// Search for the first occurrence of three possible bytes in a haystack. +/// +/// This returns the index corresponding to the first occurrence of one of the +/// needle bytes in `haystack`, or `None` if one is not found. If an index is +/// returned, it is guaranteed to be less than `haystack.len()`. +/// +/// While this is semantically the same as something like +/// `haystack.iter().position(|&b| b == needle1 || b == needle2 || b == needle3)`, +/// this routine will attempt to use highly optimized vector operations that +/// can be an order of magnitude faster (or more). +/// +/// # Example +/// +/// This shows how to find the first position of one of three possible bytes in +/// a haystack. +/// +/// ``` +/// use memchr::memchr3; +/// +/// let haystack = b"the quick brown fox"; +/// assert_eq!(memchr3(b'k', b'q', b'u', haystack), Some(4)); +/// ``` +#[inline] +pub fn memchr3( + needle1: u8, + needle2: u8, + needle3: u8, + haystack: &[u8], +) -> Option { + // SAFETY: memchr3_raw, when a match is found, always returns a valid + // pointer between start and end. + unsafe { + generic::search_slice_with_raw(haystack, |start, end| { + memchr3_raw(needle1, needle2, needle3, start, end) + }) + } +} + +/// Search for the last occurrence of three possible bytes in a haystack. +/// +/// This returns the index corresponding to the last occurrence of one of the +/// needle bytes in `haystack`, or `None` if one is not found. If an index is +/// returned, it is guaranteed to be less than `haystack.len()`. +/// +/// While this is semantically the same as something like +/// `haystack.iter().rposition(|&b| b == needle1 || b == needle2 || b == needle3)`, +/// this routine will attempt to use highly optimized vector operations that +/// can be an order of magnitude faster (or more). +/// +/// # Example +/// +/// This shows how to find the last position of one of three possible bytes in +/// a haystack. +/// +/// ``` +/// use memchr::memrchr3; +/// +/// let haystack = b"the quick brown fox"; +/// assert_eq!(memrchr3(b'k', b'o', b'n', haystack), Some(17)); +/// ``` +#[inline] +pub fn memrchr3( + needle1: u8, + needle2: u8, + needle3: u8, + haystack: &[u8], +) -> Option { + // SAFETY: memrchr3_raw, when a match is found, always returns a valid + // pointer between start and end. + unsafe { + generic::search_slice_with_raw(haystack, |start, end| { + memrchr3_raw(needle1, needle2, needle3, start, end) + }) + } +} + +/// Returns an iterator over all occurrences of the needle in a haystack. +/// +/// The iterator returned implements `DoubleEndedIterator`. This means it +/// can also be used to find occurrences in reverse order. +#[inline] +pub fn memchr_iter<'h>(needle: u8, haystack: &'h [u8]) -> Memchr<'h> { + Memchr::new(needle, haystack) +} + +/// Returns an iterator over all occurrences of the needle in a haystack, in +/// reverse. +#[inline] +pub fn memrchr_iter(needle: u8, haystack: &[u8]) -> Rev> { + Memchr::new(needle, haystack).rev() +} + +/// Returns an iterator over all occurrences of the needles in a haystack. +/// +/// The iterator returned implements `DoubleEndedIterator`. This means it +/// can also be used to find occurrences in reverse order. +#[inline] +pub fn memchr2_iter<'h>( + needle1: u8, + needle2: u8, + haystack: &'h [u8], +) -> Memchr2<'h> { + Memchr2::new(needle1, needle2, haystack) +} + +/// Returns an iterator over all occurrences of the needles in a haystack, in +/// reverse. +#[inline] +pub fn memrchr2_iter( + needle1: u8, + needle2: u8, + haystack: &[u8], +) -> Rev> { + Memchr2::new(needle1, needle2, haystack).rev() +} + +/// Returns an iterator over all occurrences of the needles in a haystack. +/// +/// The iterator returned implements `DoubleEndedIterator`. This means it +/// can also be used to find occurrences in reverse order. +#[inline] +pub fn memchr3_iter<'h>( + needle1: u8, + needle2: u8, + needle3: u8, + haystack: &'h [u8], +) -> Memchr3<'h> { + Memchr3::new(needle1, needle2, needle3, haystack) +} + +/// Returns an iterator over all occurrences of the needles in a haystack, in +/// reverse. +#[inline] +pub fn memrchr3_iter( + needle1: u8, + needle2: u8, + needle3: u8, + haystack: &[u8], +) -> Rev> { + Memchr3::new(needle1, needle2, needle3, haystack).rev() +} + +/// An iterator over all occurrences of a single byte in a haystack. +/// +/// This iterator implements `DoubleEndedIterator`, which means it can also be +/// used to find occurrences in reverse order. +/// +/// This iterator is created by the [`memchr_iter`] or `[memrchr_iter`] +/// functions. It can also be created with the [`Memchr::new`] method. +/// +/// The lifetime parameter `'h` refers to the lifetime of the haystack being +/// searched. +#[derive(Clone, Debug)] +pub struct Memchr<'h> { + needle1: u8, + it: crate::arch::generic::memchr::Iter<'h>, +} + +impl<'h> Memchr<'h> { + /// Returns an iterator over all occurrences of the needle byte in the + /// given haystack. + /// + /// The iterator returned implements `DoubleEndedIterator`. This means it + /// can also be used to find occurrences in reverse order. + #[inline] + pub fn new(needle1: u8, haystack: &'h [u8]) -> Memchr<'h> { + Memchr { + needle1, + it: crate::arch::generic::memchr::Iter::new(haystack), + } + } +} + +impl<'h> Iterator for Memchr<'h> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + // SAFETY: All of our implementations of memchr ensure that any + // pointers returns will fall within the start and end bounds, and this + // upholds the safety contract of `self.it.next`. + unsafe { + // NOTE: I attempted to define an enum of previously created + // searchers and then switch on those here instead of just + // calling `memchr_raw` (or `One::new(..).find_raw(..)`). But + // that turned out to have a fair bit of extra overhead when + // searching very small haystacks. + self.it.next(|s, e| memchr_raw(self.needle1, s, e)) + } + } + + #[inline] + fn count(self) -> usize { + self.it.count(|s, e| { + // SAFETY: We rely on our generic iterator to return valid start + // and end pointers. + unsafe { count_raw(self.needle1, s, e) } + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'h> DoubleEndedIterator for Memchr<'h> { + #[inline] + fn next_back(&mut self) -> Option { + // SAFETY: All of our implementations of memchr ensure that any + // pointers returns will fall within the start and end bounds, and this + // upholds the safety contract of `self.it.next_back`. + unsafe { self.it.next_back(|s, e| memrchr_raw(self.needle1, s, e)) } + } +} + +impl<'h> core::iter::FusedIterator for Memchr<'h> {} + +/// An iterator over all occurrences of two possible bytes in a haystack. +/// +/// This iterator implements `DoubleEndedIterator`, which means it can also be +/// used to find occurrences in reverse order. +/// +/// This iterator is created by the [`memchr2_iter`] or `[memrchr2_iter`] +/// functions. It can also be created with the [`Memchr2::new`] method. +/// +/// The lifetime parameter `'h` refers to the lifetime of the haystack being +/// searched. +#[derive(Clone, Debug)] +pub struct Memchr2<'h> { + needle1: u8, + needle2: u8, + it: crate::arch::generic::memchr::Iter<'h>, +} + +impl<'h> Memchr2<'h> { + /// Returns an iterator over all occurrences of the needle bytes in the + /// given haystack. + /// + /// The iterator returned implements `DoubleEndedIterator`. This means it + /// can also be used to find occurrences in reverse order. + #[inline] + pub fn new(needle1: u8, needle2: u8, haystack: &'h [u8]) -> Memchr2<'h> { + Memchr2 { + needle1, + needle2, + it: crate::arch::generic::memchr::Iter::new(haystack), + } + } +} + +impl<'h> Iterator for Memchr2<'h> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + // SAFETY: All of our implementations of memchr ensure that any + // pointers returns will fall within the start and end bounds, and this + // upholds the safety contract of `self.it.next`. + unsafe { + self.it.next(|s, e| memchr2_raw(self.needle1, self.needle2, s, e)) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'h> DoubleEndedIterator for Memchr2<'h> { + #[inline] + fn next_back(&mut self) -> Option { + // SAFETY: All of our implementations of memchr ensure that any + // pointers returns will fall within the start and end bounds, and this + // upholds the safety contract of `self.it.next_back`. + unsafe { + self.it.next_back(|s, e| { + memrchr2_raw(self.needle1, self.needle2, s, e) + }) + } + } +} + +impl<'h> core::iter::FusedIterator for Memchr2<'h> {} + +/// An iterator over all occurrences of three possible bytes in a haystack. +/// +/// This iterator implements `DoubleEndedIterator`, which means it can also be +/// used to find occurrences in reverse order. +/// +/// This iterator is created by the [`memchr2_iter`] or `[memrchr2_iter`] +/// functions. It can also be created with the [`Memchr3::new`] method. +/// +/// The lifetime parameter `'h` refers to the lifetime of the haystack being +/// searched. +#[derive(Clone, Debug)] +pub struct Memchr3<'h> { + needle1: u8, + needle2: u8, + needle3: u8, + it: crate::arch::generic::memchr::Iter<'h>, +} + +impl<'h> Memchr3<'h> { + /// Returns an iterator over all occurrences of the needle bytes in the + /// given haystack. + /// + /// The iterator returned implements `DoubleEndedIterator`. This means it + /// can also be used to find occurrences in reverse order. + #[inline] + pub fn new( + needle1: u8, + needle2: u8, + needle3: u8, + haystack: &'h [u8], + ) -> Memchr3<'h> { + Memchr3 { + needle1, + needle2, + needle3, + it: crate::arch::generic::memchr::Iter::new(haystack), + } + } +} + +impl<'h> Iterator for Memchr3<'h> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + // SAFETY: All of our implementations of memchr ensure that any + // pointers returns will fall within the start and end bounds, and this + // upholds the safety contract of `self.it.next`. + unsafe { + self.it.next(|s, e| { + memchr3_raw(self.needle1, self.needle2, self.needle3, s, e) + }) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'h> DoubleEndedIterator for Memchr3<'h> { + #[inline] + fn next_back(&mut self) -> Option { + // SAFETY: All of our implementations of memchr ensure that any + // pointers returns will fall within the start and end bounds, and this + // upholds the safety contract of `self.it.next_back`. + unsafe { + self.it.next_back(|s, e| { + memrchr3_raw(self.needle1, self.needle2, self.needle3, s, e) + }) + } + } +} + +impl<'h> core::iter::FusedIterator for Memchr3<'h> {} + +/// memchr, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `One::find_raw`. +#[inline] +unsafe fn memchr_raw( + needle: u8, + start: *const u8, + end: *const u8, +) -> Option<*const u8> { + #[cfg(target_arch = "x86_64")] + { + // x86_64 does CPU feature detection at runtime in order to use AVX2 + // instructions even when the `avx2` feature isn't enabled at compile + // time. This function also handles using a fallback if neither AVX2 + // nor SSE2 (unusual) are available. + crate::arch::x86_64::memchr::memchr_raw(needle, start, end) + } + #[cfg(all(target_arch = "wasm32", target_feature = "simd128"))] + { + crate::arch::wasm32::memchr::memchr_raw(needle, start, end) + } + #[cfg(target_arch = "aarch64")] + { + crate::arch::aarch64::memchr::memchr_raw(needle, start, end) + } + #[cfg(not(any( + target_arch = "x86_64", + all(target_arch = "wasm32", target_feature = "simd128"), + target_arch = "aarch64" + )))] + { + crate::arch::all::memchr::One::new(needle).find_raw(start, end) + } +} + +/// memrchr, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `One::rfind_raw`. +#[inline] +unsafe fn memrchr_raw( + needle: u8, + start: *const u8, + end: *const u8, +) -> Option<*const u8> { + #[cfg(target_arch = "x86_64")] + { + crate::arch::x86_64::memchr::memrchr_raw(needle, start, end) + } + #[cfg(all(target_arch = "wasm32", target_feature = "simd128"))] + { + crate::arch::wasm32::memchr::memrchr_raw(needle, start, end) + } + #[cfg(target_arch = "aarch64")] + { + crate::arch::aarch64::memchr::memrchr_raw(needle, start, end) + } + #[cfg(not(any( + target_arch = "x86_64", + all(target_arch = "wasm32", target_feature = "simd128"), + target_arch = "aarch64" + )))] + { + crate::arch::all::memchr::One::new(needle).rfind_raw(start, end) + } +} + +/// memchr2, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `Two::find_raw`. +#[inline] +unsafe fn memchr2_raw( + needle1: u8, + needle2: u8, + start: *const u8, + end: *const u8, +) -> Option<*const u8> { + #[cfg(target_arch = "x86_64")] + { + crate::arch::x86_64::memchr::memchr2_raw(needle1, needle2, start, end) + } + #[cfg(all(target_arch = "wasm32", target_feature = "simd128"))] + { + crate::arch::wasm32::memchr::memchr2_raw(needle1, needle2, start, end) + } + #[cfg(target_arch = "aarch64")] + { + crate::arch::aarch64::memchr::memchr2_raw(needle1, needle2, start, end) + } + #[cfg(not(any( + target_arch = "x86_64", + all(target_arch = "wasm32", target_feature = "simd128"), + target_arch = "aarch64" + )))] + { + crate::arch::all::memchr::Two::new(needle1, needle2) + .find_raw(start, end) + } +} + +/// memrchr2, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `Two::rfind_raw`. +#[inline] +unsafe fn memrchr2_raw( + needle1: u8, + needle2: u8, + start: *const u8, + end: *const u8, +) -> Option<*const u8> { + #[cfg(target_arch = "x86_64")] + { + crate::arch::x86_64::memchr::memrchr2_raw(needle1, needle2, start, end) + } + #[cfg(all(target_arch = "wasm32", target_feature = "simd128"))] + { + crate::arch::wasm32::memchr::memrchr2_raw(needle1, needle2, start, end) + } + #[cfg(target_arch = "aarch64")] + { + crate::arch::aarch64::memchr::memrchr2_raw( + needle1, needle2, start, end, + ) + } + #[cfg(not(any( + target_arch = "x86_64", + all(target_arch = "wasm32", target_feature = "simd128"), + target_arch = "aarch64" + )))] + { + crate::arch::all::memchr::Two::new(needle1, needle2) + .rfind_raw(start, end) + } +} + +/// memchr3, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `Three::find_raw`. +#[inline] +unsafe fn memchr3_raw( + needle1: u8, + needle2: u8, + needle3: u8, + start: *const u8, + end: *const u8, +) -> Option<*const u8> { + #[cfg(target_arch = "x86_64")] + { + crate::arch::x86_64::memchr::memchr3_raw( + needle1, needle2, needle3, start, end, + ) + } + #[cfg(all(target_arch = "wasm32", target_feature = "simd128"))] + { + crate::arch::wasm32::memchr::memchr3_raw( + needle1, needle2, needle3, start, end, + ) + } + #[cfg(target_arch = "aarch64")] + { + crate::arch::aarch64::memchr::memchr3_raw( + needle1, needle2, needle3, start, end, + ) + } + #[cfg(not(any( + target_arch = "x86_64", + all(target_arch = "wasm32", target_feature = "simd128"), + target_arch = "aarch64" + )))] + { + crate::arch::all::memchr::Three::new(needle1, needle2, needle3) + .find_raw(start, end) + } +} + +/// memrchr3, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `Three::rfind_raw`. +#[inline] +unsafe fn memrchr3_raw( + needle1: u8, + needle2: u8, + needle3: u8, + start: *const u8, + end: *const u8, +) -> Option<*const u8> { + #[cfg(target_arch = "x86_64")] + { + crate::arch::x86_64::memchr::memrchr3_raw( + needle1, needle2, needle3, start, end, + ) + } + #[cfg(all(target_arch = "wasm32", target_feature = "simd128"))] + { + crate::arch::wasm32::memchr::memrchr3_raw( + needle1, needle2, needle3, start, end, + ) + } + #[cfg(target_arch = "aarch64")] + { + crate::arch::aarch64::memchr::memrchr3_raw( + needle1, needle2, needle3, start, end, + ) + } + #[cfg(not(any( + target_arch = "x86_64", + all(target_arch = "wasm32", target_feature = "simd128"), + target_arch = "aarch64" + )))] + { + crate::arch::all::memchr::Three::new(needle1, needle2, needle3) + .rfind_raw(start, end) + } +} + +/// Count all matching bytes, but using raw pointers to represent the haystack. +/// +/// # Safety +/// +/// Pointers must be valid. See `One::count_raw`. +#[inline] +unsafe fn count_raw(needle: u8, start: *const u8, end: *const u8) -> usize { + #[cfg(target_arch = "x86_64")] + { + crate::arch::x86_64::memchr::count_raw(needle, start, end) + } + #[cfg(all(target_arch = "wasm32", target_feature = "simd128"))] + { + crate::arch::wasm32::memchr::count_raw(needle, start, end) + } + #[cfg(target_arch = "aarch64")] + { + crate::arch::aarch64::memchr::count_raw(needle, start, end) + } + #[cfg(not(any( + target_arch = "x86_64", + all(target_arch = "wasm32", target_feature = "simd128"), + target_arch = "aarch64" + )))] + { + crate::arch::all::memchr::One::new(needle).count_raw(start, end) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn forward1_iter() { + crate::tests::memchr::Runner::new(1).forward_iter( + |haystack, needles| { + Some(memchr_iter(needles[0], haystack).collect()) + }, + ) + } + + #[test] + fn forward1_oneshot() { + crate::tests::memchr::Runner::new(1).forward_oneshot( + |haystack, needles| Some(memchr(needles[0], haystack)), + ) + } + + #[test] + fn reverse1_iter() { + crate::tests::memchr::Runner::new(1).reverse_iter( + |haystack, needles| { + Some(memrchr_iter(needles[0], haystack).collect()) + }, + ) + } + + #[test] + fn reverse1_oneshot() { + crate::tests::memchr::Runner::new(1).reverse_oneshot( + |haystack, needles| Some(memrchr(needles[0], haystack)), + ) + } + + #[test] + fn count1_iter() { + crate::tests::memchr::Runner::new(1).count_iter(|haystack, needles| { + Some(memchr_iter(needles[0], haystack).count()) + }) + } + + #[test] + fn forward2_iter() { + crate::tests::memchr::Runner::new(2).forward_iter( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + Some(memchr2_iter(n1, n2, haystack).collect()) + }, + ) + } + + #[test] + fn forward2_oneshot() { + crate::tests::memchr::Runner::new(2).forward_oneshot( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + Some(memchr2(n1, n2, haystack)) + }, + ) + } + + #[test] + fn reverse2_iter() { + crate::tests::memchr::Runner::new(2).reverse_iter( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + Some(memrchr2_iter(n1, n2, haystack).collect()) + }, + ) + } + + #[test] + fn reverse2_oneshot() { + crate::tests::memchr::Runner::new(2).reverse_oneshot( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + Some(memrchr2(n1, n2, haystack)) + }, + ) + } + + #[test] + fn forward3_iter() { + crate::tests::memchr::Runner::new(3).forward_iter( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + let n3 = needles.get(2).copied()?; + Some(memchr3_iter(n1, n2, n3, haystack).collect()) + }, + ) + } + + #[test] + fn forward3_oneshot() { + crate::tests::memchr::Runner::new(3).forward_oneshot( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + let n3 = needles.get(2).copied()?; + Some(memchr3(n1, n2, n3, haystack)) + }, + ) + } + + #[test] + fn reverse3_iter() { + crate::tests::memchr::Runner::new(3).reverse_iter( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + let n3 = needles.get(2).copied()?; + Some(memrchr3_iter(n1, n2, n3, haystack).collect()) + }, + ) + } + + #[test] + fn reverse3_oneshot() { + crate::tests::memchr::Runner::new(3).reverse_oneshot( + |haystack, needles| { + let n1 = needles.get(0).copied()?; + let n2 = needles.get(1).copied()?; + let n3 = needles.get(2).copied()?; + Some(memrchr3(n1, n2, n3, haystack)) + }, + ) + } + + // Prior to memchr 2.6, the memchr iterators both implemented Send and + // Sync. But in memchr 2.6, the iterator changed to use raw pointers + // internally and I didn't add explicit Send/Sync impls. This ended up + // regressing the API. This test ensures we don't do that again. + // + // See: https://github.com/BurntSushi/memchr/issues/133 + #[test] + fn sync_regression() { + use core::panic::{RefUnwindSafe, UnwindSafe}; + + fn assert_send_sync() {} + assert_send_sync::(); + assert_send_sync::(); + assert_send_sync::() + } +} diff --git a/third_party/crates/memchr-2.8.3/src/memmem/mod.rs b/third_party/crates/memchr-2.8.3/src/memmem/mod.rs new file mode 100644 index 0000000..ab19a9d --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/memmem/mod.rs @@ -0,0 +1,767 @@ +/*! +This module provides forward and reverse substring search routines. + +Unlike the standard library's substring search routines, these work on +arbitrary bytes. For all non-empty needles, these routines will report exactly +the same values as the corresponding routines in the standard library. For +the empty needle, the standard library reports matches only at valid UTF-8 +boundaries, where as these routines will report matches at every position. + +Other than being able to work on arbitrary bytes, the primary reason to prefer +these routines over the standard library routines is that these will generally +be faster. In some cases, significantly so. + +# Example: iterating over substring matches + +This example shows how to use [`find_iter`] to find occurrences of a substring +in a haystack. + +``` +use memchr::memmem; + +let haystack = b"foo bar foo baz foo"; + +let mut it = memmem::find_iter(haystack, "foo"); +assert_eq!(Some(0), it.next()); +assert_eq!(Some(8), it.next()); +assert_eq!(Some(16), it.next()); +assert_eq!(None, it.next()); +``` + +# Example: iterating over substring matches in reverse + +This example shows how to use [`rfind_iter`] to find occurrences of a substring +in a haystack starting from the end of the haystack. + +**NOTE:** This module does not implement double ended iterators, so reverse +searches aren't done by calling `rev` on a forward iterator. + +``` +use memchr::memmem; + +let haystack = b"foo bar foo baz foo"; + +let mut it = memmem::rfind_iter(haystack, "foo"); +assert_eq!(Some(16), it.next()); +assert_eq!(Some(8), it.next()); +assert_eq!(Some(0), it.next()); +assert_eq!(None, it.next()); +``` + +# Example: repeating a search for the same needle + +It may be possible for the overhead of constructing a substring searcher to be +measurable in some workloads. In cases where the same needle is used to search +many haystacks, it is possible to do construction once and thus to avoid it for +subsequent searches. This can be done with a [`Finder`] (or a [`FinderRev`] for +reverse searches). + +``` +use memchr::memmem; + +let finder = memmem::Finder::new("foo"); + +assert_eq!(Some(4), finder.find(b"baz foo quux")); +assert_eq!(None, finder.find(b"quux baz bar")); +``` +*/ + +pub use crate::memmem::searcher::PrefilterConfig as Prefilter; + +// This is exported here for use in the crate::arch::all::twoway +// implementation. This is essentially an abstraction breaker. Namely, the +// public API of twoway doesn't support providing a prefilter, but its crate +// internal API does. The main reason for this is that I didn't want to do the +// API design required to support it without a concrete use case. +pub(crate) use crate::memmem::searcher::Pre; + +use crate::{ + arch::all::{ + packedpair::{DefaultFrequencyRank, HeuristicFrequencyRank}, + rabinkarp, + }, + cow::CowBytes, + memmem::searcher::{PrefilterState, Searcher, SearcherRev}, +}; + +mod searcher; + +/// Returns an iterator over all non-overlapping occurrences of a substring in +/// a haystack. +/// +/// # Complexity +/// +/// This routine is guaranteed to have worst case linear time complexity +/// with respect to both the needle and the haystack. That is, this runs +/// in `O(needle.len() + haystack.len())` time. +/// +/// This routine is also guaranteed to have worst case constant space +/// complexity. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use memchr::memmem; +/// +/// let haystack = b"foo bar foo baz foo"; +/// let mut it = memmem::find_iter(haystack, b"foo"); +/// assert_eq!(Some(0), it.next()); +/// assert_eq!(Some(8), it.next()); +/// assert_eq!(Some(16), it.next()); +/// assert_eq!(None, it.next()); +/// ``` +#[inline] +pub fn find_iter<'h, 'n, N: 'n + ?Sized + AsRef<[u8]>>( + haystack: &'h [u8], + needle: &'n N, +) -> FindIter<'h, 'n> { + FindIter::new(haystack, Finder::new(needle)) +} + +/// Returns a reverse iterator over all non-overlapping occurrences of a +/// substring in a haystack. +/// +/// # Complexity +/// +/// This routine is guaranteed to have worst case linear time complexity +/// with respect to both the needle and the haystack. That is, this runs +/// in `O(needle.len() + haystack.len())` time. +/// +/// This routine is also guaranteed to have worst case constant space +/// complexity. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use memchr::memmem; +/// +/// let haystack = b"foo bar foo baz foo"; +/// let mut it = memmem::rfind_iter(haystack, b"foo"); +/// assert_eq!(Some(16), it.next()); +/// assert_eq!(Some(8), it.next()); +/// assert_eq!(Some(0), it.next()); +/// assert_eq!(None, it.next()); +/// ``` +#[inline] +pub fn rfind_iter<'h, 'n, N: 'n + ?Sized + AsRef<[u8]>>( + haystack: &'h [u8], + needle: &'n N, +) -> FindRevIter<'h, 'n> { + FindRevIter::new(haystack, FinderRev::new(needle)) +} + +/// Returns the index of the first occurrence of the given needle. +/// +/// Note that if you're are searching for the same needle in many different +/// small haystacks, it may be faster to initialize a [`Finder`] once, +/// and reuse it for each search. +/// +/// # Complexity +/// +/// This routine is guaranteed to have worst case linear time complexity +/// with respect to both the needle and the haystack. That is, this runs +/// in `O(needle.len() + haystack.len())` time. +/// +/// This routine is also guaranteed to have worst case constant space +/// complexity. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use memchr::memmem; +/// +/// let haystack = b"foo bar baz"; +/// assert_eq!(Some(0), memmem::find(haystack, b"foo")); +/// assert_eq!(Some(4), memmem::find(haystack, b"bar")); +/// assert_eq!(None, memmem::find(haystack, b"quux")); +/// ``` +#[inline] +pub fn find(haystack: &[u8], needle: &[u8]) -> Option { + if haystack.len() < 64 { + rabinkarp::Finder::new(needle).find(haystack, needle) + } else { + Finder::new(needle).find(haystack) + } +} + +/// Returns the index of the last occurrence of the given needle. +/// +/// Note that if you're are searching for the same needle in many different +/// small haystacks, it may be faster to initialize a [`FinderRev`] once, +/// and reuse it for each search. +/// +/// # Complexity +/// +/// This routine is guaranteed to have worst case linear time complexity +/// with respect to both the needle and the haystack. That is, this runs +/// in `O(needle.len() + haystack.len())` time. +/// +/// This routine is also guaranteed to have worst case constant space +/// complexity. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use memchr::memmem; +/// +/// let haystack = b"foo bar baz"; +/// assert_eq!(Some(0), memmem::rfind(haystack, b"foo")); +/// assert_eq!(Some(4), memmem::rfind(haystack, b"bar")); +/// assert_eq!(Some(8), memmem::rfind(haystack, b"ba")); +/// assert_eq!(None, memmem::rfind(haystack, b"quux")); +/// ``` +#[inline] +pub fn rfind(haystack: &[u8], needle: &[u8]) -> Option { + if haystack.len() < 64 { + rabinkarp::FinderRev::new(needle).rfind(haystack, needle) + } else { + FinderRev::new(needle).rfind(haystack) + } +} + +/// An iterator over non-overlapping substring matches. +/// +/// Matches are reported by the byte offset at which they begin. +/// +/// `'h` is the lifetime of the haystack while `'n` is the lifetime of the +/// needle. +#[derive(Debug, Clone)] +pub struct FindIter<'h, 'n> { + haystack: &'h [u8], + prestate: PrefilterState, + finder: Finder<'n>, + pos: usize, +} + +impl<'h, 'n> FindIter<'h, 'n> { + #[inline(always)] + pub(crate) fn new( + haystack: &'h [u8], + finder: Finder<'n>, + ) -> FindIter<'h, 'n> { + let prestate = PrefilterState::new(); + FindIter { haystack, prestate, finder, pos: 0 } + } + + /// Convert this iterator into its owned variant, such that it no longer + /// borrows the finder and needle. + /// + /// If this is already an owned iterator, then this is a no-op. Otherwise, + /// this copies the needle. + /// + /// This is only available when the `alloc` feature is enabled. + #[cfg(feature = "alloc")] + #[inline] + pub fn into_owned(self) -> FindIter<'h, 'static> { + FindIter { + haystack: self.haystack, + prestate: self.prestate, + finder: self.finder.into_owned(), + pos: self.pos, + } + } +} + +impl<'h, 'n> Iterator for FindIter<'h, 'n> { + type Item = usize; + + fn next(&mut self) -> Option { + let needle = self.finder.needle(); + let haystack = self.haystack.get(self.pos..)?; + let idx = + self.finder.searcher.find(&mut self.prestate, haystack, needle)?; + + let pos = self.pos + idx; + self.pos = pos + needle.len().max(1); + + Some(pos) + } + + fn size_hint(&self) -> (usize, Option) { + // The largest possible number of non-overlapping matches is the + // quotient of the haystack and the needle (or the length of the + // haystack, if the needle is empty) + match self.haystack.len().checked_sub(self.pos) { + None => (0, Some(0)), + Some(haystack_len) => match self.finder.needle().len() { + // Empty needles always succeed and match at every point + // (including the very end) + 0 => ( + haystack_len.saturating_add(1), + haystack_len.checked_add(1), + ), + needle_len => (0, Some(haystack_len / needle_len)), + }, + } + } +} + +/// An iterator over non-overlapping substring matches in reverse. +/// +/// Matches are reported by the byte offset at which they begin. +/// +/// `'h` is the lifetime of the haystack while `'n` is the lifetime of the +/// needle. +#[derive(Clone, Debug)] +pub struct FindRevIter<'h, 'n> { + haystack: &'h [u8], + finder: FinderRev<'n>, + /// When searching with an empty needle, this gets set to `None` after + /// we've yielded the last element at `0`. + pos: Option, +} + +impl<'h, 'n> FindRevIter<'h, 'n> { + #[inline(always)] + pub(crate) fn new( + haystack: &'h [u8], + finder: FinderRev<'n>, + ) -> FindRevIter<'h, 'n> { + let pos = Some(haystack.len()); + FindRevIter { haystack, finder, pos } + } + + /// Convert this iterator into its owned variant, such that it no longer + /// borrows the finder and needle. + /// + /// If this is already an owned iterator, then this is a no-op. Otherwise, + /// this copies the needle. + /// + /// This is only available when the `std` feature is enabled. + #[cfg(feature = "alloc")] + #[inline] + pub fn into_owned(self) -> FindRevIter<'h, 'static> { + FindRevIter { + haystack: self.haystack, + finder: self.finder.into_owned(), + pos: self.pos, + } + } +} + +impl<'h, 'n> Iterator for FindRevIter<'h, 'n> { + type Item = usize; + + fn next(&mut self) -> Option { + let pos = self.pos?; + let result = self.finder.rfind(&self.haystack[..pos]); + match result { + None => None, + Some(i) => { + if pos == i { + self.pos = pos.checked_sub(1); + } else { + self.pos = Some(i); + } + Some(i) + } + } + } +} + +/// A single substring searcher fixed to a particular needle. +/// +/// The purpose of this type is to permit callers to construct a substring +/// searcher that can be used to search haystacks without the overhead of +/// constructing the searcher in the first place. This is a somewhat niche +/// concern when it's necessary to re-use the same needle to search multiple +/// different haystacks with as little overhead as possible. In general, using +/// [`find`] is good enough, but `Finder` is useful when you can meaningfully +/// observe searcher construction time in a profile. +/// +/// When the `std` feature is enabled, then this type has an `into_owned` +/// version which permits building a `Finder` that is not connected to +/// the lifetime of its needle. +#[derive(Clone, Debug)] +pub struct Finder<'n> { + needle: CowBytes<'n>, + searcher: Searcher, +} + +impl<'n> Finder<'n> { + /// Create a new finder for the given needle. + #[inline] + pub fn new>(needle: &'n B) -> Finder<'n> { + FinderBuilder::new().build_forward(needle) + } + + /// Returns the index of the first occurrence of this needle in the given + /// haystack. + /// + /// # Complexity + /// + /// This routine is guaranteed to have worst case linear time complexity + /// with respect to both the needle and the haystack. That is, this runs + /// in `O(needle.len() + haystack.len())` time. + /// + /// This routine is also guaranteed to have worst case constant space + /// complexity. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use memchr::memmem::Finder; + /// + /// let haystack = b"foo bar baz"; + /// assert_eq!(Some(0), Finder::new("foo").find(haystack)); + /// assert_eq!(Some(4), Finder::new("bar").find(haystack)); + /// assert_eq!(None, Finder::new("quux").find(haystack)); + /// ``` + #[inline] + pub fn find(&self, haystack: &[u8]) -> Option { + let mut prestate = PrefilterState::new(); + let needle = self.needle.as_slice(); + self.searcher.find(&mut prestate, haystack, needle) + } + + /// Returns an iterator over all occurrences of a substring in a haystack. + /// + /// # Complexity + /// + /// This routine is guaranteed to have worst case linear time complexity + /// with respect to both the needle and the haystack. That is, this runs + /// in `O(needle.len() + haystack.len())` time. + /// + /// This routine is also guaranteed to have worst case constant space + /// complexity. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use memchr::memmem::Finder; + /// + /// let haystack = b"foo bar foo baz foo"; + /// let finder = Finder::new(b"foo"); + /// let mut it = finder.find_iter(haystack); + /// assert_eq!(Some(0), it.next()); + /// assert_eq!(Some(8), it.next()); + /// assert_eq!(Some(16), it.next()); + /// assert_eq!(None, it.next()); + /// ``` + #[inline] + pub fn find_iter<'a, 'h>( + &'a self, + haystack: &'h [u8], + ) -> FindIter<'h, 'a> { + FindIter::new(haystack, self.as_ref()) + } + + /// Convert this finder into its owned variant, such that it no longer + /// borrows the needle. + /// + /// If this is already an owned finder, then this is a no-op. Otherwise, + /// this copies the needle. + /// + /// This is only available when the `alloc` feature is enabled. + #[cfg(feature = "alloc")] + #[inline] + pub fn into_owned(self) -> Finder<'static> { + Finder { needle: self.needle.into_owned(), searcher: self.searcher } + } + + /// Convert this finder into its borrowed variant. + /// + /// This is primarily useful if your finder is owned and you'd like to + /// store its borrowed variant in some intermediate data structure. + /// + /// Note that the lifetime parameter of the returned finder is tied to the + /// lifetime of `self`, and may be shorter than the `'n` lifetime of the + /// needle itself. Namely, a finder's needle can be either borrowed or + /// owned, so the lifetime of the needle returned must necessarily be the + /// shorter of the two. + #[inline] + pub fn as_ref(&self) -> Finder<'_> { + Finder { + needle: CowBytes::new(self.needle()), + searcher: self.searcher.clone(), + } + } + + /// Returns the needle that this finder searches for. + /// + /// Note that the lifetime of the needle returned is tied to the lifetime + /// of the finder, and may be shorter than the `'n` lifetime. Namely, a + /// finder's needle can be either borrowed or owned, so the lifetime of the + /// needle returned must necessarily be the shorter of the two. + #[inline] + pub fn needle(&self) -> &[u8] { + self.needle.as_slice() + } +} + +/// A single substring reverse searcher fixed to a particular needle. +/// +/// The purpose of this type is to permit callers to construct a substring +/// searcher that can be used to search haystacks without the overhead of +/// constructing the searcher in the first place. This is a somewhat niche +/// concern when it's necessary to re-use the same needle to search multiple +/// different haystacks with as little overhead as possible. In general, +/// using [`rfind`] is good enough, but `FinderRev` is useful when you can +/// meaningfully observe searcher construction time in a profile. +/// +/// When the `std` feature is enabled, then this type has an `into_owned` +/// version which permits building a `FinderRev` that is not connected to +/// the lifetime of its needle. +#[derive(Clone, Debug)] +pub struct FinderRev<'n> { + needle: CowBytes<'n>, + searcher: SearcherRev, +} + +impl<'n> FinderRev<'n> { + /// Create a new reverse finder for the given needle. + #[inline] + pub fn new>(needle: &'n B) -> FinderRev<'n> { + FinderBuilder::new().build_reverse(needle) + } + + /// Returns the index of the last occurrence of this needle in the given + /// haystack. + /// + /// The haystack may be any type that can be cheaply converted into a + /// `&[u8]`. This includes, but is not limited to, `&str` and `&[u8]`. + /// + /// # Complexity + /// + /// This routine is guaranteed to have worst case linear time complexity + /// with respect to both the needle and the haystack. That is, this runs + /// in `O(needle.len() + haystack.len())` time. + /// + /// This routine is also guaranteed to have worst case constant space + /// complexity. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use memchr::memmem::FinderRev; + /// + /// let haystack = b"foo bar baz"; + /// assert_eq!(Some(0), FinderRev::new("foo").rfind(haystack)); + /// assert_eq!(Some(4), FinderRev::new("bar").rfind(haystack)); + /// assert_eq!(None, FinderRev::new("quux").rfind(haystack)); + /// ``` + pub fn rfind>(&self, haystack: B) -> Option { + self.searcher.rfind(haystack.as_ref(), self.needle.as_slice()) + } + + /// Returns a reverse iterator over all occurrences of a substring in a + /// haystack. + /// + /// # Complexity + /// + /// This routine is guaranteed to have worst case linear time complexity + /// with respect to both the needle and the haystack. That is, this runs + /// in `O(needle.len() + haystack.len())` time. + /// + /// This routine is also guaranteed to have worst case constant space + /// complexity. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use memchr::memmem::FinderRev; + /// + /// let haystack = b"foo bar foo baz foo"; + /// let finder = FinderRev::new(b"foo"); + /// let mut it = finder.rfind_iter(haystack); + /// assert_eq!(Some(16), it.next()); + /// assert_eq!(Some(8), it.next()); + /// assert_eq!(Some(0), it.next()); + /// assert_eq!(None, it.next()); + /// ``` + #[inline] + pub fn rfind_iter<'a, 'h>( + &'a self, + haystack: &'h [u8], + ) -> FindRevIter<'h, 'a> { + FindRevIter::new(haystack, self.as_ref()) + } + + /// Convert this finder into its owned variant, such that it no longer + /// borrows the needle. + /// + /// If this is already an owned finder, then this is a no-op. Otherwise, + /// this copies the needle. + /// + /// This is only available when the `std` feature is enabled. + #[cfg(feature = "alloc")] + #[inline] + pub fn into_owned(self) -> FinderRev<'static> { + FinderRev { needle: self.needle.into_owned(), searcher: self.searcher } + } + + /// Convert this finder into its borrowed variant. + /// + /// This is primarily useful if your finder is owned and you'd like to + /// store its borrowed variant in some intermediate data structure. + /// + /// Note that the lifetime parameter of the returned finder is tied to the + /// lifetime of `self`, and may be shorter than the `'n` lifetime of the + /// needle itself. Namely, a finder's needle can be either borrowed or + /// owned, so the lifetime of the needle returned must necessarily be the + /// shorter of the two. + #[inline] + pub fn as_ref(&self) -> FinderRev<'_> { + FinderRev { + needle: CowBytes::new(self.needle()), + searcher: self.searcher.clone(), + } + } + + /// Returns the needle that this finder searches for. + /// + /// Note that the lifetime of the needle returned is tied to the lifetime + /// of the finder, and may be shorter than the `'n` lifetime. Namely, a + /// finder's needle can be either borrowed or owned, so the lifetime of the + /// needle returned must necessarily be the shorter of the two. + #[inline] + pub fn needle(&self) -> &[u8] { + self.needle.as_slice() + } +} + +/// A builder for constructing non-default forward or reverse memmem finders. +/// +/// A builder is primarily useful for configuring a substring searcher. +/// Currently, the only configuration exposed is the ability to disable +/// heuristic prefilters used to speed up certain searches. +#[derive(Clone, Debug, Default)] +pub struct FinderBuilder { + prefilter: Prefilter, +} + +impl FinderBuilder { + /// Create a new finder builder with default settings. + pub fn new() -> FinderBuilder { + FinderBuilder::default() + } + + /// Build a forward finder using the given needle from the current + /// settings. + pub fn build_forward<'n, B: ?Sized + AsRef<[u8]>>( + &self, + needle: &'n B, + ) -> Finder<'n> { + self.build_forward_with_ranker(DefaultFrequencyRank, needle) + } + + /// Build an owned forward finder using the given needle from the current + /// settings. + #[cfg(feature = "alloc")] + pub fn build_forward_owned>>( + &self, + needle: B, + ) -> Finder<'static> { + self.build_forward_with_ranker_owned(DefaultFrequencyRank, needle) + } + + /// Build a forward finder using the given needle and a custom heuristic + /// for determining the frequency of a given byte in the dataset. See + /// [`HeuristicFrequencyRank`] for more details. + pub fn build_forward_with_ranker< + 'n, + R: HeuristicFrequencyRank, + B: ?Sized + AsRef<[u8]>, + >( + &self, + ranker: R, + needle: &'n B, + ) -> Finder<'n> { + let needle = needle.as_ref(); + Finder { + needle: CowBytes::new(needle), + searcher: Searcher::new(self.prefilter, ranker, needle), + } + } + + /// Build an owned forward finder using the given needle and a custom + /// heuristic for determining the frequency of a given byte in the dataset. + /// See [`HeuristicFrequencyRank`] for more details. + #[cfg(feature = "alloc")] + pub fn build_forward_with_ranker_owned< + R: HeuristicFrequencyRank, + B: Into>, + >( + &self, + ranker: R, + needle: B, + ) -> Finder<'static> { + let needle = needle.into(); + let searcher = Searcher::new(self.prefilter, ranker, &needle); + Finder { needle: CowBytes::new_owned(needle), searcher } + } + + /// Build a reverse finder using the given needle from the current + /// settings. + pub fn build_reverse<'n, B: ?Sized + AsRef<[u8]>>( + &self, + needle: &'n B, + ) -> FinderRev<'n> { + let needle = needle.as_ref(); + FinderRev { + needle: CowBytes::new(needle), + searcher: SearcherRev::new(needle), + } + } + + /// Build an owned reverse finder using the given needle from the current + /// settings. + #[cfg(feature = "alloc")] + pub fn build_reverse_owned>>( + &self, + needle: B, + ) -> FinderRev<'static> { + let needle = needle.into(); + let searcher = SearcherRev::new(&needle); + FinderRev { needle: CowBytes::new_owned(needle), searcher } + } + + /// Configure the prefilter setting for the finder. + /// + /// See the documentation for [`Prefilter`] for more discussion on why + /// you might want to configure this. + pub fn prefilter(&mut self, prefilter: Prefilter) -> &mut FinderBuilder { + self.prefilter = prefilter; + self + } +} + +#[cfg(test)] +mod tests { + use super::*; + + define_substring_forward_quickcheck!(|h, n| Some(Finder::new(n).find(h))); + define_substring_reverse_quickcheck!(|h, n| Some( + FinderRev::new(n).rfind(h) + )); + + #[test] + fn forward() { + crate::tests::substring::Runner::new() + .fwd(|h, n| Some(Finder::new(n).find(h))) + .run(); + } + + #[test] + fn reverse() { + crate::tests::substring::Runner::new() + .rev(|h, n| Some(FinderRev::new(n).rfind(h))) + .run(); + } +} diff --git a/third_party/crates/memchr-2.8.3/src/memmem/searcher.rs b/third_party/crates/memchr-2.8.3/src/memmem/searcher.rs new file mode 100644 index 0000000..73ece73 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/memmem/searcher.rs @@ -0,0 +1,1028 @@ +use crate::arch::all::{ + packedpair::{HeuristicFrequencyRank, Pair}, + rabinkarp, twoway, +}; + +#[cfg(target_arch = "aarch64")] +use crate::arch::aarch64::neon::packedpair as neon; +#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))] +use crate::arch::wasm32::simd128::packedpair as simd128; +#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] +use crate::arch::x86_64::{ + avx2::packedpair as avx2, sse2::packedpair as sse2, +}; + +/// A "meta" substring searcher. +/// +/// To a first approximation, this chooses what it believes to be the "best" +/// substring search implemnetation based on the needle at construction time. +/// Then, every call to `find` will execute that particular implementation. To +/// a second approximation, multiple substring search algorithms may be used, +/// depending on the haystack. For example, for supremely short haystacks, +/// Rabin-Karp is typically used. +/// +/// See the documentation on `Prefilter` for an explanation of the dispatching +/// mechanism. The quick summary is that an enum has too much overhead and +/// we can't use dynamic dispatch via traits because we need to work in a +/// core-only environment. (Dynamic dispatch works in core-only, but you +/// need `&dyn Trait` and we really need a `Box` here. The latter +/// requires `alloc`.) So instead, we use a union and an appropriately paired +/// free function to read from the correct field on the union and execute the +/// chosen substring search implementation. +#[derive(Clone)] +pub(crate) struct Searcher { + call: SearcherKindFn, + kind: SearcherKind, + rabinkarp: rabinkarp::Finder, +} + +impl Searcher { + /// Creates a new "meta" substring searcher that attempts to choose the + /// best algorithm based on the needle, heuristics and what the current + /// target supports. + #[inline] + pub(crate) fn new( + prefilter: PrefilterConfig, + ranker: R, + needle: &[u8], + ) -> Searcher { + let rabinkarp = rabinkarp::Finder::new(needle); + if needle.len() <= 1 { + return if needle.is_empty() { + trace!("building empty substring searcher"); + Searcher { + call: searcher_kind_empty, + kind: SearcherKind { empty: () }, + rabinkarp, + } + } else { + trace!("building one-byte substring searcher"); + debug_assert_eq!(1, needle.len()); + Searcher { + call: searcher_kind_one_byte, + kind: SearcherKind { one_byte: needle[0] }, + rabinkarp, + } + }; + } + let pair = match Pair::with_ranker(needle, &ranker) { + Some(pair) => pair, + None => return Searcher::twoway(needle, rabinkarp, None), + }; + debug_assert_ne!( + pair.index1(), + pair.index2(), + "pair offsets should not be equivalent" + ); + #[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] + { + if let Some(pp) = avx2::Finder::with_pair(needle, pair) { + if do_packed_search(needle) { + trace!("building x86_64 AVX2 substring searcher"); + let kind = SearcherKind { avx2: pp }; + Searcher { call: searcher_kind_avx2, kind, rabinkarp } + } else if prefilter.is_none() { + Searcher::twoway(needle, rabinkarp, None) + } else { + let prestrat = Prefilter::avx2(pp, needle); + Searcher::twoway(needle, rabinkarp, Some(prestrat)) + } + } else if let Some(pp) = sse2::Finder::with_pair(needle, pair) { + if do_packed_search(needle) { + trace!("building x86_64 SSE2 substring searcher"); + let kind = SearcherKind { sse2: pp }; + Searcher { call: searcher_kind_sse2, kind, rabinkarp } + } else if prefilter.is_none() { + Searcher::twoway(needle, rabinkarp, None) + } else { + let prestrat = Prefilter::sse2(pp, needle); + Searcher::twoway(needle, rabinkarp, Some(prestrat)) + } + } else if prefilter.is_none() { + Searcher::twoway(needle, rabinkarp, None) + } else { + // We're pretty unlikely to get to this point, but it is + // possible to be running on x86_64 without SSE2. Namely, it's + // really up to the OS whether it wants to support vector + // registers or not. + let prestrat = Prefilter::fallback(ranker, pair, needle); + Searcher::twoway(needle, rabinkarp, prestrat) + } + } + #[cfg(all(target_arch = "wasm32", target_feature = "simd128"))] + { + if let Some(pp) = simd128::Finder::with_pair(needle, pair) { + if do_packed_search(needle) { + trace!("building wasm32 simd128 substring searcher"); + let kind = SearcherKind { simd128: pp }; + Searcher { call: searcher_kind_simd128, kind, rabinkarp } + } else if prefilter.is_none() { + Searcher::twoway(needle, rabinkarp, None) + } else { + let prestrat = Prefilter::simd128(pp, needle); + Searcher::twoway(needle, rabinkarp, Some(prestrat)) + } + } else if prefilter.is_none() { + Searcher::twoway(needle, rabinkarp, None) + } else { + let prestrat = Prefilter::fallback(ranker, pair, needle); + Searcher::twoway(needle, rabinkarp, prestrat) + } + } + #[cfg(target_arch = "aarch64")] + { + if let Some(pp) = neon::Finder::with_pair(needle, pair) { + if do_packed_search(needle) { + trace!("building aarch64 neon substring searcher"); + let kind = SearcherKind { neon: pp }; + Searcher { call: searcher_kind_neon, kind, rabinkarp } + } else if prefilter.is_none() { + Searcher::twoway(needle, rabinkarp, None) + } else { + let prestrat = Prefilter::neon(pp, needle); + Searcher::twoway(needle, rabinkarp, Some(prestrat)) + } + } else if prefilter.is_none() { + Searcher::twoway(needle, rabinkarp, None) + } else { + let prestrat = Prefilter::fallback(ranker, pair, needle); + Searcher::twoway(needle, rabinkarp, prestrat) + } + } + #[cfg(not(any( + all(target_arch = "x86_64", target_feature = "sse2"), + all(target_arch = "wasm32", target_feature = "simd128"), + target_arch = "aarch64" + )))] + { + if prefilter.is_none() { + Searcher::twoway(needle, rabinkarp, None) + } else { + let prestrat = Prefilter::fallback(ranker, pair, needle); + Searcher::twoway(needle, rabinkarp, prestrat) + } + } + } + + /// Creates a new searcher that always uses the Two-Way algorithm. This is + /// typically used when vector algorithms are unavailable or inappropriate. + /// (For example, when the needle is "too long.") + /// + /// If a prefilter is given, then the searcher returned will be accelerated + /// by the prefilter. + #[inline] + fn twoway( + needle: &[u8], + rabinkarp: rabinkarp::Finder, + prestrat: Option, + ) -> Searcher { + let finder = twoway::Finder::new(needle); + match prestrat { + None => { + trace!("building scalar two-way substring searcher"); + let kind = SearcherKind { two_way: finder }; + Searcher { call: searcher_kind_two_way, kind, rabinkarp } + } + Some(prestrat) => { + trace!( + "building scalar two-way \ + substring searcher with a prefilter" + ); + let two_way_with_prefilter = + TwoWayWithPrefilter { finder, prestrat }; + let kind = SearcherKind { two_way_with_prefilter }; + Searcher { + call: searcher_kind_two_way_with_prefilter, + kind, + rabinkarp, + } + } + } + } + + /// Searches the given haystack for the given needle. The needle given + /// should be the same as the needle that this finder was initialized + /// with. + /// + /// Inlining this can lead to big wins for latency, and #[inline] doesn't + /// seem to be enough in some cases. + #[inline(always)] + pub(crate) fn find( + &self, + prestate: &mut PrefilterState, + haystack: &[u8], + needle: &[u8], + ) -> Option { + if haystack.len() < needle.len() { + None + } else { + // SAFETY: By construction, we've ensured that the function + // in `self.call` is properly paired with the union used in + // `self.kind`. + unsafe { (self.call)(self, prestate, haystack, needle) } + } + } +} + +impl core::fmt::Debug for Searcher { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + f.debug_struct("Searcher") + .field("call", &"") + .field("kind", &"") + .field("rabinkarp", &self.rabinkarp) + .finish() + } +} + +/// A union indicating one of several possible substring search implementations +/// that are in active use. +/// +/// This union should only be read by one of the functions prefixed with +/// `searcher_kind_`. Namely, the correct function is meant to be paired with +/// the union by the caller, such that the function always reads from the +/// designated union field. +#[derive(Clone, Copy)] +union SearcherKind { + empty: (), + one_byte: u8, + two_way: twoway::Finder, + two_way_with_prefilter: TwoWayWithPrefilter, + #[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] + sse2: crate::arch::x86_64::sse2::packedpair::Finder, + #[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] + avx2: crate::arch::x86_64::avx2::packedpair::Finder, + #[cfg(all(target_arch = "wasm32", target_feature = "simd128"))] + simd128: crate::arch::wasm32::simd128::packedpair::Finder, + #[cfg(target_arch = "aarch64")] + neon: crate::arch::aarch64::neon::packedpair::Finder, +} + +/// A two-way substring searcher with a prefilter. +#[derive(Copy, Clone, Debug)] +struct TwoWayWithPrefilter { + finder: twoway::Finder, + prestrat: Prefilter, +} + +/// The type of a substring search function. +/// +/// # Safety +/// +/// When using a function of this type, callers must ensure that the correct +/// function is paired with the value populated in `SearcherKind` union. +type SearcherKindFn = unsafe fn( + searcher: &Searcher, + prestate: &mut PrefilterState, + haystack: &[u8], + needle: &[u8], +) -> Option; + +/// Reads from the `empty` field of `SearcherKind` to handle the case of +/// searching for the empty needle. Works on all platforms. +/// +/// # Safety +/// +/// Callers must ensure that the `searcher.kind.empty` union field is set. +unsafe fn searcher_kind_empty( + _searcher: &Searcher, + _prestate: &mut PrefilterState, + _haystack: &[u8], + _needle: &[u8], +) -> Option { + Some(0) +} + +/// Reads from the `one_byte` field of `SearcherKind` to handle the case of +/// searching for a single byte needle. Works on all platforms. +/// +/// # Safety +/// +/// Callers must ensure that the `searcher.kind.one_byte` union field is set. +unsafe fn searcher_kind_one_byte( + searcher: &Searcher, + _prestate: &mut PrefilterState, + haystack: &[u8], + _needle: &[u8], +) -> Option { + let needle = searcher.kind.one_byte; + crate::memchr(needle, haystack) +} + +/// Reads from the `two_way` field of `SearcherKind` to handle the case of +/// searching for an arbitrary needle without prefilter acceleration. Works on +/// all platforms. +/// +/// # Safety +/// +/// Callers must ensure that the `searcher.kind.two_way` union field is set. +unsafe fn searcher_kind_two_way( + searcher: &Searcher, + _prestate: &mut PrefilterState, + haystack: &[u8], + needle: &[u8], +) -> Option { + if rabinkarp::is_fast(haystack, needle) { + searcher.rabinkarp.find(haystack, needle) + } else { + searcher.kind.two_way.find(haystack, needle) + } +} + +/// Reads from the `two_way_with_prefilter` field of `SearcherKind` to handle +/// the case of searching for an arbitrary needle with prefilter acceleration. +/// Works on all platforms. +/// +/// # Safety +/// +/// Callers must ensure that the `searcher.kind.two_way_with_prefilter` union +/// field is set. +unsafe fn searcher_kind_two_way_with_prefilter( + searcher: &Searcher, + prestate: &mut PrefilterState, + haystack: &[u8], + needle: &[u8], +) -> Option { + if rabinkarp::is_fast(haystack, needle) { + searcher.rabinkarp.find(haystack, needle) + } else { + let TwoWayWithPrefilter { ref finder, ref prestrat } = + searcher.kind.two_way_with_prefilter; + let pre = Pre { prestate, prestrat }; + finder.find_with_prefilter(Some(pre), haystack, needle) + } +} + +/// Reads from the `sse2` field of `SearcherKind` to execute the x86_64 SSE2 +/// vectorized substring search implementation. +/// +/// # Safety +/// +/// Callers must ensure that the `searcher.kind.sse2` union field is set. +#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] +unsafe fn searcher_kind_sse2( + searcher: &Searcher, + _prestate: &mut PrefilterState, + haystack: &[u8], + needle: &[u8], +) -> Option { + let finder = &searcher.kind.sse2; + if haystack.len() < finder.min_haystack_len() { + searcher.rabinkarp.find(haystack, needle) + } else { + finder.find(haystack, needle) + } +} + +/// Reads from the `avx2` field of `SearcherKind` to execute the x86_64 AVX2 +/// vectorized substring search implementation. +/// +/// # Safety +/// +/// Callers must ensure that the `searcher.kind.avx2` union field is set. +#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] +unsafe fn searcher_kind_avx2( + searcher: &Searcher, + _prestate: &mut PrefilterState, + haystack: &[u8], + needle: &[u8], +) -> Option { + let finder = &searcher.kind.avx2; + if haystack.len() < finder.min_haystack_len() { + searcher.rabinkarp.find(haystack, needle) + } else { + finder.find(haystack, needle) + } +} + +/// Reads from the `simd128` field of `SearcherKind` to execute the wasm32 +/// simd128 vectorized substring search implementation. +/// +/// # Safety +/// +/// Callers must ensure that the `searcher.kind.simd128` union field is set. +#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))] +unsafe fn searcher_kind_simd128( + searcher: &Searcher, + _prestate: &mut PrefilterState, + haystack: &[u8], + needle: &[u8], +) -> Option { + let finder = &searcher.kind.simd128; + if haystack.len() < finder.min_haystack_len() { + searcher.rabinkarp.find(haystack, needle) + } else { + finder.find(haystack, needle) + } +} + +/// Reads from the `neon` field of `SearcherKind` to execute the aarch64 neon +/// vectorized substring search implementation. +/// +/// # Safety +/// +/// Callers must ensure that the `searcher.kind.neon` union field is set. +#[cfg(target_arch = "aarch64")] +unsafe fn searcher_kind_neon( + searcher: &Searcher, + _prestate: &mut PrefilterState, + haystack: &[u8], + needle: &[u8], +) -> Option { + let finder = &searcher.kind.neon; + if haystack.len() < finder.min_haystack_len() { + searcher.rabinkarp.find(haystack, needle) + } else { + finder.find(haystack, needle) + } +} + +/// A reverse substring searcher. +#[derive(Clone, Debug)] +pub(crate) struct SearcherRev { + kind: SearcherRevKind, + rabinkarp: rabinkarp::FinderRev, +} + +/// The kind of the reverse searcher. +/// +/// For the reverse case, we don't do any SIMD acceleration or prefilters. +/// There is no specific technical reason why we don't, but rather don't do it +/// because it's not clear it's worth the extra code to do so. If you have a +/// use case for it, please file an issue. +/// +/// We also don't do the union trick as we do with the forward case and +/// prefilters. Basically for the same reason we don't have prefilters or +/// vector algorithms for reverse searching: it's not clear it's worth doing. +/// Please file an issue if you have a compelling use case for fast reverse +/// substring search. +#[derive(Clone, Debug)] +enum SearcherRevKind { + Empty, + OneByte { needle: u8 }, + TwoWay { finder: twoway::FinderRev }, +} + +impl SearcherRev { + /// Creates a new searcher for finding occurrences of the given needle in + /// reverse. That is, it reports the last (instead of the first) occurrence + /// of a needle in a haystack. + #[inline] + pub(crate) fn new(needle: &[u8]) -> SearcherRev { + let kind = if needle.len() <= 1 { + if needle.is_empty() { + trace!("building empty reverse substring searcher"); + SearcherRevKind::Empty + } else { + trace!("building one-byte reverse substring searcher"); + debug_assert_eq!(1, needle.len()); + SearcherRevKind::OneByte { needle: needle[0] } + } + } else { + trace!("building scalar two-way reverse substring searcher"); + let finder = twoway::FinderRev::new(needle); + SearcherRevKind::TwoWay { finder } + }; + let rabinkarp = rabinkarp::FinderRev::new(needle); + SearcherRev { kind, rabinkarp } + } + + /// Searches the given haystack for the last occurrence of the given + /// needle. The needle given should be the same as the needle that this + /// finder was initialized with. + #[inline] + pub(crate) fn rfind( + &self, + haystack: &[u8], + needle: &[u8], + ) -> Option { + if haystack.len() < needle.len() { + return None; + } + match self.kind { + SearcherRevKind::Empty => Some(haystack.len()), + SearcherRevKind::OneByte { needle } => { + crate::memrchr(needle, haystack) + } + SearcherRevKind::TwoWay { ref finder } => { + if rabinkarp::is_fast(haystack, needle) { + self.rabinkarp.rfind(haystack, needle) + } else { + finder.rfind(haystack, needle) + } + } + } + } +} + +/// Prefilter controls whether heuristics are used to accelerate searching. +/// +/// A prefilter refers to the idea of detecting candidate matches very quickly, +/// and then confirming whether those candidates are full matches. This +/// idea can be quite effective since it's often the case that looking for +/// candidates can be a lot faster than running a complete substring search +/// over the entire input. Namely, looking for candidates can be done with +/// extremely fast vectorized code. +/// +/// The downside of a prefilter is that it assumes false positives (which are +/// candidates generated by a prefilter that aren't matches) are somewhat rare +/// relative to the frequency of full matches. That is, if a lot of false +/// positives are generated, then it's possible for search time to be worse +/// than if the prefilter wasn't enabled in the first place. +/// +/// Another downside of a prefilter is that it can result in highly variable +/// performance, where some cases are extraordinarily fast and others aren't. +/// Typically, variable performance isn't a problem, but it may be for your use +/// case. +/// +/// The use of prefilters in this implementation does use a heuristic to detect +/// when a prefilter might not be carrying its weight, and will dynamically +/// disable its use. Nevertheless, this configuration option gives callers +/// the ability to disable prefilters if you have knowledge that they won't be +/// useful. +#[derive(Clone, Copy, Debug)] +#[non_exhaustive] +pub enum PrefilterConfig { + /// Never used a prefilter in substring search. + None, + /// Automatically detect whether a heuristic prefilter should be used. If + /// it is used, then heuristics will be used to dynamically disable the + /// prefilter if it is believed to not be carrying its weight. + Auto, +} + +impl Default for PrefilterConfig { + fn default() -> PrefilterConfig { + PrefilterConfig::Auto + } +} + +impl PrefilterConfig { + /// Returns true when this prefilter is set to the `None` variant. + fn is_none(&self) -> bool { + matches!(*self, PrefilterConfig::None) + } +} + +/// The implementation of a prefilter. +/// +/// This type encapsulates dispatch to one of several possible choices for a +/// prefilter. Generally speaking, all prefilters have the same approximate +/// algorithm: they choose a couple of bytes from the needle that are believed +/// to be rare, use a fast vector algorithm to look for those bytes and return +/// positions as candidates for some substring search algorithm (currently only +/// Two-Way) to confirm as a match or not. +/// +/// The differences between the algorithms are actually at the vector +/// implementation level. Namely, we need different routines based on both +/// which target architecture we're on and what CPU features are supported. +/// +/// The straight-forwardly obvious approach here is to use an enum, and make +/// `Prefilter::find` do case analysis to determine which algorithm was +/// selected and invoke it. However, I've observed that this leads to poor +/// codegen in some cases, especially in latency sensitive benchmarks. That is, +/// this approach comes with overhead that I wasn't able to eliminate. +/// +/// The second obvious approach is to use dynamic dispatch with traits. Doing +/// that in this context where `Prefilter` owns the selection generally +/// requires heap allocation, and this code is designed to run in core-only +/// environments. +/// +/// So we settle on using a union (that's `PrefilterKind`) and a function +/// pointer (that's `PrefilterKindFn`). We select the right function pointer +/// based on which field in the union we set, and that function in turn +/// knows which field of the union to access. The downside of this approach +/// is that it forces us to think about safety, but the upside is that +/// there are some nice latency improvements to benchmarks. (Especially the +/// `memmem/sliceslice/short` benchmark.) +/// +/// In cases where we've selected a vector algorithm and the haystack given +/// is too short, we fallback to the scalar version of `memchr` on the +/// `rarest_byte`. (The scalar version of `memchr` is still better than a naive +/// byte-at-a-time loop because it will read in `usize`-sized chunks at a +/// time.) +#[derive(Clone, Copy)] +struct Prefilter { + call: PrefilterKindFn, + kind: PrefilterKind, + rarest_byte: u8, + rarest_offset: u8, +} + +impl Prefilter { + /// Return a "fallback" prefilter, but only if it is believed to be + /// effective. + #[inline] + fn fallback( + ranker: R, + pair: Pair, + needle: &[u8], + ) -> Option { + /// The maximum frequency rank permitted for the fallback prefilter. + /// If the rarest byte in the needle has a frequency rank above this + /// value, then no prefilter is used if the fallback prefilter would + /// otherwise be selected. + const MAX_FALLBACK_RANK: u8 = 250; + + trace!("building fallback prefilter"); + let rarest_offset = pair.index1(); + let rarest_byte = needle[usize::from(rarest_offset)]; + let rarest_rank = ranker.rank(rarest_byte); + if rarest_rank > MAX_FALLBACK_RANK { + None + } else { + let finder = + crate::arch::all::packedpair::Finder::with_pair(needle, pair)?; + let call = prefilter_kind_fallback; + let kind = PrefilterKind { fallback: finder }; + Some(Prefilter { call, kind, rarest_byte, rarest_offset }) + } + } + + /// Return a prefilter using a x86_64 SSE2 vector algorithm. + #[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] + #[inline] + fn sse2(finder: sse2::Finder, needle: &[u8]) -> Prefilter { + trace!("building x86_64 SSE2 prefilter"); + let rarest_offset = finder.pair().index1(); + let rarest_byte = needle[usize::from(rarest_offset)]; + Prefilter { + call: prefilter_kind_sse2, + kind: PrefilterKind { sse2: finder }, + rarest_byte, + rarest_offset, + } + } + + /// Return a prefilter using a x86_64 AVX2 vector algorithm. + #[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] + #[inline] + fn avx2(finder: avx2::Finder, needle: &[u8]) -> Prefilter { + trace!("building x86_64 AVX2 prefilter"); + let rarest_offset = finder.pair().index1(); + let rarest_byte = needle[usize::from(rarest_offset)]; + Prefilter { + call: prefilter_kind_avx2, + kind: PrefilterKind { avx2: finder }, + rarest_byte, + rarest_offset, + } + } + + /// Return a prefilter using a wasm32 simd128 vector algorithm. + #[cfg(all(target_arch = "wasm32", target_feature = "simd128"))] + #[inline] + fn simd128(finder: simd128::Finder, needle: &[u8]) -> Prefilter { + trace!("building wasm32 simd128 prefilter"); + let rarest_offset = finder.pair().index1(); + let rarest_byte = needle[usize::from(rarest_offset)]; + Prefilter { + call: prefilter_kind_simd128, + kind: PrefilterKind { simd128: finder }, + rarest_byte, + rarest_offset, + } + } + + /// Return a prefilter using a aarch64 neon vector algorithm. + #[cfg(target_arch = "aarch64")] + #[inline] + fn neon(finder: neon::Finder, needle: &[u8]) -> Prefilter { + trace!("building aarch64 neon prefilter"); + let rarest_offset = finder.pair().index1(); + let rarest_byte = needle[usize::from(rarest_offset)]; + Prefilter { + call: prefilter_kind_neon, + kind: PrefilterKind { neon: finder }, + rarest_byte, + rarest_offset, + } + } + + /// Return a *candidate* position for a match. + /// + /// When this returns an offset, it implies that a match could begin at + /// that offset, but it may not. That is, it is possible for a false + /// positive to be returned. + /// + /// When `None` is returned, then it is guaranteed that there are no + /// matches for the needle in the given haystack. That is, it is impossible + /// for a false negative to be returned. + /// + /// The purpose of this routine is to look for candidate matching positions + /// as quickly as possible before running a (likely) slower confirmation + /// step. + #[inline] + fn find(&self, haystack: &[u8]) -> Option { + // SAFETY: By construction, we've ensured that the function in + // `self.call` is properly paired with the union used in `self.kind`. + unsafe { (self.call)(self, haystack) } + } + + /// A "simple" prefilter that just looks for the occurrence of the rarest + /// byte from the needle. This is generally only used for very small + /// haystacks. + #[inline] + fn find_simple(&self, haystack: &[u8]) -> Option { + // We don't use crate::memchr here because the haystack should be small + // enough that memchr won't be able to use vector routines anyway. So + // we just skip straight to the fallback implementation which is likely + // faster. (A byte-at-a-time loop is only used when the haystack is + // smaller than `size_of::()`.) + crate::arch::all::memchr::One::new(self.rarest_byte) + .find(haystack) + .map(|i| i.saturating_sub(usize::from(self.rarest_offset))) + } +} + +impl core::fmt::Debug for Prefilter { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + f.debug_struct("Prefilter") + .field("call", &"") + .field("kind", &"") + .field("rarest_byte", &self.rarest_byte) + .field("rarest_offset", &self.rarest_offset) + .finish() + } +} + +/// A union indicating one of several possible prefilters that are in active +/// use. +/// +/// This union should only be read by one of the functions prefixed with +/// `prefilter_kind_`. Namely, the correct function is meant to be paired with +/// the union by the caller, such that the function always reads from the +/// designated union field. +#[derive(Clone, Copy)] +union PrefilterKind { + fallback: crate::arch::all::packedpair::Finder, + #[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] + sse2: crate::arch::x86_64::sse2::packedpair::Finder, + #[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] + avx2: crate::arch::x86_64::avx2::packedpair::Finder, + #[cfg(all(target_arch = "wasm32", target_feature = "simd128"))] + simd128: crate::arch::wasm32::simd128::packedpair::Finder, + #[cfg(target_arch = "aarch64")] + neon: crate::arch::aarch64::neon::packedpair::Finder, +} + +/// The type of a prefilter function. +/// +/// # Safety +/// +/// When using a function of this type, callers must ensure that the correct +/// function is paired with the value populated in `PrefilterKind` union. +type PrefilterKindFn = + unsafe fn(strat: &Prefilter, haystack: &[u8]) -> Option; + +/// Reads from the `fallback` field of `PrefilterKind` to execute the fallback +/// prefilter. Works on all platforms. +/// +/// # Safety +/// +/// Callers must ensure that the `strat.kind.fallback` union field is set. +unsafe fn prefilter_kind_fallback( + strat: &Prefilter, + haystack: &[u8], +) -> Option { + strat.kind.fallback.find_prefilter(haystack) +} + +/// Reads from the `sse2` field of `PrefilterKind` to execute the x86_64 SSE2 +/// prefilter. +/// +/// # Safety +/// +/// Callers must ensure that the `strat.kind.sse2` union field is set. +#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] +unsafe fn prefilter_kind_sse2( + strat: &Prefilter, + haystack: &[u8], +) -> Option { + let finder = &strat.kind.sse2; + if haystack.len() < finder.min_haystack_len() { + strat.find_simple(haystack) + } else { + finder.find_prefilter(haystack) + } +} + +/// Reads from the `avx2` field of `PrefilterKind` to execute the x86_64 AVX2 +/// prefilter. +/// +/// # Safety +/// +/// Callers must ensure that the `strat.kind.avx2` union field is set. +#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] +unsafe fn prefilter_kind_avx2( + strat: &Prefilter, + haystack: &[u8], +) -> Option { + let finder = &strat.kind.avx2; + if haystack.len() < finder.min_haystack_len() { + strat.find_simple(haystack) + } else { + finder.find_prefilter(haystack) + } +} + +/// Reads from the `simd128` field of `PrefilterKind` to execute the wasm32 +/// simd128 prefilter. +/// +/// # Safety +/// +/// Callers must ensure that the `strat.kind.simd128` union field is set. +#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))] +unsafe fn prefilter_kind_simd128( + strat: &Prefilter, + haystack: &[u8], +) -> Option { + let finder = &strat.kind.simd128; + if haystack.len() < finder.min_haystack_len() { + strat.find_simple(haystack) + } else { + finder.find_prefilter(haystack) + } +} + +/// Reads from the `neon` field of `PrefilterKind` to execute the aarch64 neon +/// prefilter. +/// +/// # Safety +/// +/// Callers must ensure that the `strat.kind.neon` union field is set. +#[cfg(target_arch = "aarch64")] +unsafe fn prefilter_kind_neon( + strat: &Prefilter, + haystack: &[u8], +) -> Option { + let finder = &strat.kind.neon; + if haystack.len() < finder.min_haystack_len() { + strat.find_simple(haystack) + } else { + finder.find_prefilter(haystack) + } +} + +/// PrefilterState tracks state associated with the effectiveness of a +/// prefilter. It is used to track how many bytes, on average, are skipped by +/// the prefilter. If this average dips below a certain threshold over time, +/// then the state renders the prefilter inert and stops using it. +/// +/// A prefilter state should be created for each search. (Where creating an +/// iterator is treated as a single search.) A prefilter state should only be +/// created from a `Freqy`. e.g., An inert `Freqy` will produce an inert +/// `PrefilterState`. +#[derive(Clone, Copy, Debug)] +pub(crate) struct PrefilterState { + /// The number of skips that has been executed. This is always 1 greater + /// than the actual number of skips. The special sentinel value of 0 + /// indicates that the prefilter is inert. This is useful to avoid + /// additional checks to determine whether the prefilter is still + /// "effective." Once a prefilter becomes inert, it should no longer be + /// used (according to our heuristics). + skips: u32, + /// The total number of bytes that have been skipped. + skipped: u32, +} + +impl PrefilterState { + /// The minimum number of skip attempts to try before considering whether + /// a prefilter is effective or not. + const MIN_SKIPS: u32 = 50; + + /// The minimum amount of bytes that skipping must average. + /// + /// This value was chosen based on varying it and checking + /// the microbenchmarks. In particular, this can impact the + /// pathological/repeated-{huge,small} benchmarks quite a bit if it's set + /// too low. + const MIN_SKIP_BYTES: u32 = 8; + + /// Create a fresh prefilter state. + #[inline] + pub(crate) fn new() -> PrefilterState { + PrefilterState { skips: 1, skipped: 0 } + } + + /// Update this state with the number of bytes skipped on the last + /// invocation of the prefilter. + #[inline] + fn update(&mut self, skipped: usize) { + self.skips = self.skips.saturating_add(1); + // We need to do this dance since it's technically possible for + // `skipped` to overflow a `u32`. (And we use a `u32` to reduce the + // size of a prefilter state.) + self.skipped = match u32::try_from(skipped) { + Err(_) => core::u32::MAX, + Ok(skipped) => self.skipped.saturating_add(skipped), + }; + } + + /// Return true if and only if this state indicates that a prefilter is + /// still effective. + #[inline] + fn is_effective(&mut self) -> bool { + if self.is_inert() { + return false; + } + if self.skips() < PrefilterState::MIN_SKIPS { + return true; + } + if self.skipped >= PrefilterState::MIN_SKIP_BYTES * self.skips() { + return true; + } + + // We're inert. + self.skips = 0; + false + } + + /// Returns true if the prefilter this state represents should no longer + /// be used. + #[inline] + fn is_inert(&self) -> bool { + self.skips == 0 + } + + /// Returns the total number of times the prefilter has been used. + #[inline] + fn skips(&self) -> u32 { + // Remember, `0` is a sentinel value indicating inertness, so we + // always need to subtract `1` to get our actual number of skips. + self.skips.saturating_sub(1) + } +} + +/// A combination of prefilter effectiveness state and the prefilter itself. +#[derive(Debug)] +pub(crate) struct Pre<'a> { + /// State that tracks the effectiveness of a prefilter. + prestate: &'a mut PrefilterState, + /// The actual prefilter. + prestrat: &'a Prefilter, +} + +impl<'a> Pre<'a> { + /// Call this prefilter on the given haystack with the given needle. + #[inline] + pub(crate) fn find(&mut self, haystack: &[u8]) -> Option { + let result = self.prestrat.find(haystack); + self.prestate.update(result.unwrap_or(haystack.len())); + result + } + + /// Return true if and only if this prefilter should be used. + #[inline] + pub(crate) fn is_effective(&mut self) -> bool { + self.prestate.is_effective() + } +} + +/// Returns true if the needle has the right characteristics for a vector +/// algorithm to handle the entirety of substring search. +/// +/// Vector algorithms can be used for prefilters for other substring search +/// algorithms (like Two-Way), but they can also be used for substring search +/// on their own. When used for substring search, vector algorithms will +/// quickly identify candidate match positions (just like in the prefilter +/// case), but instead of returning the candidate position they will try to +/// confirm the match themselves. Confirmation happens via `memcmp`. This +/// works well for short needles, but can break down when many false candidate +/// positions are generated for large needles. Thus, we only permit vector +/// algorithms to own substring search when the needle is of a certain length. +#[inline] +fn do_packed_search(needle: &[u8]) -> bool { + /// The minimum length of a needle required for this algorithm. The minimum + /// is 2 since a length of 1 should just use memchr and a length of 0 isn't + /// a case handled by this searcher. + const MIN_LEN: usize = 2; + + /// The maximum length of a needle required for this algorithm. + /// + /// In reality, there is no hard max here. The code below can handle any + /// length needle. (Perhaps that suggests there are missing optimizations.) + /// Instead, this is a heuristic and a bound guaranteeing our linear time + /// complexity. + /// + /// It is a heuristic because when a candidate match is found, memcmp is + /// run. For very large needles with lots of false positives, memcmp can + /// make the code run quite slow. + /// + /// It is a bound because the worst case behavior with memcmp is + /// multiplicative in the size of the needle and haystack, and we want + /// to keep that additive. This bound ensures we still meet that bound + /// theoretically, since it's just a constant. We aren't acting in bad + /// faith here, memcmp on tiny needles is so fast that even in pathological + /// cases (see pathological vector benchmarks), this is still just as fast + /// or faster in practice. + /// + /// This specific number was chosen by tweaking a bit and running + /// benchmarks. The rare-medium-needle, for example, gets about 5% faster + /// by using this algorithm instead of a prefilter-accelerated Two-Way. + /// There's also a theoretical desire to keep this number reasonably + /// low, to mitigate the impact of pathological cases. I did try 64, and + /// some benchmarks got a little better, and others (particularly the + /// pathological ones), got a lot worse. So... 32 it is? + const MAX_LEN: usize = 32; + MIN_LEN <= needle.len() && needle.len() <= MAX_LEN +} diff --git a/third_party/crates/memchr-2.8.3/src/tests/memchr/mod.rs b/third_party/crates/memchr-2.8.3/src/tests/memchr/mod.rs new file mode 100644 index 0000000..0564ad4 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/tests/memchr/mod.rs @@ -0,0 +1,307 @@ +use alloc::{ + string::{String, ToString}, + vec, + vec::Vec, +}; + +use crate::ext::Byte; + +pub(crate) mod naive; +#[macro_use] +pub(crate) mod prop; + +const SEEDS: &'static [Seed] = &[ + Seed { haystack: "a", needles: &[b'a'], positions: &[0] }, + Seed { haystack: "aa", needles: &[b'a'], positions: &[0, 1] }, + Seed { haystack: "aaa", needles: &[b'a'], positions: &[0, 1, 2] }, + Seed { haystack: "", needles: &[b'a'], positions: &[] }, + Seed { haystack: "z", needles: &[b'a'], positions: &[] }, + Seed { haystack: "zz", needles: &[b'a'], positions: &[] }, + Seed { haystack: "zza", needles: &[b'a'], positions: &[2] }, + Seed { haystack: "zaza", needles: &[b'a'], positions: &[1, 3] }, + Seed { haystack: "zzza", needles: &[b'a'], positions: &[3] }, + Seed { haystack: "\x00a", needles: &[b'a'], positions: &[1] }, + Seed { haystack: "\x00", needles: &[b'\x00'], positions: &[0] }, + Seed { haystack: "\x00\x00", needles: &[b'\x00'], positions: &[0, 1] }, + Seed { haystack: "\x00a\x00", needles: &[b'\x00'], positions: &[0, 2] }, + Seed { haystack: "zzzzzzzzzzzzzzzza", needles: &[b'a'], positions: &[16] }, + Seed { + haystack: "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzza", + needles: &[b'a'], + positions: &[32], + }, + // two needles (applied to memchr2 + memchr3) + Seed { haystack: "az", needles: &[b'a', b'z'], positions: &[0, 1] }, + Seed { haystack: "az", needles: &[b'a', b'z'], positions: &[0, 1] }, + Seed { haystack: "az", needles: &[b'x', b'y'], positions: &[] }, + Seed { haystack: "az", needles: &[b'a', b'y'], positions: &[0] }, + Seed { haystack: "az", needles: &[b'x', b'z'], positions: &[1] }, + Seed { haystack: "yyyyaz", needles: &[b'a', b'z'], positions: &[4, 5] }, + Seed { haystack: "yyyyaz", needles: &[b'z', b'a'], positions: &[4, 5] }, + // three needles (applied to memchr3) + Seed { + haystack: "xyz", + needles: &[b'x', b'y', b'z'], + positions: &[0, 1, 2], + }, + Seed { + haystack: "zxy", + needles: &[b'x', b'y', b'z'], + positions: &[0, 1, 2], + }, + Seed { haystack: "zxy", needles: &[b'x', b'a', b'z'], positions: &[0, 1] }, + Seed { haystack: "zxy", needles: &[b't', b'a', b'z'], positions: &[0] }, + Seed { haystack: "yxz", needles: &[b't', b'a', b'z'], positions: &[2] }, +]; + +/// Runs a host of substring search tests. +/// +/// This has support for "partial" substring search implementations only work +/// for a subset of needles/haystacks. For example, the "packed pair" substring +/// search implementation only works for haystacks of some minimum length based +/// of the pair of bytes selected and the size of the vector used. +pub(crate) struct Runner { + needle_len: usize, +} + +impl Runner { + /// Create a new test runner for forward and reverse byte search + /// implementations. + /// + /// The `needle_len` given must be at most `3` and at least `1`. It + /// corresponds to the number of needle bytes to search for. + pub(crate) fn new(needle_len: usize) -> Runner { + assert!(needle_len >= 1, "needle_len must be at least 1"); + assert!(needle_len <= 3, "needle_len must be at most 3"); + Runner { needle_len } + } + + /// Run all tests. This panics on the first failure. + /// + /// If the implementation being tested returns `None` for a particular + /// haystack/needle combination, then that test is skipped. + pub(crate) fn forward_iter(self, mut test: F) + where + F: FnMut(&[u8], &[u8]) -> Option> + 'static, + { + for seed in SEEDS.iter() { + if seed.needles.len() > self.needle_len { + continue; + } + for t in seed.generate() { + let results = match test(t.haystack.as_bytes(), &t.needles) { + None => continue, + Some(results) => results, + }; + assert_eq!( + t.expected, + results, + "needles: {:?}, haystack: {:?}", + t.needles + .iter() + .map(|&b| b.to_char()) + .collect::>(), + t.haystack, + ); + } + } + } + + /// Run all tests in the reverse direction. This panics on the first + /// failure. + /// + /// If the implementation being tested returns `None` for a particular + /// haystack/needle combination, then that test is skipped. + pub(crate) fn reverse_iter(self, mut test: F) + where + F: FnMut(&[u8], &[u8]) -> Option> + 'static, + { + for seed in SEEDS.iter() { + if seed.needles.len() > self.needle_len { + continue; + } + for t in seed.generate() { + let mut results = match test(t.haystack.as_bytes(), &t.needles) + { + None => continue, + Some(results) => results, + }; + results.reverse(); + assert_eq!( + t.expected, + results, + "needles: {:?}, haystack: {:?}", + t.needles + .iter() + .map(|&b| b.to_char()) + .collect::>(), + t.haystack, + ); + } + } + } + + /// Run all tests as counting tests. This panics on the first failure. + /// + /// That is, this only checks that the number of matches is correct and + /// not whether the offsets of each match are. + pub(crate) fn count_iter(self, mut test: F) + where + F: FnMut(&[u8], &[u8]) -> Option + 'static, + { + for seed in SEEDS.iter() { + if seed.needles.len() > self.needle_len { + continue; + } + for t in seed.generate() { + let got = match test(t.haystack.as_bytes(), &t.needles) { + None => continue, + Some(got) => got, + }; + assert_eq!( + t.expected.len(), + got, + "needles: {:?}, haystack: {:?}", + t.needles + .iter() + .map(|&b| b.to_char()) + .collect::>(), + t.haystack, + ); + } + } + } + + /// Like `Runner::forward`, but for a function that returns only the next + /// match and not all matches. + /// + /// If the function returns `None`, then it is skipped. + pub(crate) fn forward_oneshot(self, mut test: F) + where + F: FnMut(&[u8], &[u8]) -> Option> + 'static, + { + self.forward_iter(move |haystack, needles| { + let mut start = 0; + let mut results = vec![]; + while let Some(i) = test(&haystack[start..], needles)? { + results.push(start + i); + start += i + 1; + } + Some(results) + }) + } + + /// Like `Runner::reverse`, but for a function that returns only the last + /// match and not all matches. + /// + /// If the function returns `None`, then it is skipped. + pub(crate) fn reverse_oneshot(self, mut test: F) + where + F: FnMut(&[u8], &[u8]) -> Option> + 'static, + { + self.reverse_iter(move |haystack, needles| { + let mut end = haystack.len(); + let mut results = vec![]; + while let Some(i) = test(&haystack[..end], needles)? { + results.push(i); + end = i; + } + Some(results) + }) + } +} + +/// A single test for memr?chr{,2,3}. +#[derive(Clone, Debug)] +struct Test { + /// The string to search in. + haystack: String, + /// The needles to look for. + needles: Vec, + /// The offsets that are expected to be found for all needles in the + /// forward direction. + expected: Vec, +} + +impl Test { + fn new(seed: &Seed) -> Test { + Test { + haystack: seed.haystack.to_string(), + needles: seed.needles.to_vec(), + expected: seed.positions.to_vec(), + } + } +} + +/// Data that can be expanded into many memchr tests by padding out the corpus. +#[derive(Clone, Debug)] +struct Seed { + /// The thing to search. We use `&str` instead of `&[u8]` because they + /// are nicer to write in tests, and we don't miss much since memchr + /// doesn't care about UTF-8. + /// + /// Corpora cannot contain either '%' or '#'. We use these bytes when + /// expanding test cases into many test cases, and we assume they are not + /// used. If they are used, `memchr_tests` will panic. + haystack: &'static str, + /// The needles to search for. This is intended to be an alternation of + /// needles. The number of needles may cause this test to be skipped for + /// some memchr variants. For example, a test with 2 needles cannot be used + /// to test `memchr`, but can be used to test `memchr2` and `memchr3`. + /// However, a test with only 1 needle can be used to test all of `memchr`, + /// `memchr2` and `memchr3`. We achieve this by filling in the needles with + /// bytes that we never used in the corpus (such as '#'). + needles: &'static [u8], + /// The positions expected to match for all of the needles. + positions: &'static [usize], +} + +impl Seed { + /// Controls how much we expand the haystack on either side for each test. + /// We lower this on Miri because otherwise running the tests would take + /// forever. + const EXPAND_LEN: usize = { + #[cfg(not(miri))] + { + 515 + } + #[cfg(miri)] + { + 6 + } + }; + + /// Expand this test into many variations of the same test. + /// + /// In particular, this will generate more tests with larger corpus sizes. + /// The expected positions are updated to maintain the integrity of the + /// test. + /// + /// This is important in testing a memchr implementation, because there are + /// often different cases depending on the length of the corpus. + /// + /// Note that we extend the corpus by adding `%` bytes, which we + /// don't otherwise use as a needle. + fn generate(&self) -> impl Iterator { + let mut more = vec![]; + + // Add bytes to the start of the corpus. + for i in 0..Seed::EXPAND_LEN { + let mut t = Test::new(self); + let mut new: String = core::iter::repeat('%').take(i).collect(); + new.push_str(&t.haystack); + t.haystack = new; + t.expected = t.expected.into_iter().map(|p| p + i).collect(); + more.push(t); + } + // Add bytes to the end of the corpus. + for i in 1..Seed::EXPAND_LEN { + let mut t = Test::new(self); + let padding: String = core::iter::repeat('%').take(i).collect(); + t.haystack.push_str(&padding); + more.push(t); + } + + more.into_iter() + } +} diff --git a/third_party/crates/memchr-2.8.3/src/tests/memchr/naive.rs b/third_party/crates/memchr-2.8.3/src/tests/memchr/naive.rs new file mode 100644 index 0000000..6ebcdae --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/tests/memchr/naive.rs @@ -0,0 +1,33 @@ +pub(crate) fn memchr(n1: u8, haystack: &[u8]) -> Option { + haystack.iter().position(|&b| b == n1) +} + +pub(crate) fn memchr2(n1: u8, n2: u8, haystack: &[u8]) -> Option { + haystack.iter().position(|&b| b == n1 || b == n2) +} + +pub(crate) fn memchr3( + n1: u8, + n2: u8, + n3: u8, + haystack: &[u8], +) -> Option { + haystack.iter().position(|&b| b == n1 || b == n2 || b == n3) +} + +pub(crate) fn memrchr(n1: u8, haystack: &[u8]) -> Option { + haystack.iter().rposition(|&b| b == n1) +} + +pub(crate) fn memrchr2(n1: u8, n2: u8, haystack: &[u8]) -> Option { + haystack.iter().rposition(|&b| b == n1 || b == n2) +} + +pub(crate) fn memrchr3( + n1: u8, + n2: u8, + n3: u8, + haystack: &[u8], +) -> Option { + haystack.iter().rposition(|&b| b == n1 || b == n2 || b == n3) +} diff --git a/third_party/crates/memchr-2.8.3/src/tests/memchr/prop.rs b/third_party/crates/memchr-2.8.3/src/tests/memchr/prop.rs new file mode 100644 index 0000000..949ef1f --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/tests/memchr/prop.rs @@ -0,0 +1,323 @@ +/// Defines a host of quickcheck tests for the given memchr searcher. +#[cfg(miri)] +#[macro_export] +macro_rules! define_memchr_quickcheck { + ($($tt:tt)*) => {}; +} + +/// Defines a host of quickcheck tests for the given memchr searcher. +#[cfg(not(miri))] +#[macro_export] +macro_rules! define_memchr_quickcheck { + ($mod:ident) => { + define_memchr_quickcheck!($mod, new); + }; + ($mod:ident, $cons:ident) => { + use alloc::vec::Vec; + + use quickcheck::TestResult; + + use crate::tests::memchr::{ + naive, + prop::{double_ended_take, naive1_iter, naive2_iter, naive3_iter}, + }; + + quickcheck::quickcheck! { + fn qc_memchr_matches_naive(n1: u8, corpus: Vec) -> TestResult { + let expected = naive::memchr(n1, &corpus); + let got = match $mod::One::$cons(n1) { + None => return TestResult::discard(), + Some(f) => f.find(&corpus), + }; + TestResult::from_bool(expected == got) + } + + fn qc_memrchr_matches_naive(n1: u8, corpus: Vec) -> TestResult { + let expected = naive::memrchr(n1, &corpus); + let got = match $mod::One::$cons(n1) { + None => return TestResult::discard(), + Some(f) => f.rfind(&corpus), + }; + TestResult::from_bool(expected == got) + } + + fn qc_memchr2_matches_naive(n1: u8, n2: u8, corpus: Vec) -> TestResult { + let expected = naive::memchr2(n1, n2, &corpus); + let got = match $mod::Two::$cons(n1, n2) { + None => return TestResult::discard(), + Some(f) => f.find(&corpus), + }; + TestResult::from_bool(expected == got) + } + + fn qc_memrchr2_matches_naive(n1: u8, n2: u8, corpus: Vec) -> TestResult { + let expected = naive::memrchr2(n1, n2, &corpus); + let got = match $mod::Two::$cons(n1, n2) { + None => return TestResult::discard(), + Some(f) => f.rfind(&corpus), + }; + TestResult::from_bool(expected == got) + } + + fn qc_memchr3_matches_naive( + n1: u8, n2: u8, n3: u8, + corpus: Vec + ) -> TestResult { + let expected = naive::memchr3(n1, n2, n3, &corpus); + let got = match $mod::Three::$cons(n1, n2, n3) { + None => return TestResult::discard(), + Some(f) => f.find(&corpus), + }; + TestResult::from_bool(expected == got) + } + + fn qc_memrchr3_matches_naive( + n1: u8, n2: u8, n3: u8, + corpus: Vec + ) -> TestResult { + let expected = naive::memrchr3(n1, n2, n3, &corpus); + let got = match $mod::Three::$cons(n1, n2, n3) { + None => return TestResult::discard(), + Some(f) => f.rfind(&corpus), + }; + TestResult::from_bool(expected == got) + } + + fn qc_memchr_double_ended_iter( + needle: u8, data: Vec, take_side: Vec + ) -> TestResult { + // make nonempty + let mut take_side = take_side; + if take_side.is_empty() { take_side.push(true) }; + + let finder = match $mod::One::$cons(needle) { + None => return TestResult::discard(), + Some(finder) => finder, + }; + let iter = finder.iter(&data); + let got = double_ended_take( + iter, + take_side.iter().cycle().cloned(), + ); + let expected = naive1_iter(needle, &data); + + TestResult::from_bool(got.iter().cloned().eq(expected)) + } + + fn qc_memchr2_double_ended_iter( + needle1: u8, needle2: u8, data: Vec, take_side: Vec + ) -> TestResult { + // make nonempty + let mut take_side = take_side; + if take_side.is_empty() { take_side.push(true) }; + + let finder = match $mod::Two::$cons(needle1, needle2) { + None => return TestResult::discard(), + Some(finder) => finder, + }; + let iter = finder.iter(&data); + let got = double_ended_take( + iter, + take_side.iter().cycle().cloned(), + ); + let expected = naive2_iter(needle1, needle2, &data); + + TestResult::from_bool(got.iter().cloned().eq(expected)) + } + + fn qc_memchr3_double_ended_iter( + needle1: u8, needle2: u8, needle3: u8, + data: Vec, take_side: Vec + ) -> TestResult { + // make nonempty + let mut take_side = take_side; + if take_side.is_empty() { take_side.push(true) }; + + let finder = match $mod::Three::$cons(needle1, needle2, needle3) { + None => return TestResult::discard(), + Some(finder) => finder, + }; + let iter = finder.iter(&data); + let got = double_ended_take( + iter, + take_side.iter().cycle().cloned(), + ); + let expected = naive3_iter(needle1, needle2, needle3, &data); + + TestResult::from_bool(got.iter().cloned().eq(expected)) + } + + fn qc_memchr1_iter(data: Vec) -> TestResult { + let needle = 0; + let finder = match $mod::One::$cons(needle) { + None => return TestResult::discard(), + Some(finder) => finder, + }; + let got = finder.iter(&data); + let expected = naive1_iter(needle, &data); + TestResult::from_bool(got.eq(expected)) + } + + fn qc_memchr1_rev_iter(data: Vec) -> TestResult { + let needle = 0; + + let finder = match $mod::One::$cons(needle) { + None => return TestResult::discard(), + Some(finder) => finder, + }; + let got = finder.iter(&data).rev(); + let expected = naive1_iter(needle, &data).rev(); + TestResult::from_bool(got.eq(expected)) + } + + fn qc_memchr2_iter(data: Vec) -> TestResult { + let needle1 = 0; + let needle2 = 1; + + let finder = match $mod::Two::$cons(needle1, needle2) { + None => return TestResult::discard(), + Some(finder) => finder, + }; + let got = finder.iter(&data); + let expected = naive2_iter(needle1, needle2, &data); + TestResult::from_bool(got.eq(expected)) + } + + fn qc_memchr2_rev_iter(data: Vec) -> TestResult { + let needle1 = 0; + let needle2 = 1; + + let finder = match $mod::Two::$cons(needle1, needle2) { + None => return TestResult::discard(), + Some(finder) => finder, + }; + let got = finder.iter(&data).rev(); + let expected = naive2_iter(needle1, needle2, &data).rev(); + TestResult::from_bool(got.eq(expected)) + } + + fn qc_memchr3_iter(data: Vec) -> TestResult { + let needle1 = 0; + let needle2 = 1; + let needle3 = 2; + + let finder = match $mod::Three::$cons(needle1, needle2, needle3) { + None => return TestResult::discard(), + Some(finder) => finder, + }; + let got = finder.iter(&data); + let expected = naive3_iter(needle1, needle2, needle3, &data); + TestResult::from_bool(got.eq(expected)) + } + + fn qc_memchr3_rev_iter(data: Vec) -> TestResult { + let needle1 = 0; + let needle2 = 1; + let needle3 = 2; + + let finder = match $mod::Three::$cons(needle1, needle2, needle3) { + None => return TestResult::discard(), + Some(finder) => finder, + }; + let got = finder.iter(&data).rev(); + let expected = naive3_iter(needle1, needle2, needle3, &data).rev(); + TestResult::from_bool(got.eq(expected)) + } + + fn qc_memchr1_iter_size_hint(data: Vec) -> TestResult { + // test that the size hint is within reasonable bounds + let needle = 0; + let finder = match $mod::One::$cons(needle) { + None => return TestResult::discard(), + Some(finder) => finder, + }; + let mut iter = finder.iter(&data); + let mut real_count = data + .iter() + .filter(|&&elt| elt == needle) + .count(); + + while let Some(index) = iter.next() { + real_count -= 1; + let (lower, upper) = iter.size_hint(); + assert!(lower <= real_count); + assert!(upper.unwrap() >= real_count); + assert!(upper.unwrap() <= data.len() - index); + } + TestResult::passed() + } + } + }; +} + +// take items from a DEI, taking front for each true and back for each false. +// Return a vector with the concatenation of the fronts and the reverse of the +// backs. +#[cfg(not(miri))] +pub(crate) fn double_ended_take( + mut iter: I, + take_side: J, +) -> alloc::vec::Vec +where + I: DoubleEndedIterator, + J: Iterator, +{ + let mut found_front = alloc::vec![]; + let mut found_back = alloc::vec![]; + + for take_front in take_side { + if take_front { + if let Some(pos) = iter.next() { + found_front.push(pos); + } else { + break; + } + } else { + if let Some(pos) = iter.next_back() { + found_back.push(pos); + } else { + break; + } + }; + } + + let mut all_found = found_front; + all_found.extend(found_back.into_iter().rev()); + all_found +} + +// return an iterator of the 0-based indices of haystack that match the needle +#[cfg(not(miri))] +pub(crate) fn naive1_iter<'a>( + n1: u8, + haystack: &'a [u8], +) -> impl DoubleEndedIterator + 'a { + haystack.iter().enumerate().filter(move |&(_, &b)| b == n1).map(|t| t.0) +} + +#[cfg(not(miri))] +pub(crate) fn naive2_iter<'a>( + n1: u8, + n2: u8, + haystack: &'a [u8], +) -> impl DoubleEndedIterator + 'a { + haystack + .iter() + .enumerate() + .filter(move |&(_, &b)| b == n1 || b == n2) + .map(|t| t.0) +} + +#[cfg(not(miri))] +pub(crate) fn naive3_iter<'a>( + n1: u8, + n2: u8, + n3: u8, + haystack: &'a [u8], +) -> impl DoubleEndedIterator + 'a { + haystack + .iter() + .enumerate() + .filter(move |&(_, &b)| b == n1 || b == n2 || b == n3) + .map(|t| t.0) +} diff --git a/third_party/crates/memchr-2.8.3/src/tests/mod.rs b/third_party/crates/memchr-2.8.3/src/tests/mod.rs new file mode 100644 index 0000000..259b678 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/tests/mod.rs @@ -0,0 +1,15 @@ +#[macro_use] +pub(crate) mod memchr; +pub(crate) mod packedpair; +#[macro_use] +pub(crate) mod substring; + +// For debugging, particularly in CI, print out the byte order of the current +// target. +#[test] +fn byte_order() { + #[cfg(target_endian = "little")] + std::eprintln!("LITTLE ENDIAN"); + #[cfg(target_endian = "big")] + std::eprintln!("BIG ENDIAN"); +} diff --git a/third_party/crates/memchr-2.8.3/src/tests/packedpair.rs b/third_party/crates/memchr-2.8.3/src/tests/packedpair.rs new file mode 100644 index 0000000..204635b --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/tests/packedpair.rs @@ -0,0 +1,216 @@ +use alloc::{boxed::Box, vec, vec::Vec}; + +/// A set of "packed pair" test seeds. Each seed serves as the base for the +/// generation of many other tests. In essence, the seed captures the pair of +/// bytes we used for a predicate and first byte among our needle. The tests +/// generated from each seed essentially vary the length of the needle and +/// haystack, while using the rare/first byte configuration from the seed. +/// +/// The purpose of this is to test many different needle/haystack lengths. +/// In particular, some of the vector optimizations might only have bugs +/// in haystacks of a certain size. +const SEEDS: &[Seed] = &[ + // Why not use different 'first' bytes? It seemed like a good idea to be + // able to configure it, but when I wrote the test generator below, it + // didn't seem necessary to use for reasons that I forget. + Seed { first: b'x', index1: b'y', index2: b'z' }, + Seed { first: b'x', index1: b'x', index2: b'z' }, + Seed { first: b'x', index1: b'y', index2: b'x' }, + Seed { first: b'x', index1: b'x', index2: b'x' }, + Seed { first: b'x', index1: b'y', index2: b'y' }, +]; + +/// Runs a host of "packed pair" search tests. +/// +/// These tests specifically look for the occurrence of a possible substring +/// match based on a pair of bytes matching at the right offsets. +pub(crate) struct Runner { + fwd: Option< + Box< + dyn FnMut(&[u8], &[u8], u8, u8) -> Option> + 'static, + >, + >, +} + +impl Runner { + /// Create a new test runner for "packed pair" substring search. + pub(crate) fn new() -> Runner { + Runner { fwd: None } + } + + /// Run all tests. This panics on the first failure. + /// + /// If the implementation being tested returns `None` for a particular + /// haystack/needle combination, then that test is skipped. + /// + /// This runs tests on both the forward and reverse implementations given. + /// If either (or both) are missing, then tests for that implementation are + /// skipped. + pub(crate) fn run(self) { + if let Some(mut fwd) = self.fwd { + for seed in SEEDS.iter() { + for t in seed.generate() { + match fwd(&t.haystack, &t.needle, t.index1, t.index2) { + None => continue, + Some(result) => { + assert_eq!( + t.fwd, result, + "FORWARD, needle: {:?}, haystack: {:?}, \ + index1: {:?}, index2: {:?}", + t.needle, t.haystack, t.index1, t.index2, + ) + } + } + } + } + } + } + + /// Set the implementation for forward "packed pair" substring search. + /// + /// If the closure returns `None`, then it is assumed that the given + /// test cannot be applied to the particular implementation and it is + /// skipped. For example, if a particular implementation only supports + /// needles or haystacks for some minimum length. + /// + /// If this is not set, then forward "packed pair" search is not tested. + pub(crate) fn fwd( + mut self, + search: impl FnMut(&[u8], &[u8], u8, u8) -> Option> + 'static, + ) -> Runner { + self.fwd = Some(Box::new(search)); + self + } +} + +/// A test that represents the input and expected output to a "packed pair" +/// search function. The test should be able to run with any "packed pair" +/// implementation and get the expected output. +struct Test { + haystack: Vec, + needle: Vec, + index1: u8, + index2: u8, + fwd: Option, +} + +impl Test { + /// Create a new "packed pair" test from a seed and some given offsets to + /// the pair of bytes to use as a predicate in the seed's needle. + /// + /// If a valid test could not be constructed, then None is returned. + /// (Currently, we take the approach of massaging tests to be valid + /// instead of rejecting them outright.) + fn new( + seed: Seed, + index1: usize, + index2: usize, + haystack_len: usize, + needle_len: usize, + fwd: Option, + ) -> Option { + let mut index1: u8 = index1.try_into().unwrap(); + let mut index2: u8 = index2.try_into().unwrap(); + // The '#' byte is never used in a haystack (unless we're expecting + // a match), while the '@' byte is never used in a needle. + let mut haystack = vec![b'@'; haystack_len]; + let mut needle = vec![b'#'; needle_len]; + needle[0] = seed.first; + needle[index1 as usize] = seed.index1; + needle[index2 as usize] = seed.index2; + // If we're expecting a match, then make sure the needle occurs + // in the haystack at the expected position. + if let Some(i) = fwd { + haystack[i..i + needle.len()].copy_from_slice(&needle); + } + // If the operations above lead to rare offsets pointing to the + // non-first occurrence of a byte, then adjust it. This might lead + // to redundant tests, but it's simpler than trying to change the + // generation process I think. + if let Some(i) = crate::memchr(seed.index1, &needle) { + index1 = u8::try_from(i).unwrap(); + } + if let Some(i) = crate::memchr(seed.index2, &needle) { + index2 = u8::try_from(i).unwrap(); + } + Some(Test { haystack, needle, index1, index2, fwd }) + } +} + +/// Data that describes a single prefilter test seed. +#[derive(Clone, Copy)] +struct Seed { + first: u8, + index1: u8, + index2: u8, +} + +impl Seed { + const NEEDLE_LENGTH_LIMIT: usize = { + #[cfg(not(miri))] + { + 33 + } + #[cfg(miri)] + { + 5 + } + }; + + const HAYSTACK_LENGTH_LIMIT: usize = { + #[cfg(not(miri))] + { + 65 + } + #[cfg(miri)] + { + 8 + } + }; + + /// Generate a series of prefilter tests from this seed. + fn generate(self) -> impl Iterator { + let len_start = 2; + // The iterator below generates *a lot* of tests. The number of + // tests was chosen somewhat empirically to be "bearable" when + // running the test suite. + // + // We use an iterator here because the collective haystacks of all + // these test cases add up to enough memory to OOM a conservative + // sandbox or a small laptop. + (len_start..=Seed::NEEDLE_LENGTH_LIMIT).flat_map(move |needle_len| { + let index_start = len_start - 1; + (index_start..needle_len).flat_map(move |index1| { + (index1..needle_len).flat_map(move |index2| { + (needle_len..=Seed::HAYSTACK_LENGTH_LIMIT).flat_map( + move |haystack_len| { + Test::new( + self, + index1, + index2, + haystack_len, + needle_len, + None, + ) + .into_iter() + .chain( + (0..=(haystack_len - needle_len)).flat_map( + move |output| { + Test::new( + self, + index1, + index2, + haystack_len, + needle_len, + Some(output), + ) + }, + ), + ) + }, + ) + }) + }) + }) + } +} diff --git a/third_party/crates/memchr-2.8.3/src/tests/substring/mod.rs b/third_party/crates/memchr-2.8.3/src/tests/substring/mod.rs new file mode 100644 index 0000000..dd10cbd --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/tests/substring/mod.rs @@ -0,0 +1,232 @@ +/*! +This module defines tests and test helpers for substring implementations. +*/ + +use alloc::{ + boxed::Box, + format, + string::{String, ToString}, +}; + +pub(crate) mod naive; +#[macro_use] +pub(crate) mod prop; + +const SEEDS: &'static [Seed] = &[ + Seed::new("", "", Some(0), Some(0)), + Seed::new("", "a", Some(0), Some(1)), + Seed::new("", "ab", Some(0), Some(2)), + Seed::new("", "abc", Some(0), Some(3)), + Seed::new("a", "", None, None), + Seed::new("a", "a", Some(0), Some(0)), + Seed::new("a", "aa", Some(0), Some(1)), + Seed::new("a", "ba", Some(1), Some(1)), + Seed::new("a", "bba", Some(2), Some(2)), + Seed::new("a", "bbba", Some(3), Some(3)), + Seed::new("a", "bbbab", Some(3), Some(3)), + Seed::new("a", "bbbabb", Some(3), Some(3)), + Seed::new("a", "bbbabbb", Some(3), Some(3)), + Seed::new("a", "bbbbbb", None, None), + Seed::new("ab", "", None, None), + Seed::new("ab", "a", None, None), + Seed::new("ab", "b", None, None), + Seed::new("ab", "ab", Some(0), Some(0)), + Seed::new("ab", "aab", Some(1), Some(1)), + Seed::new("ab", "aaab", Some(2), Some(2)), + Seed::new("ab", "abaab", Some(0), Some(3)), + Seed::new("ab", "baaab", Some(3), Some(3)), + Seed::new("ab", "acb", None, None), + Seed::new("ab", "abba", Some(0), Some(0)), + Seed::new("abc", "ab", None, None), + Seed::new("abc", "abc", Some(0), Some(0)), + Seed::new("abc", "abcz", Some(0), Some(0)), + Seed::new("abc", "abczz", Some(0), Some(0)), + Seed::new("abc", "zabc", Some(1), Some(1)), + Seed::new("abc", "zzabc", Some(2), Some(2)), + Seed::new("abc", "azbc", None, None), + Seed::new("abc", "abzc", None, None), + Seed::new("abczdef", "abczdefzzzzzzzzzzzzzzzzzzzz", Some(0), Some(0)), + Seed::new("abczdef", "zzzzzzzzzzzzzzzzzzzzabczdef", Some(20), Some(20)), + Seed::new( + "xyz", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaxyz", + Some(32), + Some(32), + ), + Seed::new("\u{0}\u{15}", "\u{0}\u{15}\u{15}\u{0}", Some(0), Some(0)), + Seed::new("\u{0}\u{1e}", "\u{1e}\u{0}", None, None), +]; + +/// Runs a host of substring search tests. +/// +/// This has support for "partial" substring search implementations only work +/// for a subset of needles/haystacks. For example, the "packed pair" substring +/// search implementation only works for haystacks of some minimum length based +/// of the pair of bytes selected and the size of the vector used. +pub(crate) struct Runner { + fwd: Option< + Box Option> + 'static>, + >, + rev: Option< + Box Option> + 'static>, + >, +} + +impl Runner { + /// Create a new test runner for forward and reverse substring search + /// implementations. + pub(crate) fn new() -> Runner { + Runner { fwd: None, rev: None } + } + + /// Run all tests. This panics on the first failure. + /// + /// If the implementation being tested returns `None` for a particular + /// haystack/needle combination, then that test is skipped. + /// + /// This runs tests on both the forward and reverse implementations given. + /// If either (or both) are missing, then tests for that implementation are + /// skipped. + pub(crate) fn run(self) { + if let Some(mut fwd) = self.fwd { + for seed in SEEDS.iter() { + for t in seed.generate() { + match fwd(t.haystack.as_bytes(), t.needle.as_bytes()) { + None => continue, + Some(result) => { + assert_eq!( + t.fwd, result, + "FORWARD, needle: {:?}, haystack: {:?}", + t.needle, t.haystack, + ); + } + } + } + } + } + if let Some(mut rev) = self.rev { + for seed in SEEDS.iter() { + for t in seed.generate() { + match rev(t.haystack.as_bytes(), t.needle.as_bytes()) { + None => continue, + Some(result) => { + assert_eq!( + t.rev, result, + "REVERSE, needle: {:?}, haystack: {:?}", + t.needle, t.haystack, + ); + } + } + } + } + } + } + + /// Set the implementation for forward substring search. + /// + /// If the closure returns `None`, then it is assumed that the given + /// test cannot be applied to the particular implementation and it is + /// skipped. For example, if a particular implementation only supports + /// needles or haystacks for some minimum length. + /// + /// If this is not set, then forward substring search is not tested. + pub(crate) fn fwd( + mut self, + search: impl FnMut(&[u8], &[u8]) -> Option> + 'static, + ) -> Runner { + self.fwd = Some(Box::new(search)); + self + } + + /// Set the implementation for reverse substring search. + /// + /// If the closure returns `None`, then it is assumed that the given + /// test cannot be applied to the particular implementation and it is + /// skipped. For example, if a particular implementation only supports + /// needles or haystacks for some minimum length. + /// + /// If this is not set, then reverse substring search is not tested. + pub(crate) fn rev( + mut self, + search: impl FnMut(&[u8], &[u8]) -> Option> + 'static, + ) -> Runner { + self.rev = Some(Box::new(search)); + self + } +} + +/// A single substring test for forward and reverse searches. +#[derive(Clone, Debug)] +struct Test { + needle: String, + haystack: String, + fwd: Option, + rev: Option, +} + +/// A single substring test for forward and reverse searches. +/// +/// Each seed is valid on its own, but it also serves as a starting point +/// to generate more tests. Namely, we pad out the haystacks with other +/// characters so that we get more complete coverage. This is especially useful +/// for testing vector algorithms that tend to have weird special cases for +/// alignment and loop unrolling. +/// +/// Padding works by assuming certain characters never otherwise appear in a +/// needle or a haystack. Neither should contain a `#` character. +#[derive(Clone, Copy, Debug)] +struct Seed { + needle: &'static str, + haystack: &'static str, + fwd: Option, + rev: Option, +} + +impl Seed { + const MAX_PAD: usize = 34; + + const fn new( + needle: &'static str, + haystack: &'static str, + fwd: Option, + rev: Option, + ) -> Seed { + Seed { needle, haystack, fwd, rev } + } + + fn generate(self) -> impl Iterator { + assert!(!self.needle.contains('#'), "needle must not contain '#'"); + assert!(!self.haystack.contains('#'), "haystack must not contain '#'"); + (0..=Seed::MAX_PAD) + // Generate tests for padding at the beginning of haystack. + .map(move |pad| { + let needle = self.needle.to_string(); + let prefix = "#".repeat(pad); + let haystack = format!("{}{}", prefix, self.haystack); + let fwd = if needle.is_empty() { + Some(0) + } else { + self.fwd.map(|i| pad + i) + }; + let rev = if needle.is_empty() { + Some(haystack.len()) + } else { + self.rev.map(|i| pad + i) + }; + Test { needle, haystack, fwd, rev } + }) + // Generate tests for padding at the end of haystack. + .chain((1..=Seed::MAX_PAD).map(move |pad| { + let needle = self.needle.to_string(); + let suffix = "#".repeat(pad); + let haystack = format!("{}{}", self.haystack, suffix); + let fwd = if needle.is_empty() { Some(0) } else { self.fwd }; + let rev = if needle.is_empty() { + Some(haystack.len()) + } else { + self.rev + }; + Test { needle, haystack, fwd, rev } + })) + } +} diff --git a/third_party/crates/memchr-2.8.3/src/tests/substring/naive.rs b/third_party/crates/memchr-2.8.3/src/tests/substring/naive.rs new file mode 100644 index 0000000..1bc6009 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/tests/substring/naive.rs @@ -0,0 +1,45 @@ +/*! +This module defines "naive" implementations of substring search. + +These are sometimes useful to compare with "real" substring implementations. +The idea is that they are so simple that they are unlikely to be incorrect. +*/ + +/// Naively search forwards for the given needle in the given haystack. +pub(crate) fn find(haystack: &[u8], needle: &[u8]) -> Option { + let end = haystack.len().checked_sub(needle.len()).map_or(0, |i| i + 1); + for i in 0..end { + if needle == &haystack[i..i + needle.len()] { + return Some(i); + } + } + None +} + +/// Naively search in reverse for the given needle in the given haystack. +pub(crate) fn rfind(haystack: &[u8], needle: &[u8]) -> Option { + let end = haystack.len().checked_sub(needle.len()).map_or(0, |i| i + 1); + for i in (0..end).rev() { + if needle == &haystack[i..i + needle.len()] { + return Some(i); + } + } + None +} + +#[cfg(test)] +mod tests { + use crate::tests::substring; + + use super::*; + + #[test] + fn forward() { + substring::Runner::new().fwd(|h, n| Some(find(h, n))).run() + } + + #[test] + fn reverse() { + substring::Runner::new().rev(|h, n| Some(rfind(h, n))).run() + } +} diff --git a/third_party/crates/memchr-2.8.3/src/tests/substring/prop.rs b/third_party/crates/memchr-2.8.3/src/tests/substring/prop.rs new file mode 100644 index 0000000..a8352ec --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/tests/substring/prop.rs @@ -0,0 +1,126 @@ +/*! +This module defines a few quickcheck properties for substring search. + +It also provides a forward and reverse macro for conveniently defining +quickcheck tests that run these properties over any substring search +implementation. +*/ + +use crate::tests::substring::naive; + +/// $fwd is a `impl FnMut(haystack, needle) -> Option>`. When the +/// routine returns `None`, then it's skipped, which is useful for substring +/// implementations that don't work for all inputs. +#[macro_export] +macro_rules! define_substring_forward_quickcheck { + ($fwd:expr) => { + #[cfg(not(miri))] + quickcheck::quickcheck! { + fn qc_fwd_prefix_is_substring(bs: alloc::vec::Vec) -> bool { + crate::tests::substring::prop::prefix_is_substring(&bs, $fwd) + } + + fn qc_fwd_suffix_is_substring(bs: alloc::vec::Vec) -> bool { + crate::tests::substring::prop::suffix_is_substring(&bs, $fwd) + } + + fn qc_fwd_matches_naive( + haystack: alloc::vec::Vec, + needle: alloc::vec::Vec + ) -> bool { + crate::tests::substring::prop::same_as_naive( + false, + &haystack, + &needle, + $fwd, + ) + } + } + }; +} + +/// $rev is a `impl FnMut(haystack, needle) -> Option>`. When the +/// routine returns `None`, then it's skipped, which is useful for substring +/// implementations that don't work for all inputs. +#[macro_export] +macro_rules! define_substring_reverse_quickcheck { + ($rev:expr) => { + #[cfg(not(miri))] + quickcheck::quickcheck! { + fn qc_rev_prefix_is_substring(bs: alloc::vec::Vec) -> bool { + crate::tests::substring::prop::prefix_is_substring(&bs, $rev) + } + + fn qc_rev_suffix_is_substring(bs: alloc::vec::Vec) -> bool { + crate::tests::substring::prop::suffix_is_substring(&bs, $rev) + } + + fn qc_rev_matches_naive( + haystack: alloc::vec::Vec, + needle: alloc::vec::Vec + ) -> bool { + crate::tests::substring::prop::same_as_naive( + true, + &haystack, + &needle, + $rev, + ) + } + } + }; +} + +/// Check that every prefix of the given byte string is a substring. +pub(crate) fn prefix_is_substring( + bs: &[u8], + mut search: impl FnMut(&[u8], &[u8]) -> Option>, +) -> bool { + for i in 0..bs.len().saturating_sub(1) { + let prefix = &bs[..i]; + let result = match search(bs, prefix) { + None => continue, + Some(result) => result, + }; + if !result.is_some() { + return false; + } + } + true +} + +/// Check that every suffix of the given byte string is a substring. +pub(crate) fn suffix_is_substring( + bs: &[u8], + mut search: impl FnMut(&[u8], &[u8]) -> Option>, +) -> bool { + for i in 0..bs.len().saturating_sub(1) { + let suffix = &bs[i..]; + let result = match search(bs, suffix) { + None => continue, + Some(result) => result, + }; + if !result.is_some() { + return false; + } + } + true +} + +/// Check that naive substring search matches the result of the given search +/// algorithm. +pub(crate) fn same_as_naive( + reverse: bool, + haystack: &[u8], + needle: &[u8], + mut search: impl FnMut(&[u8], &[u8]) -> Option>, +) -> bool { + let result = match search(haystack, needle) { + None => return true, + Some(result) => result, + }; + if reverse { + result == naive::rfind(haystack, needle) + } else { + result == naive::find(haystack, needle) + } +} diff --git a/third_party/crates/memchr-2.8.3/src/vector.rs b/third_party/crates/memchr-2.8.3/src/vector.rs new file mode 100644 index 0000000..a243273 --- /dev/null +++ b/third_party/crates/memchr-2.8.3/src/vector.rs @@ -0,0 +1,514 @@ +/// A trait for describing vector operations used by vectorized searchers. +/// +/// The trait is highly constrained to low level vector operations needed. +/// In general, it was invented mostly to be generic over x86's __m128i and +/// __m256i types. At time of writing, it also supports wasm and aarch64 +/// 128-bit vector types as well. +/// +/// # Safety +/// +/// All methods are not safe since they are intended to be implemented using +/// vendor intrinsics, which are also not safe. Callers must ensure that the +/// appropriate target features are enabled in the calling function, and that +/// the current CPU supports them. All implementations should avoid marking the +/// routines with #[target_feature] and instead mark them as #[inline(always)] +/// to ensure they get appropriately inlined. (inline(always) cannot be used +/// with target_feature.) +pub(crate) trait Vector: Copy + core::fmt::Debug { + /// The number of bytes in the vector. That is, this is the size of the + /// vector in memory. + const BYTES: usize; + /// The bits that must be zero in order for a `*const u8` pointer to be + /// correctly aligned to read vector values. + const ALIGN: usize; + + /// The type of the value returned by `Vector::movemask`. + /// + /// This supports abstracting over the specific representation used in + /// order to accommodate different representations in different ISAs. + type Mask: MoveMask; + + /// Create a vector with 8-bit lanes with the given byte repeated into each + /// lane. + unsafe fn splat(byte: u8) -> Self; + + /// Read a vector-size number of bytes from the given pointer. The pointer + /// must be aligned to the size of the vector. + /// + /// # Safety + /// + /// Callers must guarantee that at least `BYTES` bytes are readable from + /// `data` and that `data` is aligned to a `BYTES` boundary. + unsafe fn load_aligned(data: *const u8) -> Self; + + /// Read a vector-size number of bytes from the given pointer. The pointer + /// does not need to be aligned. + /// + /// # Safety + /// + /// Callers must guarantee that at least `BYTES` bytes are readable from + /// `data`. + unsafe fn load_unaligned(data: *const u8) -> Self; + + /// _mm_movemask_epi8 or _mm256_movemask_epi8 + unsafe fn movemask(self) -> Self::Mask; + /// _mm_cmpeq_epi8 or _mm256_cmpeq_epi8 + unsafe fn cmpeq(self, vector2: Self) -> Self; + /// _mm_and_si128 or _mm256_and_si256 + unsafe fn and(self, vector2: Self) -> Self; + /// _mm_or or _mm256_or_si256 + unsafe fn or(self, vector2: Self) -> Self; + /// Returns true if and only if `Self::movemask` would return a mask that + /// contains at least one non-zero bit. + unsafe fn movemask_will_have_non_zero(self) -> bool { + self.movemask().has_non_zero() + } +} + +/// A trait that abstracts over a vector-to-scalar operation called +/// "move mask." +/// +/// On x86-64, this is `_mm_movemask_epi8` for SSE2 and `_mm256_movemask_epi8` +/// for AVX2. It takes a vector of `u8` lanes and returns a scalar where the +/// `i`th bit is set if and only if the most significant bit in the `i`th lane +/// of the vector is set. The simd128 ISA for wasm32 also supports this +/// exact same operation natively. +/// +/// ... But aarch64 doesn't. So we have to fake it with more instructions and +/// a slightly different representation. We could do extra work to unify the +/// representations, but then would require additional costs in the hot path +/// for `memchr` and `packedpair`. So instead, we abstraction over the specific +/// representation with this trait and define the operations we actually need. +pub(crate) trait MoveMask: Copy + core::fmt::Debug { + /// Return a mask that is all zeros except for the least significant `n` + /// lanes in a corresponding vector. + fn all_zeros_except_least_significant(n: usize) -> Self; + + /// Returns true if and only if this mask has a a non-zero bit anywhere. + fn has_non_zero(self) -> bool; + + /// Returns the number of bits set to 1 in this mask. + fn count_ones(self) -> usize; + + /// Does a bitwise `and` operation between `self` and `other`. + fn and(self, other: Self) -> Self; + + /// Does a bitwise `or` operation between `self` and `other`. + fn or(self, other: Self) -> Self; + + /// Returns a mask that is equivalent to `self` but with the least + /// significant 1-bit set to 0. + fn clear_least_significant_bit(self) -> Self; + + /// Returns the offset of the first non-zero lane this mask represents. + fn first_offset(self) -> usize; + + /// Returns the offset of the last non-zero lane this mask represents. + fn last_offset(self) -> usize; +} + +/// This is a "sensible" movemask implementation where each bit represents +/// whether the most significant bit is set in each corresponding lane of a +/// vector. This is used on x86-64 and wasm, but such a mask is more expensive +/// to get on aarch64 so we use something a little different. +/// +/// We call this "sensible" because this is what we get using native sse/avx +/// movemask instructions. But neon has no such native equivalent. +#[derive(Clone, Copy, Debug)] +pub(crate) struct SensibleMoveMask(u32); + +impl SensibleMoveMask { + /// Get the mask in a form suitable for computing offsets. + /// + /// Basically, this normalizes to little endian. On big endian, this swaps + /// the bytes. + #[inline(always)] + fn get_for_offset(self) -> u32 { + #[cfg(target_endian = "big")] + { + self.0.swap_bytes() + } + #[cfg(target_endian = "little")] + { + self.0 + } + } +} + +impl MoveMask for SensibleMoveMask { + #[inline(always)] + fn all_zeros_except_least_significant(n: usize) -> SensibleMoveMask { + debug_assert!(n < 32); + SensibleMoveMask(!((1 << n) - 1)) + } + + #[inline(always)] + fn has_non_zero(self) -> bool { + self.0 != 0 + } + + #[inline(always)] + fn count_ones(self) -> usize { + self.0.count_ones() as usize + } + + #[inline(always)] + fn and(self, other: SensibleMoveMask) -> SensibleMoveMask { + SensibleMoveMask(self.0 & other.0) + } + + #[inline(always)] + fn or(self, other: SensibleMoveMask) -> SensibleMoveMask { + SensibleMoveMask(self.0 | other.0) + } + + #[inline(always)] + fn clear_least_significant_bit(self) -> SensibleMoveMask { + SensibleMoveMask(self.0 & (self.0 - 1)) + } + + #[inline(always)] + fn first_offset(self) -> usize { + // We are dealing with little endian here (and if we aren't, we swap + // the bytes so we are in practice), where the most significant byte + // is at a higher address. That means the least significant bit that + // is set corresponds to the position of our first matching byte. + // That position corresponds to the number of zeros after the least + // significant bit. + self.get_for_offset().trailing_zeros() as usize + } + + #[inline(always)] + fn last_offset(self) -> usize { + // We are dealing with little endian here (and if we aren't, we swap + // the bytes so we are in practice), where the most significant byte is + // at a higher address. That means the most significant bit that is set + // corresponds to the position of our last matching byte. The position + // from the end of the mask is therefore the number of leading zeros + // in a 32 bit integer, and the position from the start of the mask is + // therefore 32 - (leading zeros) - 1. + 32 - self.get_for_offset().leading_zeros() as usize - 1 + } +} + +#[cfg(target_arch = "x86_64")] +mod x86sse2 { + use core::arch::x86_64::*; + + use super::{SensibleMoveMask, Vector}; + + impl Vector for __m128i { + const BYTES: usize = 16; + const ALIGN: usize = Self::BYTES - 1; + + type Mask = SensibleMoveMask; + + #[inline(always)] + unsafe fn splat(byte: u8) -> __m128i { + _mm_set1_epi8(byte as i8) + } + + #[inline(always)] + unsafe fn load_aligned(data: *const u8) -> __m128i { + _mm_load_si128(data as *const __m128i) + } + + #[inline(always)] + unsafe fn load_unaligned(data: *const u8) -> __m128i { + _mm_loadu_si128(data as *const __m128i) + } + + #[inline(always)] + unsafe fn movemask(self) -> SensibleMoveMask { + SensibleMoveMask(_mm_movemask_epi8(self) as u32) + } + + #[inline(always)] + unsafe fn cmpeq(self, vector2: Self) -> __m128i { + _mm_cmpeq_epi8(self, vector2) + } + + #[inline(always)] + unsafe fn and(self, vector2: Self) -> __m128i { + _mm_and_si128(self, vector2) + } + + #[inline(always)] + unsafe fn or(self, vector2: Self) -> __m128i { + _mm_or_si128(self, vector2) + } + } +} + +#[cfg(target_arch = "x86_64")] +mod x86avx2 { + use core::arch::x86_64::*; + + use super::{SensibleMoveMask, Vector}; + + impl Vector for __m256i { + const BYTES: usize = 32; + const ALIGN: usize = Self::BYTES - 1; + + type Mask = SensibleMoveMask; + + #[inline(always)] + unsafe fn splat(byte: u8) -> __m256i { + _mm256_set1_epi8(byte as i8) + } + + #[inline(always)] + unsafe fn load_aligned(data: *const u8) -> __m256i { + _mm256_load_si256(data as *const __m256i) + } + + #[inline(always)] + unsafe fn load_unaligned(data: *const u8) -> __m256i { + _mm256_loadu_si256(data as *const __m256i) + } + + #[inline(always)] + unsafe fn movemask(self) -> SensibleMoveMask { + SensibleMoveMask(_mm256_movemask_epi8(self) as u32) + } + + #[inline(always)] + unsafe fn cmpeq(self, vector2: Self) -> __m256i { + _mm256_cmpeq_epi8(self, vector2) + } + + #[inline(always)] + unsafe fn and(self, vector2: Self) -> __m256i { + _mm256_and_si256(self, vector2) + } + + #[inline(always)] + unsafe fn or(self, vector2: Self) -> __m256i { + _mm256_or_si256(self, vector2) + } + } +} + +#[cfg(target_arch = "aarch64")] +mod aarch64neon { + use core::arch::aarch64::*; + + use super::{MoveMask, Vector}; + + impl Vector for uint8x16_t { + const BYTES: usize = 16; + const ALIGN: usize = Self::BYTES - 1; + + type Mask = NeonMoveMask; + + #[inline(always)] + unsafe fn splat(byte: u8) -> uint8x16_t { + vdupq_n_u8(byte) + } + + #[inline(always)] + unsafe fn load_aligned(data: *const u8) -> uint8x16_t { + // I've tried `data.cast::().read()` instead, but + // couldn't observe any benchmark differences. + Self::load_unaligned(data) + } + + #[inline(always)] + unsafe fn load_unaligned(data: *const u8) -> uint8x16_t { + vld1q_u8(data) + } + + #[inline(always)] + #[cfg(target_endian = "little")] + unsafe fn movemask(self) -> NeonMoveMask { + let asu16s = vreinterpretq_u16_u8(self); + let mask = vshrn_n_u16(asu16s, 4); + let asu64 = vreinterpret_u64_u8(mask); + let scalar64 = vget_lane_u64(asu64, 0); + NeonMoveMask(scalar64 & 0x8888888888888888) + } + + #[inline(always)] + #[cfg(target_endian = "big")] + unsafe fn movemask(self) -> NeonMoveMask { + // Swap the endianness of each 16-bit input. + let asu16s = vreinterpretq_u16_u8(vrev16q_u8(self)); + let mask = vshrn_n_u16(asu16s, 4); + let asu64 = vreinterpret_u64_u8(mask); + // Use `swap_bytes` to swap the endianness of the 64-bit output. + let scalar64 = vget_lane_u64(asu64, 0).swap_bytes(); + NeonMoveMask(scalar64 & 0x8888888888888888) + } + + #[inline(always)] + unsafe fn cmpeq(self, vector2: Self) -> uint8x16_t { + vceqq_u8(self, vector2) + } + + #[inline(always)] + unsafe fn and(self, vector2: Self) -> uint8x16_t { + vandq_u8(self, vector2) + } + + #[inline(always)] + unsafe fn or(self, vector2: Self) -> uint8x16_t { + vorrq_u8(self, vector2) + } + + /// This is the only interesting implementation of this routine. + /// Basically, instead of doing the "shift right narrow" dance, we use + /// adjacent folding max to determine whether there are any non-zero + /// bytes in our mask. If there are, *then* we'll do the "shift right + /// narrow" dance. In benchmarks, this does lead to slightly better + /// throughput, but the win doesn't appear huge. + #[inline(always)] + unsafe fn movemask_will_have_non_zero(self) -> bool { + let low = vreinterpretq_u64_u8(vpmaxq_u8(self, self)); + vgetq_lane_u64(low, 0) != 0 + } + } + + /// Neon doesn't have a `movemask` that works like the one in x86-64, so we + /// wind up using a different method[1]. The different method also produces + /// a mask, but 4 bits are set in the neon case instead of a single bit set + /// in the x86-64 case. We do an extra step to zero out 3 of the 4 bits, + /// but we still wind up with at least 3 zeroes between each set bit. This + /// generally means that we need to do some division by 4 before extracting + /// offsets. + /// + /// In fact, the existence of this type is the entire reason that we have + /// the `MoveMask` trait in the first place. This basically lets us keep + /// the different representations of masks without being forced to unify + /// them into a single representation, which could result in extra and + /// unnecessary work. + /// + /// [1]: https://community.arm.com/arm-community-blogs/b/infrastructure-solutions-blog/posts/porting-x86-vector-bitmask-optimizations-to-arm-neon + #[derive(Clone, Copy, Debug)] + pub(crate) struct NeonMoveMask(u64); + + impl NeonMoveMask { + /// Get the mask in a form suitable for computing offsets. + /// + /// The mask is always already in host-endianness, so this is a no-op. + #[inline(always)] + fn get_for_offset(self) -> u64 { + self.0 + } + } + + impl MoveMask for NeonMoveMask { + #[inline(always)] + fn all_zeros_except_least_significant(n: usize) -> NeonMoveMask { + debug_assert!(n < 16); + NeonMoveMask(!(((1 << n) << 2) - 1)) + } + + #[inline(always)] + fn has_non_zero(self) -> bool { + self.0 != 0 + } + + #[inline(always)] + fn count_ones(self) -> usize { + self.0.count_ones() as usize + } + + #[inline(always)] + fn and(self, other: NeonMoveMask) -> NeonMoveMask { + NeonMoveMask(self.0 & other.0) + } + + #[inline(always)] + fn or(self, other: NeonMoveMask) -> NeonMoveMask { + NeonMoveMask(self.0 | other.0) + } + + #[inline(always)] + fn clear_least_significant_bit(self) -> NeonMoveMask { + NeonMoveMask(self.0 & (self.0 - 1)) + } + + #[inline(always)] + fn first_offset(self) -> usize { + // We are dealing with little endian here (and if we aren't, + // we swap the bytes so we are in practice), where the most + // significant byte is at a higher address. That means the least + // significant bit that is set corresponds to the position of our + // first matching byte. That position corresponds to the number of + // zeros after the least significant bit. + // + // Note that unlike `SensibleMoveMask`, this mask has its bits + // spread out over 64 bits instead of 16 bits (for a 128 bit + // vector). Namely, where as x86-64 will turn + // + // 0x00 0xFF 0x00 0x00 0xFF + // + // into 10010, our neon approach will turn it into + // + // 10000000000010000000 + // + // And this happens because neon doesn't have a native `movemask` + // instruction, so we kind of fake it[1]. Thus, we divide the + // number of trailing zeros by 4 to get the "real" offset. + // + // [1]: https://community.arm.com/arm-community-blogs/b/infrastructure-solutions-blog/posts/porting-x86-vector-bitmask-optimizations-to-arm-neon + (self.get_for_offset().trailing_zeros() >> 2) as usize + } + + #[inline(always)] + fn last_offset(self) -> usize { + // See comment in `first_offset` above. This is basically the same, + // but coming from the other direction. + 16 - (self.get_for_offset().leading_zeros() >> 2) as usize - 1 + } + } +} + +#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))] +mod wasm_simd128 { + use core::arch::wasm32::*; + + use super::{SensibleMoveMask, Vector}; + + impl Vector for v128 { + const BYTES: usize = 16; + const ALIGN: usize = Self::BYTES - 1; + + type Mask = SensibleMoveMask; + + #[inline(always)] + unsafe fn splat(byte: u8) -> v128 { + u8x16_splat(byte) + } + + #[inline(always)] + unsafe fn load_aligned(data: *const u8) -> v128 { + *data.cast() + } + + #[inline(always)] + unsafe fn load_unaligned(data: *const u8) -> v128 { + v128_load(data.cast()) + } + + #[inline(always)] + unsafe fn movemask(self) -> SensibleMoveMask { + SensibleMoveMask(u8x16_bitmask(self).into()) + } + + #[inline(always)] + unsafe fn cmpeq(self, vector2: Self) -> v128 { + u8x16_eq(self, vector2) + } + + #[inline(always)] + unsafe fn and(self, vector2: Self) -> v128 { + v128_and(self, vector2) + } + + #[inline(always)] + unsafe fn or(self, vector2: Self) -> v128 { + v128_or(self, vector2) + } + } +} diff --git a/third_party/crates/proc-macro2-1.0.107/.cargo-checksum.json b/third_party/crates/proc-macro2-1.0.107/.cargo-checksum.json new file mode 100644 index 0000000..e391c5d --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/.cargo-checksum.json @@ -0,0 +1 @@ +{"$comment":"This file only protects against accidental modifications. It is not a security mechanism and does not protect against malicious changes.","files":{".cargo_vcs_info.json":"0a870b23ea0c10231ed5a850b8fe8f23dd74926e90594e49a35a7e1b5e8a92f5",".github/FUNDING.yml":"b017158736b3c9751a2d21edfce7fe61c8954e2fced8da8dd3013c2f3e295bd9",".github/workflows/ci.yml":"f0003fd6c9bd0f9208f552a57dd5dd76fee714a7d0be286cecc98f06add580ff","Cargo.lock":"30daf1b1e7557b089dfe7783a6cdd8bd7b4f82b31eaaa554c1afbca448f3a936","Cargo.toml":"6bdbe54a7f052e552dcfca90351764476e2767237ec3f954df8bd9f602861056","Cargo.toml.orig":"e04a009c48ea3e9b017807ea9183e330cc909a9cc0e754c5c6b3f7c0b29fb9de","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"8eebdcf2f9a5034693589a9982adf06c2aac5c9f078c07a44400d293ed5b4a8e","build.rs":"baeb20b52f6b536be8657a566591a507bb2e34a45cf8baa42b135510a0c3c729","rust-toolchain.toml":"6bbb61302978c736b2da03e4fb40e3beab908f85d533ab46fd541e637b5f3e0f","src/detection.rs":"ed9a5f9a979ab01247d7a68eeb1afa3c13209334c5bfff0f9289cb07e5bb4e8b","src/extra.rs":"29f094473279a29b71c3cc9f5fa27c2e2c30c670390cf7e4b7cf451486cc857e","src/fallback.rs":"416a3d24349c163d47f62ac8ae61c28ba6dc4990f04f3d5dacde030b86582d06","src/lib.rs":"ed6bf5e3c3b4fc952d4bdf9b48b149087bceaebf5392befce0bc6cae590a008d","src/location.rs":"9225c5a55f03b56cce42bc55ceb509e8216a5e0b24c94aa1cd071b04e3d6c15f","src/marker.rs":"c11c5a1be8bdf18be3fcd224393f350a9aae7ce282e19ce583c84910c6903a8f","src/num.rs":"82d625cbcd255965e46231ac3af1b74ab8bff9787c799e8ed1f978de146cb0b5","src/parse.rs":"1257d423e9311dda9db0239ff244dfe7b028c1048ab8a83d76daec6068b05114","src/probe.rs":"2b57e8ebf46a7c60ee2762f23f16d24ee9ddb8f1acd0a7faf7a99cf2e4187151","src/probe/proc_macro_span.rs":"53853f0c70170c9695294b8867821664d9b8f1c901957b003003a3c26987abbe","src/probe/proc_macro_span_file.rs":"e7fb4cf8852d9d589bfa3321d8d5cdc8cccb45606ec816a6b8a08f73e416b9ce","src/probe/proc_macro_span_location.rs":"e022386204b6e042b3c55a6c809923849a2f915199bcbf3be72d0b7c8ffa7f83","src/rcvec.rs":"d6e4c1ea42f75e63465fce50ca83f9257536ccdc0345fe78b0037aa2c08c5e37","src/rustc_literal_escaper.rs":"fb3f2f93a09b84f539e6ef514d4b403ee16f2112ff04642099170a60828318ee","src/wrapper.rs":"21a563ef1eec685e3d60ee0479812f212c578dc6d405053b7827c46f6801fdc6","tests/comments.rs":"11520f6baee23b9258db904f4c256fd3877493f754e2b99041f73a330e74a911","tests/features.rs":"7e52c0c801019b271bf11a994c2e1799a1429b0c1a3a34e551a23971797fe412","tests/marker.rs":"f16299460587d6c65603ed809f1a3b81853e4b99d6cb44d0b68bb07259d7e9f8","tests/test.rs":"7d58c3a754241ffdec84e4e9ac799852071db71d77359de164ca7ba6217020e9","tests/test_fmt.rs":"1fa3a817bf934c3bb38942e56eecb70ef525710c6bcfec0356adec654b053c0b","tests/test_size.rs":"7ed5f07c3ccc74c4d09f3c1c43542fbbe23417146761558a0fd4659e19ae1afc"},"package":"985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"} \ No newline at end of file diff --git a/third_party/crates/proc-macro2-1.0.107/.cargo_vcs_info.json b/third_party/crates/proc-macro2-1.0.107/.cargo_vcs_info.json new file mode 100644 index 0000000..61f4171 --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "ed8a5497669cd63db33bf24646f261b012bbbc4a" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/third_party/crates/proc-macro2-1.0.107/.github/FUNDING.yml b/third_party/crates/proc-macro2-1.0.107/.github/FUNDING.yml new file mode 100644 index 0000000..7507077 --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/.github/FUNDING.yml @@ -0,0 +1 @@ +github: dtolnay diff --git a/third_party/crates/proc-macro2-1.0.107/.github/workflows/ci.yml b/third_party/crates/proc-macro2-1.0.107/.github/workflows/ci.yml new file mode 100644 index 0000000..a14d4ab --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/.github/workflows/ci.yml @@ -0,0 +1,232 @@ +name: CI + +on: + push: + pull_request: + workflow_dispatch: + schedule: [cron: "40 1 * * *"] + +permissions: + contents: read + +env: + RUSTFLAGS: -Dwarnings + +jobs: + pre_ci: + uses: dtolnay/.github/.github/workflows/pre_ci.yml@master + + test: + name: Rust ${{matrix.rust}} + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + rust: [1.80.0, stable, beta] + timeout-minutes: 45 + steps: + - uses: actions/checkout@v7 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{matrix.rust}} + components: rust-src + - run: cargo test + - run: cargo test --no-default-features + - run: cargo test --features span-locations + - name: RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo test + run: cargo test + env: + RUSTFLAGS: --cfg procmacro2_semver_exempt ${{env.RUSTFLAGS}} + - name: RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo test --no-default-features + run: cargo test --no-default-features + env: + RUSTFLAGS: --cfg procmacro2_semver_exempt ${{env.RUSTFLAGS}} + + nightly: + name: Rust nightly + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@v7 + - uses: dtolnay/rust-toolchain@nightly + with: + components: rust-src + - name: Enable type layout randomization + run: echo RUSTFLAGS=${RUSTFLAGS}\ -Zrandomize-layout\ --cfg=randomize_layout >> $GITHUB_ENV + - run: cargo check + env: + RUSTFLAGS: --cfg procmacro2_nightly_testing ${{env.RUSTFLAGS}} + - run: cargo test + - run: cargo test --no-default-features + - run: cargo test --no-default-features --test features -- --ignored make_sure_no_proc_macro # run the ignored test to make sure the `proc-macro` feature is disabled + - run: cargo test --features span-locations + - run: cargo test --manifest-path tests/ui/Cargo.toml + - name: RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo test + run: cargo test + env: + RUSTFLAGS: --cfg procmacro2_semver_exempt ${{env.RUSTFLAGS}} + - name: RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo test --no-default-features + run: cargo test --no-default-features + env: + RUSTFLAGS: --cfg procmacro2_semver_exempt ${{env.RUSTFLAGS}} + - name: RUSTFLAGS='-Z allow-features=' cargo test + run: cargo test + env: + RUSTFLAGS: -Z allow-features= --cfg procmacro2_backtrace ${{env.RUSTFLAGS}} + - uses: actions/upload-artifact@v7 + if: always() + with: + name: Cargo.lock + path: Cargo.lock + continue-on-error: true + + layout: + name: Layout + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@v7 + - uses: dtolnay/rust-toolchain@nightly + with: + components: rust-src + - run: cargo test --test test_size + - run: cargo test --test test_size --features span-locations + - run: cargo test --test test_size --no-default-features + - run: cargo test --test test_size --no-default-features --features span-locations + + msrv: + name: Rust 1.71.0 + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@v7 + - uses: dtolnay/rust-toolchain@1.71.0 + with: + components: rust-src + - run: cargo check + - run: cargo check --no-default-features + - run: cargo check --features span-locations + - name: RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo check + run: cargo check + env: + RUSTFLAGS: --cfg procmacro2_semver_exempt ${{env.RUSTFLAGS}} + - name: RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo check --no-default-features + run: cargo check --no-default-features + env: + RUSTFLAGS: --cfg procmacro2_semver_exempt ${{env.RUSTFLAGS}} + + minimal: + name: Minimal versions + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@v7 + - uses: dtolnay/rust-toolchain@nightly + - run: cargo generate-lockfile -Z minimal-versions + - run: cargo check --locked + + webassembly: + name: WebAssembly + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@v7 + - uses: dtolnay/rust-toolchain@nightly + with: + target: wasm32-unknown-unknown + components: rust-src + - name: Ignore WebAssembly linker warning + run: echo RUSTFLAGS=${RUSTFLAGS}\ -Alinker_messages >> $GITHUB_ENV + - run: cargo test --target wasm32-unknown-unknown --no-run + + fuzz: + name: Fuzz + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@v7 + - uses: dtolnay/rust-toolchain@nightly + with: + components: rust-src + - uses: dtolnay/install@cargo-fuzz + - run: cargo fuzz check + - run: cargo check --no-default-features --features afl + working-directory: fuzz + - uses: dtolnay/install@honggfuzz + - name: Run apt install binutils-dev libunwind-dev + run: | + sudo sed -i 's/^update_initramfs=yes$/update_initramfs=no/' /etc/initramfs-tools/update-initramfs.conf + sudo rm -f /var/lib/man-db/auto-update + sudo apt-get update + sudo apt-get install binutils-dev libunwind-dev + - run: cargo hfuzz build --no-default-features --features honggfuzz + working-directory: fuzz + + doc: + name: Documentation + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + timeout-minutes: 45 + env: + RUSTDOCFLAGS: -Dwarnings + steps: + - uses: actions/checkout@v7 + - uses: dtolnay/rust-toolchain@nightly + with: + components: rust-src + - uses: dtolnay/install@cargo-docs-rs + - run: cargo docs-rs + + clippy: + name: Clippy + runs-on: ubuntu-latest + if: github.event_name != 'pull_request' + timeout-minutes: 45 + steps: + - uses: actions/checkout@v7 + - uses: dtolnay/rust-toolchain@nightly + with: + components: clippy, rust-src + - run: cargo clippy --tests -- -Dclippy::all -Dclippy::pedantic + - run: cargo clippy --tests --all-features -- -Dclippy::all -Dclippy::pedantic + + miri: + name: Miri + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@v7 + - uses: dtolnay/rust-toolchain@miri + - run: cargo miri setup + - run: cargo miri test + 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@v7 + - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/install@cargo-outdated + - run: cargo outdated --workspace --exit-code 1 + - run: cargo outdated --manifest-path fuzz/Cargo.toml --exit-code 1 diff --git a/third_party/crates/proc-macro2-1.0.107/BUILD.bazel b/third_party/crates/proc-macro2-1.0.107/BUILD.bazel new file mode 100644 index 0000000..bf55969 --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/BUILD.bazel @@ -0,0 +1,186 @@ +############################################################################### +# @generated +# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To +# regenerate this file, run the following: +# +# bazel run @@//third_party:vendor_crates +############################################################################### + +load( + "@rules_rust//cargo:defs.bzl", + "cargo_build_script", + "cargo_toml_env_vars", +) +load("@rules_rust//rust:defs.bzl", "rust_library") + +package(default_visibility = ["//visibility:public"]) + +cargo_toml_env_vars( + name = "cargo_toml_env_vars", + src = "Cargo.toml", +) + +rust_library( + name = "proc_macro2", + srcs = glob( + include = ["**/*.rs"], + allow_empty = False, + ), + compile_data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + crate_features = [ + "proc-macro", + ], + crate_root = "src/lib.rs", + edition = "2021", + rustc_env_files = [ + ":cargo_toml_env_vars", + ], + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=proc-macro2", + "manual", + "noclippy", + "norustfmt", + ], + target_compatible_with = select({ + "@rules_rust//rust/platform:aarch64-apple-darwin": [], + "@rules_rust//rust/platform:aarch64-apple-ios": [], + "@rules_rust//rust/platform:aarch64-apple-ios-macabi": [], + "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], + "@rules_rust//rust/platform:aarch64-linux-android": [], + "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], + "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], + "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-none": [], + "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], + "@rules_rust//rust/platform:aarch64-unknown-uefi": [], + "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], + "@rules_rust//rust/platform:armv7-linux-androideabi": [], + "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:i686-apple-darwin": [], + "@rules_rust//rust/platform:i686-linux-android": [], + "@rules_rust//rust/platform:i686-pc-windows-msvc": [], + "@rules_rust//rust/platform:i686-unknown-freebsd": [], + "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], + "@rules_rust//rust/platform:loongarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:mips-unknown-linux-gnu": [], + "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv32imac-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], + "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-netbsd": [], + "@rules_rust//rust/platform:sparc64-unknown-openbsd": [], + "@rules_rust//rust/platform:thumbv6m-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabihf": [], + "@rules_rust//rust/platform:thumbv7m-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabihf": [], + "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], + "@rules_rust//rust/platform:wasm32-unknown-unknown": [], + "@rules_rust//rust/platform:wasm32-wasip1": [], + "@rules_rust//rust/platform:wasm32-wasip1-threads": [], + "@rules_rust//rust/platform:wasm32-wasip2": [], + "@rules_rust//rust/platform:x86_64-apple-darwin": [], + "@rules_rust//rust/platform:x86_64-apple-ios": [], + "@rules_rust//rust/platform:x86_64-apple-ios-macabi": [], + "@rules_rust//rust/platform:x86_64-linux-android": [], + "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], + "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], + "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], + "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-none": [], + "@rules_rust//rust/platform:x86_64-unknown-uefi": [], + "//conditions:default": ["@platforms//:incompatible"], + }), + version = "1.0.107", + deps = [ + ":build_script_build", + "//third_party/crates/unicode-ident-1.0.24:unicode_ident", + ], +) + +cargo_build_script( + name = "_bs", + srcs = glob( + include = ["**/*.rs"], + allow_empty = False, + ), + build_script_env_files = [ + ":cargo_toml_env_vars", + ], + compile_data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + "**/*.rs", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + crate_features = [ + "proc-macro", + ], + crate_name = "build_script_build", + crate_root = "build.rs", + data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + edition = "2021", + emit_warnings = False, + pkg_name = "proc-macro2", + rustc_env_files = [ + ":cargo_toml_env_vars", + ], + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=proc-macro2", + "manual", + "noclippy", + "norustfmt", + ], + version = "1.0.107", + visibility = ["//visibility:private"], +) + +alias( + name = "build_script_build", + actual = ":_bs", + tags = ["manual"], +) diff --git a/third_party/crates/proc-macro2-1.0.107/Cargo.lock b/third_party/crates/proc-macro2-1.0.107/Cargo.lock new file mode 100644 index 0000000..5545076 --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/Cargo.lock @@ -0,0 +1,230 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "bitflags" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" + +[[package]] +name = "either" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "filetime" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759" +dependencies = [ + "cfg-if", + "libc", +] + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +dependencies = [ + "flate2", + "quote", + "rayon", + "rustversion", + "tar", + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2 1.0.106", +] + +[[package]] +name = "rayon" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "simd-adler32" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" + +[[package]] +name = "tar" +version = "0.4.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix", +] diff --git a/third_party/crates/proc-macro2-1.0.107/Cargo.toml b/third_party/crates/proc-macro2-1.0.107/Cargo.toml new file mode 100644 index 0000000..4bfeee3 --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/Cargo.toml @@ -0,0 +1,105 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.71" +name = "proc-macro2" +version = "1.0.107" +authors = [ + "David Tolnay ", + "Alex Crichton ", +] +build = "build.rs" +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "A substitute implementation of the compiler's `proc_macro` API to decouple token-based libraries from the procedural macro use case." +documentation = "https://docs.rs/proc-macro2" +readme = "README.md" +keywords = [ + "macros", + "syn", +] +categories = ["development-tools::procedural-macro-helpers"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/dtolnay/proc-macro2" + +[package.metadata.docs.rs] +rustc-args = ["--cfg=procmacro2_semver_exempt"] +targets = ["x86_64-unknown-linux-gnu"] +rustdoc-args = [ + "--cfg=procmacro2_semver_exempt", + "--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", +] + +[package.metadata.playground] +features = ["span-locations"] + +[features] +default = ["proc-macro"] +nightly = [] +proc-macro = [] +span-locations = [] + +[lib] +name = "proc_macro2" +path = "src/lib.rs" + +[[test]] +name = "comments" +path = "tests/comments.rs" + +[[test]] +name = "features" +path = "tests/features.rs" + +[[test]] +name = "marker" +path = "tests/marker.rs" + +[[test]] +name = "test" +path = "tests/test.rs" + +[[test]] +name = "test_fmt" +path = "tests/test_fmt.rs" + +[[test]] +name = "test_size" +path = "tests/test_size.rs" + +[dependencies.unicode-ident] +version = "1.0" + +[dev-dependencies.flate2] +version = "1.0" + +[dev-dependencies.quote] +version = "1.0" +default-features = false + +[dev-dependencies.rayon] +version = "1.0" + +[dev-dependencies.rustversion] +version = "1" + +[dev-dependencies.tar] +version = "0.4" diff --git a/third_party/crates/proc-macro2-1.0.107/Cargo.toml.orig b/third_party/crates/proc-macro2-1.0.107/Cargo.toml.orig new file mode 100644 index 0000000..0edc0fd --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/Cargo.toml.orig @@ -0,0 +1,67 @@ +[package] +name = "proc-macro2" +version = "1.0.107" +authors = ["David Tolnay ", "Alex Crichton "] +autobenches = false +categories = ["development-tools::procedural-macro-helpers"] +description = "A substitute implementation of the compiler's `proc_macro` API to decouple token-based libraries from the procedural macro use case." +documentation = "https://docs.rs/proc-macro2" +edition = "2021" +keywords = ["macros", "syn"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/dtolnay/proc-macro2" +rust-version = "1.71" + +[package.metadata.docs.rs] +rustc-args = ["--cfg=procmacro2_semver_exempt"] +targets = ["x86_64-unknown-linux-gnu"] +rustdoc-args = [ + "--cfg=procmacro2_semver_exempt", + "--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", +] + +[package.metadata.playground] +features = ["span-locations"] + +[dependencies] +unicode-ident = "1.0" + +[dev-dependencies] +flate2 = "1.0" +quote = { version = "1.0", default-features = false } +rayon = "1.0" +rustversion = "1" +tar = "0.4" + +[features] +proc-macro = [] +default = ["proc-macro"] + +# Expose methods Span::start and Span::end which give the line/column location +# of a token. +span-locations = [] + +# This feature no longer means anything. +nightly = [] + +[workspace] +members = ["benches/bench-libproc-macro", "tests/ui"] + +[patch.crates-io] +# Our doc tests depend on quote which depends on proc-macro2. Without this line, +# the proc-macro2 dependency of quote would be the released version of +# proc-macro2. Quote would implement its traits for types from that proc-macro2, +# meaning impls would be missing when tested against types from the local +# proc-macro2. +# +# GitHub Actions builds that are in progress at the time that you publish may +# spuriously fail. This is because they'll be building a local proc-macro2 which +# carries the second-most-recent version number, pulling in quote which resolves +# to a dependency on the just-published most recent version number. Thus the +# patch will fail to apply because the version numbers are different. +proc-macro2 = { path = "." } diff --git a/third_party/crates/proc-macro2-1.0.107/LICENSE-APACHE b/third_party/crates/proc-macro2-1.0.107/LICENSE-APACHE new file mode 100644 index 0000000..1b5ec8b --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/third_party/crates/proc-macro2-1.0.107/LICENSE-MIT b/third_party/crates/proc-macro2-1.0.107/LICENSE-MIT new file mode 100644 index 0000000..31aa793 --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/crates/proc-macro2-1.0.107/README.md b/third_party/crates/proc-macro2-1.0.107/README.md new file mode 100644 index 0000000..ab8ca4e --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/README.md @@ -0,0 +1,94 @@ +# proc-macro2 + +[github](https://github.com/dtolnay/proc-macro2) +[crates.io](https://crates.io/crates/proc-macro2) +[docs.rs](https://docs.rs/proc-macro2) +[build status](https://github.com/dtolnay/proc-macro2/actions?query=branch%3Amaster) + +A wrapper around the procedural macro API of the compiler's `proc_macro` crate. +This library serves two purposes: + +- **Bring proc-macro-like functionality to other contexts like build.rs and + main.rs.** Types from `proc_macro` are entirely specific to procedural macros + and cannot ever exist in code outside of a procedural macro. Meanwhile + `proc_macro2` types may exist anywhere including non-macro code. By developing + foundational libraries like [syn] and [quote] against `proc_macro2` rather + than `proc_macro`, the procedural macro ecosystem becomes easily applicable to + many other use cases and we avoid reimplementing non-macro equivalents of + those libraries. + +- **Make procedural macros unit testable.** As a consequence of being specific + to procedural macros, nothing that uses `proc_macro` can be executed from a + unit test. In order for helper libraries or components of a macro to be + testable in isolation, they must be implemented using `proc_macro2`. + +[syn]: https://github.com/dtolnay/syn +[quote]: https://github.com/dtolnay/quote + +## Usage + +```toml +[dependencies] +proc-macro2 = "1.0" +``` + +The skeleton of a typical procedural macro typically looks like this: + +```rust +extern crate proc_macro; + +#[proc_macro_derive(MyDerive)] +pub fn my_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let input = proc_macro2::TokenStream::from(input); + + let output: proc_macro2::TokenStream = { + /* transform input */ + }; + + proc_macro::TokenStream::from(output) +} +``` + +If parsing with [Syn], you'll use [`parse_macro_input!`] instead to propagate +parse errors correctly back to the compiler when parsing fails. + +[`parse_macro_input!`]: https://docs.rs/syn/3/syn/macro.parse_macro_input.html + +## Unstable features + +The default feature set of proc-macro2 tracks the most recent stable compiler +API. Functionality in `proc_macro` that is not yet stable is not exposed by +proc-macro2 by default. + +To opt into the additional APIs available in the most recent nightly compiler, +the `procmacro2_semver_exempt` config flag must be passed to rustc. We will +polyfill those nightly-only APIs back to Rust 1.71.0. As these are unstable APIs +that track the nightly compiler, minor versions of proc-macro2 may make breaking +changes to them at any time. + +``` +RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo build +``` + +Note that this must not only be done for your crate, but for any crate that +depends on your crate. This infectious nature is intentional, as it serves as a +reminder that you are outside of the normal semver guarantees. + +Semver exempt methods are marked as such in the proc-macro2 documentation. + +
+ +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + diff --git a/third_party/crates/proc-macro2-1.0.107/build.rs b/third_party/crates/proc-macro2-1.0.107/build.rs new file mode 100644 index 0000000..26c3ed1 --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/build.rs @@ -0,0 +1,267 @@ +#![allow(unknown_lints)] +#![allow(unexpected_cfgs)] +#![allow(clippy::uninlined_format_args)] + +use std::env; +use std::ffi::OsString; +use std::fs; +use std::io::ErrorKind; +use std::iter; +use std::path::Path; +use std::process::{self, Command, Stdio}; +use std::str; + +fn main() { + let rustc = rustc_minor_version().unwrap_or(u32::MAX); + + if rustc >= 80 { + println!("cargo:rustc-check-cfg=cfg(fuzzing)"); + println!("cargo:rustc-check-cfg=cfg(no_is_available)"); + println!("cargo:rustc-check-cfg=cfg(no_literal_byte_character)"); + println!("cargo:rustc-check-cfg=cfg(no_literal_c_string)"); + println!("cargo:rustc-check-cfg=cfg(no_source_text)"); + println!("cargo:rustc-check-cfg=cfg(proc_macro_span)"); + println!("cargo:rustc-check-cfg=cfg(proc_macro_span_file)"); + println!("cargo:rustc-check-cfg=cfg(proc_macro_span_location)"); + println!("cargo:rustc-check-cfg=cfg(procmacro2_backtrace)"); + println!("cargo:rustc-check-cfg=cfg(procmacro2_build_probe)"); + println!("cargo:rustc-check-cfg=cfg(procmacro2_nightly_testing)"); + println!("cargo:rustc-check-cfg=cfg(procmacro2_semver_exempt)"); + println!("cargo:rustc-check-cfg=cfg(randomize_layout)"); + println!("cargo:rustc-check-cfg=cfg(span_locations)"); + println!("cargo:rustc-check-cfg=cfg(super_unstable)"); + println!("cargo:rustc-check-cfg=cfg(wrap_proc_macro)"); + } + + let semver_exempt = cfg!(procmacro2_semver_exempt); + if semver_exempt { + // https://github.com/dtolnay/proc-macro2/issues/147 + println!("cargo:rustc-cfg=procmacro2_semver_exempt"); + } + + if semver_exempt || cfg!(feature = "span-locations") { + // Provide methods Span::start and Span::end which give the line/column + // location of a token. This is behind a cfg because tracking location + // inside spans is a performance hit. + println!("cargo:rustc-cfg=span_locations"); + } + + if rustc < 57 { + // Do not use proc_macro::is_available() to detect whether the proc + // macro API is available vs needs to be polyfilled. Instead, use the + // proc macro API unconditionally and catch the panic that occurs if it + // isn't available. + println!("cargo:rustc-cfg=no_is_available"); + } + + if rustc < 66 { + // Do not call libproc_macro's Span::source_text. Always return None. + println!("cargo:rustc-cfg=no_source_text"); + } + + if rustc < 79 { + // Do not call Literal::byte_character nor Literal::c_string. They can + // be emulated by way of Literal::from_str. + println!("cargo:rustc-cfg=no_literal_byte_character"); + println!("cargo:rustc-cfg=no_literal_c_string"); + } + + if !cfg!(feature = "proc-macro") { + println!("cargo:rerun-if-changed=build.rs"); + return; + } + + let proc_macro_span; + let consider_rustc_bootstrap; + if compile_probe_unstable("proc_macro_span", false) { + // This is a nightly or dev compiler, so it supports unstable features + // regardless of RUSTC_BOOTSTRAP. No need to rerun build script if + // RUSTC_BOOTSTRAP is changed. + proc_macro_span = true; + consider_rustc_bootstrap = false; + } else if let Some(rustc_bootstrap) = env::var_os("RUSTC_BOOTSTRAP") { + if compile_probe_unstable("proc_macro_span", true) { + // This is a stable or beta compiler for which the user has set + // RUSTC_BOOTSTRAP to turn on unstable features. Rerun build script + // if they change it. + proc_macro_span = true; + consider_rustc_bootstrap = true; + } else if rustc_bootstrap == "1" { + // This compiler does not support the proc macro Span API in the + // form that proc-macro2 expects. No need to pay attention to + // RUSTC_BOOTSTRAP. + proc_macro_span = false; + consider_rustc_bootstrap = false; + } else { + // This is a stable or beta compiler for which RUSTC_BOOTSTRAP is + // set to restrict the use of unstable features by this crate. + proc_macro_span = false; + consider_rustc_bootstrap = true; + } + } else { + // Without RUSTC_BOOTSTRAP, this compiler does not support the proc + // macro Span API in the form that proc-macro2 expects, but try again if + // the user turns on unstable features. + proc_macro_span = false; + consider_rustc_bootstrap = true; + } + + if proc_macro_span || !semver_exempt { + // Wrap types from libproc_macro rather than polyfilling the whole API. + // Enabled as long as procmacro2_semver_exempt is not set, because we + // can't emulate the unstable API without emulating everything else. + // Also enabled unconditionally on nightly, in which case the + // procmacro2_semver_exempt surface area is implemented by using the + // nightly-only proc_macro API. + println!("cargo:rustc-cfg=wrap_proc_macro"); + } + + if proc_macro_span { + // Enable non-dummy behavior of Span::byte_range and Span::join methods + // which requires an unstable compiler feature. Enabled when building + // with nightly, unless `-Z allow-feature` in RUSTFLAGS disallows + // unstable features. + println!("cargo:rustc-cfg=proc_macro_span"); + } + + if proc_macro_span || (rustc >= 88 && compile_probe_stable("proc_macro_span_location")) { + // Enable non-dummy behavior of Span::start and Span::end methods on + // Rust 1.88+. + println!("cargo:rustc-cfg=proc_macro_span_location"); + } + + if proc_macro_span || (rustc >= 88 && compile_probe_stable("proc_macro_span_file")) { + // Enable non-dummy behavior of Span::file and Span::local_file methods + // on Rust 1.88+. + println!("cargo:rustc-cfg=proc_macro_span_file"); + } + + if semver_exempt && proc_macro_span { + // Implement the semver exempt API in terms of the nightly-only + // proc_macro API. + println!("cargo:rustc-cfg=super_unstable"); + } + + if consider_rustc_bootstrap { + println!("cargo:rerun-if-env-changed=RUSTC_BOOTSTRAP"); + } +} + +fn compile_probe_unstable(feature: &str, rustc_bootstrap: bool) -> bool { + // RUSTC_STAGE indicates that this crate is being compiled as a dependency + // of a multistage rustc bootstrap. This environment uses Cargo in a highly + // non-standard way with issues such as: + // + // https://github.com/rust-lang/cargo/issues/11138 + // https://github.com/rust-lang/rust/issues/114839 + // + env::var_os("RUSTC_STAGE").is_none() && do_compile_probe(feature, rustc_bootstrap) +} + +fn compile_probe_stable(feature: &str) -> bool { + env::var_os("RUSTC_STAGE").is_some() || do_compile_probe(feature, true) +} + +fn do_compile_probe(feature: &str, rustc_bootstrap: bool) -> bool { + println!("cargo:rerun-if-changed=src/probe/{}.rs", feature); + + let rustc = cargo_env_var("RUSTC"); + let out_dir = cargo_env_var("OUT_DIR"); + let out_subdir = Path::new(&out_dir).join("probe"); + let probefile = Path::new("src") + .join("probe") + .join(feature) + .with_extension("rs"); + + if let Err(err) = fs::create_dir(&out_subdir) { + if err.kind() != ErrorKind::AlreadyExists { + eprintln!("Failed to create {}: {}", out_subdir.display(), err); + process::exit(1); + } + } + + let rustc_wrapper = env::var_os("RUSTC_WRAPPER").filter(|wrapper| !wrapper.is_empty()); + let rustc_workspace_wrapper = + env::var_os("RUSTC_WORKSPACE_WRAPPER").filter(|wrapper| !wrapper.is_empty()); + let mut rustc = rustc_wrapper + .into_iter() + .chain(rustc_workspace_wrapper) + .chain(iter::once(rustc)); + let mut cmd = Command::new(rustc.next().unwrap()); + cmd.args(rustc); + + if !rustc_bootstrap { + cmd.env_remove("RUSTC_BOOTSTRAP"); + } + + cmd.stderr(Stdio::null()) + .arg("--cfg=procmacro2_build_probe") + .arg("--edition=2021") + .arg("--crate-name=proc_macro2") + .arg("--crate-type=lib") + .arg("--cap-lints=allow") + .arg("--emit=dep-info,metadata") + .arg("--out-dir") + .arg(&out_subdir) + .arg(probefile); + + if let Some(target) = env::var_os("TARGET") { + cmd.arg("--target").arg(target); + } + + // If Cargo wants to set RUSTFLAGS, use that. + if let Ok(rustflags) = env::var("CARGO_ENCODED_RUSTFLAGS") { + if !rustflags.is_empty() { + for arg in rustflags.split('\x1f') { + cmd.arg(arg); + } + } + } + + let success = match cmd.status() { + Ok(status) => status.success(), + Err(_) => false, + }; + + // Clean up to avoid leaving nondeterministic absolute paths in the dep-info + // file in OUT_DIR, which causes nonreproducible builds in build systems + // that treat the entire OUT_DIR as an artifact. + if let Err(err) = fs::remove_dir_all(&out_subdir) { + // libc::ENOTEMPTY + // Some filesystems (NFSv3) have timing issues under load where '.nfs*' + // dummy files can continue to get created for a short period after the + // probe command completes, breaking remove_dir_all. + // To be replaced with ErrorKind::DirectoryNotEmpty (Rust 1.83+). + const ENOTEMPTY: i32 = 39; + + if !(err.kind() == ErrorKind::NotFound + || (cfg!(target_os = "linux") && err.raw_os_error() == Some(ENOTEMPTY))) + { + eprintln!("Failed to clean up {}: {}", out_subdir.display(), err); + process::exit(1); + } + } + + success +} + +fn rustc_minor_version() -> Option { + let rustc = cargo_env_var("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() +} + +fn cargo_env_var(key: &str) -> OsString { + env::var_os(key).unwrap_or_else(|| { + eprintln!( + "Environment variable ${} is not set during execution of build script", + key, + ); + process::exit(1); + }) +} diff --git a/third_party/crates/proc-macro2-1.0.107/rust-toolchain.toml b/third_party/crates/proc-macro2-1.0.107/rust-toolchain.toml new file mode 100644 index 0000000..20fe888 --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +components = ["rust-src"] diff --git a/third_party/crates/proc-macro2-1.0.107/src/detection.rs b/third_party/crates/proc-macro2-1.0.107/src/detection.rs new file mode 100644 index 0000000..beba7b2 --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/src/detection.rs @@ -0,0 +1,75 @@ +use core::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Once; + +static WORKS: AtomicUsize = AtomicUsize::new(0); +static INIT: Once = Once::new(); + +pub(crate) fn inside_proc_macro() -> bool { + match WORKS.load(Ordering::Relaxed) { + 1 => return false, + 2 => return true, + _ => {} + } + + INIT.call_once(initialize); + inside_proc_macro() +} + +pub(crate) fn force_fallback() { + WORKS.store(1, Ordering::Relaxed); +} + +pub(crate) fn unforce_fallback() { + initialize(); +} + +#[cfg(not(no_is_available))] +fn initialize() { + let available = proc_macro::is_available(); + WORKS.store(available as usize + 1, Ordering::Relaxed); +} + +// Swap in a null panic hook to avoid printing "thread panicked" to stderr, +// then use catch_unwind to determine whether the compiler's proc_macro is +// working. When proc-macro2 is used from outside of a procedural macro all +// of the proc_macro crate's APIs currently panic. +// +// The Once is to prevent the possibility of this ordering: +// +// thread 1 calls take_hook, gets the user's original hook +// thread 1 calls set_hook with the null hook +// thread 2 calls take_hook, thinks null hook is the original hook +// thread 2 calls set_hook with the null hook +// thread 1 calls set_hook with the actual original hook +// thread 2 calls set_hook with what it thinks is the original hook +// +// in which the user's hook has been lost. +// +// There is still a race condition where a panic in a different thread can +// happen during the interval that the user's original panic hook is +// unregistered such that their hook is incorrectly not called. This is +// sufficiently unlikely and less bad than printing panic messages to stderr +// on correct use of this crate. Maybe there is a libstd feature request +// here. For now, if a user needs to guarantee that this failure mode does +// not occur, they need to call e.g. `proc_macro2::Span::call_site()` from +// the main thread before launching any other threads. +#[cfg(no_is_available)] +fn initialize() { + use std::panic::{self, PanicInfo}; + + type PanicHook = dyn Fn(&PanicInfo) + Sync + Send + 'static; + + let null_hook: Box = Box::new(|_panic_info| { /* ignore */ }); + let sanity_check = &*null_hook as *const PanicHook; + let original_hook = panic::take_hook(); + panic::set_hook(null_hook); + + let works = panic::catch_unwind(proc_macro::Span::call_site).is_ok(); + WORKS.store(works as usize + 1, Ordering::Relaxed); + + let hopefully_null_hook = panic::take_hook(); + panic::set_hook(original_hook); + if sanity_check != &*hopefully_null_hook { + panic!("observed race condition in proc_macro2::inside_proc_macro"); + } +} diff --git a/third_party/crates/proc-macro2-1.0.107/src/extra.rs b/third_party/crates/proc-macro2-1.0.107/src/extra.rs new file mode 100644 index 0000000..522a90e --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/src/extra.rs @@ -0,0 +1,151 @@ +//! Items which do not have a correspondence to any API in the proc_macro crate, +//! but are necessary to include in proc-macro2. + +use crate::fallback; +use crate::imp; +use crate::marker::{ProcMacroAutoTraits, MARKER}; +use crate::Span; +use core::fmt::{self, Debug}; + +/// Invalidate any `proc_macro2::Span` that exist on the current thread. +/// +/// The implementation of `Span` uses thread-local data structures and this +/// function clears them. Calling any method on a `Span` on the current thread +/// created prior to the invalidation will return incorrect values or crash. +/// +/// This function is useful for programs that process more than 232 +/// bytes of Rust source code on the same thread. Just like rustc, proc-macro2 +/// uses 32-bit source locations, and these wrap around when the total source +/// code processed by the same thread exceeds 232 bytes (4 +/// gigabytes). After a wraparound, `Span` methods such as `source_text()` can +/// return wrong data. +/// +/// # Example +/// +/// As of late 2023, there is 200 GB of Rust code published on crates.io. +/// Looking at just the newest version of every crate, it is 16 GB of code. So a +/// workload that involves parsing it all would overflow a 32-bit source +/// location unless spans are being invalidated. +/// +/// ``` +/// use flate2::read::GzDecoder; +/// use std::ffi::OsStr; +/// use std::io::{BufReader, Read}; +/// use std::str::FromStr; +/// use tar::Archive; +/// +/// rayon::scope(|s| { +/// for krate in every_version_of_every_crate() { +/// s.spawn(move |_| { +/// proc_macro2::extra::invalidate_current_thread_spans(); +/// +/// let reader = BufReader::new(krate); +/// let tar = GzDecoder::new(reader); +/// let mut archive = Archive::new(tar); +/// for entry in archive.entries().unwrap() { +/// let mut entry = entry.unwrap(); +/// let path = entry.path().unwrap(); +/// if path.extension() != Some(OsStr::new("rs")) { +/// continue; +/// } +/// let mut content = String::new(); +/// entry.read_to_string(&mut content).unwrap(); +/// match proc_macro2::TokenStream::from_str(&content) { +/// Ok(tokens) => {/* ... */}, +/// Err(_) => continue, +/// } +/// } +/// }); +/// } +/// }); +/// # +/// # fn every_version_of_every_crate() -> Vec { +/// # Vec::new() +/// # } +/// ``` +/// +/// # Panics +/// +/// This function is not applicable to and will panic if called from a +/// procedural macro. +#[cfg(span_locations)] +#[cfg_attr(docsrs, doc(cfg(feature = "span-locations")))] +pub fn invalidate_current_thread_spans() { + crate::imp::invalidate_current_thread_spans(); +} + +/// An object that holds a [`Group`]'s `span_open()` and `span_close()` together +/// in a more compact representation than holding those 2 spans individually. +/// +/// [`Group`]: crate::Group +#[derive(Copy, Clone)] +pub struct DelimSpan { + inner: DelimSpanEnum, + _marker: ProcMacroAutoTraits, +} + +#[derive(Copy, Clone)] +enum DelimSpanEnum { + #[cfg(wrap_proc_macro)] + Compiler { + join: proc_macro::Span, + open: proc_macro::Span, + close: proc_macro::Span, + }, + Fallback(fallback::Span), +} + +impl DelimSpan { + pub(crate) fn new(group: &imp::Group) -> Self { + #[cfg(wrap_proc_macro)] + let inner = match group { + imp::Group::Compiler(group) => DelimSpanEnum::Compiler { + join: group.span(), + open: group.span_open(), + close: group.span_close(), + }, + imp::Group::Fallback(group) => DelimSpanEnum::Fallback(group.span()), + }; + + #[cfg(not(wrap_proc_macro))] + let inner = DelimSpanEnum::Fallback(group.span()); + + DelimSpan { + inner, + _marker: MARKER, + } + } + + /// Returns a span covering the entire delimited group. + pub fn join(&self) -> Span { + match &self.inner { + #[cfg(wrap_proc_macro)] + DelimSpanEnum::Compiler { join, .. } => Span::_new(imp::Span::Compiler(*join)), + DelimSpanEnum::Fallback(span) => Span::_new_fallback(*span), + } + } + + /// Returns a span for the opening punctuation of the group only. + pub fn open(&self) -> Span { + match &self.inner { + #[cfg(wrap_proc_macro)] + DelimSpanEnum::Compiler { open, .. } => Span::_new(imp::Span::Compiler(*open)), + DelimSpanEnum::Fallback(span) => Span::_new_fallback(span.first_byte()), + } + } + + /// Returns a span for the closing punctuation of the group only. + pub fn close(&self) -> Span { + match &self.inner { + #[cfg(wrap_proc_macro)] + DelimSpanEnum::Compiler { close, .. } => Span::_new(imp::Span::Compiler(*close)), + DelimSpanEnum::Fallback(span) => Span::_new_fallback(span.last_byte()), + } + } +} + +impl Debug for DelimSpan { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.join(), f) + } +} diff --git a/third_party/crates/proc-macro2-1.0.107/src/fallback.rs b/third_party/crates/proc-macro2-1.0.107/src/fallback.rs new file mode 100644 index 0000000..61dc21d --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/src/fallback.rs @@ -0,0 +1,1279 @@ +#[cfg(wrap_proc_macro)] +use crate::imp; +#[cfg(span_locations)] +use crate::location::LineColumn; +use crate::parse::{self, Cursor}; +use crate::rcvec::{RcVec, RcVecBuilder, RcVecIntoIter, RcVecMut}; +use crate::{Delimiter, Spacing, TokenTree}; +use alloc::borrow::ToOwned as _; +use alloc::boxed::Box; +#[cfg(all(span_locations, not(fuzzing)))] +use alloc::collections::BTreeMap; +use alloc::format; +use alloc::string::{String, ToString as _}; +#[cfg(all(span_locations, not(fuzzing)))] +use alloc::vec; +use alloc::vec::Vec; +#[cfg(all(span_locations, not(fuzzing)))] +use core::cell::RefCell; +#[cfg(span_locations)] +use core::cmp; +#[cfg(all(span_locations, not(fuzzing)))] +use core::cmp::Ordering; +use core::ffi::CStr; +use core::fmt::{self, Debug, Display, Write}; +use core::mem::ManuallyDrop; +#[cfg(span_locations)] +use core::ops::Range; +use core::ops::RangeBounds; +use core::ptr; +use core::str; +#[cfg(feature = "proc-macro")] +use core::str::FromStr; +#[cfg(wrap_proc_macro)] +use std::panic; +#[cfg(span_locations)] +use std::path::PathBuf; +#[cfg(all(span_locations, not(fuzzing)))] +use std::thread_local; + +/// Force use of proc-macro2's fallback implementation of the API for now, even +/// if the compiler's implementation is available. +pub fn force() { + #[cfg(wrap_proc_macro)] + crate::detection::force_fallback(); +} + +/// Resume using the compiler's implementation of the proc macro API if it is +/// available. +pub fn unforce() { + #[cfg(wrap_proc_macro)] + crate::detection::unforce_fallback(); +} + +#[derive(Clone)] +pub(crate) struct TokenStream { + inner: RcVec, +} + +#[derive(Debug)] +pub(crate) struct LexError { + pub(crate) span: Span, +} + +impl LexError { + pub(crate) fn span(&self) -> Span { + self.span + } + + pub(crate) fn call_site() -> Self { + LexError { + span: Span::call_site(), + } + } +} + +impl TokenStream { + pub(crate) fn new() -> Self { + TokenStream { + inner: RcVecBuilder::new().build(), + } + } + + pub(crate) fn from_str_checked(src: &str) -> Result { + // Create a dummy file & add it to the source map + let mut cursor = get_cursor(src); + + // Strip a byte order mark if present + const BYTE_ORDER_MARK: &str = "\u{feff}"; + if cursor.starts_with(BYTE_ORDER_MARK) { + cursor = cursor.advance(BYTE_ORDER_MARK.len()); + } + + parse::token_stream(cursor) + } + + #[cfg(feature = "proc-macro")] + pub(crate) fn from_str_unchecked(src: &str) -> Self { + Self::from_str_checked(src).unwrap() + } + + pub(crate) fn is_empty(&self) -> bool { + self.inner.len() == 0 + } + + fn take_inner(self) -> RcVecBuilder { + let nodrop = ManuallyDrop::new(self); + unsafe { ptr::read(&nodrop.inner) }.make_owned() + } +} + +fn push_token_from_proc_macro(mut vec: RcVecMut, token: TokenTree) { + // https://github.com/dtolnay/proc-macro2/issues/235 + match token { + TokenTree::Literal(crate::Literal { + #[cfg(wrap_proc_macro)] + inner: crate::imp::Literal::Fallback(literal), + #[cfg(not(wrap_proc_macro))] + inner: literal, + .. + }) if literal.repr.starts_with('-') => { + push_negative_literal(vec, literal); + } + _ => vec.push(token), + } + + #[cold] + fn push_negative_literal(mut vec: RcVecMut, mut literal: Literal) { + literal.repr.remove(0); + let mut punct = crate::Punct::new('-', Spacing::Alone); + punct.set_span(crate::Span::_new_fallback(literal.span)); + vec.push(TokenTree::Punct(punct)); + vec.push(TokenTree::Literal(crate::Literal::_new_fallback(literal))); + } +} + +// Nonrecursive to prevent stack overflow. +impl Drop for TokenStream { + fn drop(&mut self) { + let mut stack = Vec::new(); + let mut current = match self.inner.get_mut() { + Some(inner) => inner.take().into_iter(), + None => return, + }; + loop { + while let Some(token) = current.next() { + let group = match token { + TokenTree::Group(group) => group.inner, + _ => continue, + }; + #[cfg(wrap_proc_macro)] + let group = match group { + crate::imp::Group::Fallback(group) => group, + crate::imp::Group::Compiler(_) => continue, + }; + let mut group = group; + if let Some(inner) = group.stream.inner.get_mut() { + stack.push(current); + current = inner.take().into_iter(); + } + } + match stack.pop() { + Some(next) => current = next, + None => return, + } + } + } +} + +pub(crate) struct TokenStreamBuilder { + inner: RcVecBuilder, +} + +impl TokenStreamBuilder { + pub(crate) fn new() -> Self { + TokenStreamBuilder { + inner: RcVecBuilder::new(), + } + } + + pub(crate) fn with_capacity(cap: usize) -> Self { + TokenStreamBuilder { + inner: RcVecBuilder::with_capacity(cap), + } + } + + pub(crate) fn push_token_from_parser(&mut self, tt: TokenTree) { + self.inner.push(tt); + } + + pub(crate) fn build(self) -> TokenStream { + TokenStream { + inner: self.inner.build(), + } + } +} + +#[cfg(span_locations)] +fn get_cursor(src: &str) -> Cursor { + #[cfg(fuzzing)] + return Cursor { rest: src, off: 1 }; + + // Create a dummy file & add it to the source map + #[cfg(not(fuzzing))] + SOURCE_MAP.with(|sm| { + let mut sm = sm.borrow_mut(); + let span = sm.add_file(src); + Cursor { + rest: src, + off: span.lo, + } + }) +} + +#[cfg(not(span_locations))] +fn get_cursor(src: &str) -> Cursor { + Cursor { rest: src } +} + +impl Display for LexError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("cannot parse string into token stream") + } +} + +impl Display for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut joint = false; + for (i, tt) in self.inner.iter().enumerate() { + if i != 0 && !joint { + write!(f, " ")?; + } + joint = false; + match tt { + TokenTree::Group(tt) => write!(f, "{}", tt), + TokenTree::Ident(tt) => write!(f, "{}", tt), + TokenTree::Punct(tt) => { + joint = tt.spacing() == Spacing::Joint; + write!(f, "{}", tt) + } + TokenTree::Literal(tt) => write!(f, "{}", tt), + }?; + } + + Ok(()) + } +} + +impl Debug for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("TokenStream ")?; + f.debug_list().entries(self.clone()).finish() + } +} + +#[cfg(feature = "proc-macro")] +impl From for TokenStream { + fn from(inner: proc_macro::TokenStream) -> Self { + TokenStream::from_str_unchecked(&inner.to_string()) + } +} + +#[cfg(feature = "proc-macro")] +impl From for proc_macro::TokenStream { + fn from(inner: TokenStream) -> Self { + proc_macro::TokenStream::from_str_unchecked(&inner.to_string()) + } +} + +impl From for TokenStream { + fn from(tree: TokenTree) -> Self { + let mut stream = RcVecBuilder::new(); + push_token_from_proc_macro(stream.as_mut(), tree); + TokenStream { + inner: stream.build(), + } + } +} + +impl FromIterator for TokenStream { + fn from_iter>(tokens: I) -> Self { + let mut stream = TokenStream::new(); + stream.extend(tokens); + stream + } +} + +impl FromIterator for TokenStream { + fn from_iter>(streams: I) -> Self { + let mut v = RcVecBuilder::new(); + + for stream in streams { + v.extend(stream.take_inner()); + } + + TokenStream { inner: v.build() } + } +} + +impl Extend for TokenStream { + fn extend>(&mut self, tokens: I) { + let mut vec = self.inner.make_mut(); + tokens + .into_iter() + .for_each(|token| push_token_from_proc_macro(vec.as_mut(), token)); + } +} + +impl Extend for TokenStream { + fn extend>(&mut self, streams: I) { + self.inner.make_mut().extend(streams.into_iter().flatten()); + } +} + +pub(crate) type TokenTreeIter = RcVecIntoIter; + +impl IntoIterator for TokenStream { + type Item = TokenTree; + type IntoIter = TokenTreeIter; + + fn into_iter(self) -> TokenTreeIter { + self.take_inner().into_iter() + } +} + +#[cfg(all(span_locations, not(fuzzing)))] +thread_local! { + static SOURCE_MAP: RefCell = RefCell::new(SourceMap { + // Start with a single dummy file which all call_site() and def_site() + // spans reference. + files: vec![FileInfo { + source_text: String::new(), + span: Span { lo: 0, hi: 0 }, + lines: vec![0], + char_index_to_byte_offset: BTreeMap::new(), + }], + }); +} + +#[cfg(span_locations)] +pub(crate) fn invalidate_current_thread_spans() { + #[cfg(not(fuzzing))] + SOURCE_MAP.with(|sm| sm.borrow_mut().files.truncate(1)); +} + +#[cfg(all(span_locations, not(fuzzing)))] +struct FileInfo { + source_text: String, + span: Span, + lines: Vec, + char_index_to_byte_offset: BTreeMap, +} + +#[cfg(all(span_locations, not(fuzzing)))] +impl FileInfo { + fn offset_line_column(&self, offset: usize) -> LineColumn { + assert!(self.span_within(Span { + lo: offset as u32, + hi: offset as u32, + })); + let offset = offset - self.span.lo as usize; + match self.lines.binary_search(&offset) { + Ok(found) => LineColumn { + line: found + 1, + column: 0, + }, + Err(idx) => LineColumn { + line: idx, + column: offset - self.lines[idx - 1], + }, + } + } + + fn span_within(&self, span: Span) -> bool { + span.lo >= self.span.lo && span.hi <= self.span.hi + } + + fn byte_range(&mut self, span: Span) -> Range { + self.byte(span.lo)..self.byte(span.hi) + } + + fn byte(&mut self, ch: u32) -> usize { + let char_index = (ch - self.span.lo) as usize; + + // Look up offset of the largest already-computed char index that is + // less than or equal to the current requested one. + let (&previous_char_index, &previous_byte_offset) = self + .char_index_to_byte_offset + .range(..=char_index) + .next_back() + .unwrap_or((&0, &0)); + + if previous_char_index == char_index { + return previous_byte_offset; + } + + // Look up next char index that is greater than the requested one. We + // resume counting chars from whichever point is closer. + let byte_offset = match self.char_index_to_byte_offset.range(char_index..).next() { + Some((&next_char_index, &next_byte_offset)) + if next_char_index - char_index < char_index - previous_char_index => + { + self.source_text[..next_byte_offset] + .char_indices() + .nth_back(next_char_index - char_index - 1) + .unwrap() + .0 + } + _ => { + match self.source_text[previous_byte_offset..] + .char_indices() + .nth(char_index - previous_char_index) + { + Some((byte_offset_from_previous, _ch)) => { + previous_byte_offset + byte_offset_from_previous + } + None => self.source_text.len(), + } + } + }; + + self.char_index_to_byte_offset + .insert(char_index, byte_offset); + byte_offset + } + + fn source_text(&mut self, span: Span) -> String { + let byte_range = self.byte_range(span); + self.source_text[byte_range].to_owned() + } +} + +/// Computes the offsets of each line in the given source string +/// and the total number of characters +#[cfg(all(span_locations, not(fuzzing)))] +fn lines_offsets(s: &str) -> (usize, Vec) { + let mut lines = vec![0]; + let mut total = 0; + + for ch in s.chars() { + total += 1; + if ch == '\n' { + lines.push(total); + } + } + + (total, lines) +} + +#[cfg(all(span_locations, not(fuzzing)))] +struct SourceMap { + files: Vec, +} + +#[cfg(all(span_locations, not(fuzzing)))] +impl SourceMap { + fn next_start_pos(&self) -> u32 { + // Add 1 so there's always space between files. + // + // We'll always have at least 1 file, as we initialize our files list + // with a dummy file. + self.files.last().unwrap().span.hi + 1 + } + + fn add_file(&mut self, src: &str) -> Span { + let (len, lines) = lines_offsets(src); + let lo = self.next_start_pos(); + let span = Span { + lo, + hi: lo + (len as u32), + }; + + self.files.push(FileInfo { + source_text: src.to_owned(), + span, + lines, + // Populated lazily by source_text(). + char_index_to_byte_offset: BTreeMap::new(), + }); + + span + } + + fn find(&self, span: Span) -> usize { + match self.files.binary_search_by(|file| { + if file.span.hi < span.lo { + Ordering::Less + } else if file.span.lo > span.hi { + Ordering::Greater + } else { + assert!(file.span_within(span)); + Ordering::Equal + } + }) { + Ok(i) => i, + Err(_) => unreachable!("Invalid span with no related FileInfo!"), + } + } + + fn filepath(&self, span: Span) -> String { + let i = self.find(span); + if i == 0 { + "".to_owned() + } else { + format!("", i) + } + } + + fn fileinfo(&self, span: Span) -> &FileInfo { + let i = self.find(span); + &self.files[i] + } + + fn fileinfo_mut(&mut self, span: Span) -> &mut FileInfo { + let i = self.find(span); + &mut self.files[i] + } +} + +#[derive(Clone, Copy, PartialEq, Eq)] +pub(crate) struct Span { + #[cfg(span_locations)] + pub(crate) lo: u32, + #[cfg(span_locations)] + pub(crate) hi: u32, +} + +impl Span { + #[cfg(not(span_locations))] + pub(crate) fn call_site() -> Self { + Span {} + } + + #[cfg(span_locations)] + pub(crate) fn call_site() -> Self { + Span { lo: 0, hi: 0 } + } + + pub(crate) fn mixed_site() -> Self { + Span::call_site() + } + + #[cfg(procmacro2_semver_exempt)] + pub(crate) fn def_site() -> Self { + Span::call_site() + } + + pub(crate) fn resolved_at(&self, _other: Span) -> Span { + // Stable spans consist only of line/column information, so + // `resolved_at` and `located_at` only select which span the + // caller wants line/column information from. + *self + } + + pub(crate) fn located_at(&self, other: Span) -> Span { + other + } + + #[cfg(span_locations)] + pub(crate) fn byte_range(&self) -> Range { + #[cfg(fuzzing)] + return 0..0; + + #[cfg(not(fuzzing))] + { + if self.is_call_site() { + 0..0 + } else { + SOURCE_MAP.with(|sm| sm.borrow_mut().fileinfo_mut(*self).byte_range(*self)) + } + } + } + + #[cfg(span_locations)] + pub(crate) fn start(&self) -> LineColumn { + #[cfg(fuzzing)] + return LineColumn { line: 0, column: 0 }; + + #[cfg(not(fuzzing))] + SOURCE_MAP.with(|sm| { + let sm = sm.borrow(); + let fi = sm.fileinfo(*self); + fi.offset_line_column(self.lo as usize) + }) + } + + #[cfg(span_locations)] + pub(crate) fn end(&self) -> LineColumn { + #[cfg(fuzzing)] + return LineColumn { line: 0, column: 0 }; + + #[cfg(not(fuzzing))] + SOURCE_MAP.with(|sm| { + let sm = sm.borrow(); + let fi = sm.fileinfo(*self); + fi.offset_line_column(self.hi as usize) + }) + } + + #[cfg(span_locations)] + pub(crate) fn file(&self) -> String { + #[cfg(fuzzing)] + return "".to_owned(); + + #[cfg(not(fuzzing))] + SOURCE_MAP.with(|sm| { + let sm = sm.borrow(); + sm.filepath(*self) + }) + } + + #[cfg(span_locations)] + pub(crate) fn local_file(&self) -> Option { + None + } + + #[cfg(not(span_locations))] + pub(crate) fn join(&self, _other: Span) -> Option { + Some(Span {}) + } + + #[cfg(span_locations)] + pub(crate) fn join(&self, other: Span) -> Option { + #[cfg(fuzzing)] + return { + let _ = other; + None + }; + + #[cfg(not(fuzzing))] + SOURCE_MAP.with(|sm| { + let sm = sm.borrow(); + // If `other` is not within the same FileInfo as us, return None. + if !sm.fileinfo(*self).span_within(other) { + return None; + } + Some(Span { + lo: cmp::min(self.lo, other.lo), + hi: cmp::max(self.hi, other.hi), + }) + }) + } + + #[cfg(not(span_locations))] + pub(crate) fn source_text(&self) -> Option { + None + } + + #[cfg(span_locations)] + pub(crate) fn source_text(&self) -> Option { + #[cfg(fuzzing)] + return None; + + #[cfg(not(fuzzing))] + { + if self.is_call_site() { + None + } else { + Some(SOURCE_MAP.with(|sm| sm.borrow_mut().fileinfo_mut(*self).source_text(*self))) + } + } + } + + #[cfg(not(span_locations))] + pub(crate) fn first_byte(self) -> Self { + self + } + + #[cfg(span_locations)] + pub(crate) fn first_byte(self) -> Self { + Span { + lo: self.lo, + hi: cmp::min(self.lo.saturating_add(1), self.hi), + } + } + + #[cfg(not(span_locations))] + pub(crate) fn last_byte(self) -> Self { + self + } + + #[cfg(span_locations)] + pub(crate) fn last_byte(self) -> Self { + Span { + lo: cmp::max(self.hi.saturating_sub(1), self.lo), + hi: self.hi, + } + } + + #[cfg(span_locations)] + fn is_call_site(&self) -> bool { + self.lo == 0 && self.hi == 0 + } +} + +impl Debug for Span { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + #[cfg(span_locations)] + return write!(f, "bytes({}..{})", self.lo, self.hi); + + #[cfg(not(span_locations))] + write!(f, "Span") + } +} + +pub(crate) fn debug_span_field_if_nontrivial(debug: &mut fmt::DebugStruct, span: Span) { + #[cfg(span_locations)] + { + if span.is_call_site() { + return; + } + } + + if cfg!(span_locations) { + debug.field("span", &span); + } +} + +#[derive(Clone)] +pub(crate) struct Group { + delimiter: Delimiter, + stream: TokenStream, + span: Span, +} + +impl Group { + pub(crate) fn new(delimiter: Delimiter, stream: TokenStream) -> Self { + Group { + delimiter, + stream, + span: Span::call_site(), + } + } + + pub(crate) fn delimiter(&self) -> Delimiter { + self.delimiter + } + + pub(crate) fn stream(&self) -> TokenStream { + self.stream.clone() + } + + pub(crate) fn span(&self) -> Span { + self.span + } + + pub(crate) fn span_open(&self) -> Span { + self.span.first_byte() + } + + pub(crate) fn span_close(&self) -> Span { + self.span.last_byte() + } + + pub(crate) fn set_span(&mut self, span: Span) { + self.span = span; + } +} + +impl Display for Group { + // We attempt to match libproc_macro's formatting. + // Empty parens: () + // Nonempty parens: (...) + // Empty brackets: [] + // Nonempty brackets: [...] + // Empty braces: { } + // Nonempty braces: { ... } + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let (open, close) = match self.delimiter { + Delimiter::Parenthesis => ("(", ")"), + Delimiter::Brace => ("{ ", "}"), + Delimiter::Bracket => ("[", "]"), + Delimiter::None => ("", ""), + }; + + f.write_str(open)?; + Display::fmt(&self.stream, f)?; + if self.delimiter == Delimiter::Brace && !self.stream.inner.is_empty() { + f.write_str(" ")?; + } + f.write_str(close)?; + + Ok(()) + } +} + +impl Debug for Group { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut debug = fmt.debug_struct("Group"); + debug.field("delimiter", &self.delimiter); + debug.field("stream", &self.stream); + debug_span_field_if_nontrivial(&mut debug, self.span); + debug.finish() + } +} + +#[derive(Clone)] +pub(crate) struct Ident { + sym: Box, + span: Span, + raw: bool, +} + +impl Ident { + #[track_caller] + pub(crate) fn new_checked(string: &str, span: Span) -> Self { + validate_ident(string); + Ident::new_unchecked(string, span) + } + + pub(crate) fn new_unchecked(string: &str, span: Span) -> Self { + Ident { + sym: Box::from(string), + span, + raw: false, + } + } + + #[track_caller] + pub(crate) fn new_raw_checked(string: &str, span: Span) -> Self { + validate_ident_raw(string); + Ident::new_raw_unchecked(string, span) + } + + pub(crate) fn new_raw_unchecked(string: &str, span: Span) -> Self { + Ident { + sym: Box::from(string), + span, + raw: true, + } + } + + pub(crate) fn span(&self) -> Span { + self.span + } + + pub(crate) fn set_span(&mut self, span: Span) { + self.span = span; + } +} + +pub(crate) fn is_ident_start(c: char) -> bool { + c == '_' || unicode_ident::is_xid_start(c) +} + +pub(crate) fn is_ident_continue(c: char) -> bool { + unicode_ident::is_xid_continue(c) +} + +#[track_caller] +fn validate_ident(string: &str) { + if string.is_empty() { + panic!("Ident is not allowed to be empty; use Option"); + } + + if string.bytes().all(|digit| b'0' <= digit && digit <= b'9') { + panic!("Ident cannot be a number; use Literal instead"); + } + + fn ident_ok(string: &str) -> bool { + let mut chars = string.chars(); + let first = chars.next().unwrap(); + if !is_ident_start(first) { + return false; + } + for ch in chars { + if !is_ident_continue(ch) { + return false; + } + } + true + } + + if !ident_ok(string) { + panic!("{:?} is not a valid Ident", string); + } +} + +#[track_caller] +fn validate_ident_raw(string: &str) { + validate_ident(string); + + match string { + "_" | "super" | "self" | "Self" | "crate" => { + panic!("`r#{}` cannot be a raw identifier", string); + } + _ => {} + } +} + +impl PartialEq for Ident { + fn eq(&self, other: &Ident) -> bool { + self.sym == other.sym && self.raw == other.raw + } +} + +impl PartialEq for Ident +where + T: ?Sized + AsRef, +{ + fn eq(&self, other: &T) -> bool { + let other = other.as_ref(); + if self.raw { + other.starts_with("r#") && *self.sym == other[2..] + } else { + *self.sym == *other + } + } +} + +impl Display for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.raw { + f.write_str("r#")?; + } + f.write_str(&self.sym) + } +} + +#[allow(clippy::missing_fields_in_debug)] +impl Debug for Ident { + // Ident(proc_macro), Ident(r#union) + #[cfg(not(span_locations))] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut debug = f.debug_tuple("Ident"); + debug.field(&format_args!("{}", self)); + debug.finish() + } + + // Ident { + // sym: proc_macro, + // span: bytes(128..138) + // } + #[cfg(span_locations)] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut debug = f.debug_struct("Ident"); + debug.field("sym", &format_args!("{}", self)); + debug_span_field_if_nontrivial(&mut debug, self.span); + debug.finish() + } +} + +#[derive(Clone)] +pub(crate) struct Literal { + pub(crate) repr: String, + span: Span, +} + +macro_rules! suffixed_numbers { + ($($name:ident => $kind:ident,)*) => ($( + pub(crate) fn $name(n: $kind) -> Literal { + Literal::_new(format!(concat!("{}", stringify!($kind)), n)) + } + )*) +} + +macro_rules! unsuffixed_numbers { + ($($name:ident => $kind:ident,)*) => ($( + pub(crate) fn $name(n: $kind) -> Literal { + Literal::_new(n.to_string()) + } + )*) +} + +impl Literal { + pub(crate) fn _new(repr: String) -> Self { + Literal { + repr, + span: Span::call_site(), + } + } + + pub(crate) fn from_str_checked(repr: &str) -> Result { + let mut cursor = get_cursor(repr); + #[cfg(span_locations)] + let lo = cursor.off; + + let negative = cursor.starts_with_char('-'); + if negative { + cursor = cursor.advance(1); + if !cursor.starts_with_fn(|ch| ch.is_ascii_digit()) { + return Err(LexError::call_site()); + } + } + + if let Ok((rest, mut literal)) = parse::literal(cursor) { + if rest.is_empty() { + if negative { + literal.repr.insert(0, '-'); + } + literal.span = Span { + #[cfg(span_locations)] + lo, + #[cfg(span_locations)] + hi: rest.off, + }; + return Ok(literal); + } + } + Err(LexError::call_site()) + } + + pub(crate) unsafe fn from_str_unchecked(repr: &str) -> Self { + Literal::_new(repr.to_owned()) + } + + suffixed_numbers! { + u8_suffixed => u8, + u16_suffixed => u16, + u32_suffixed => u32, + u64_suffixed => u64, + u128_suffixed => u128, + usize_suffixed => usize, + i8_suffixed => i8, + i16_suffixed => i16, + i32_suffixed => i32, + i64_suffixed => i64, + i128_suffixed => i128, + isize_suffixed => isize, + + f32_suffixed => f32, + f64_suffixed => f64, + } + + unsuffixed_numbers! { + u8_unsuffixed => u8, + u16_unsuffixed => u16, + u32_unsuffixed => u32, + u64_unsuffixed => u64, + u128_unsuffixed => u128, + usize_unsuffixed => usize, + i8_unsuffixed => i8, + i16_unsuffixed => i16, + i32_unsuffixed => i32, + i64_unsuffixed => i64, + i128_unsuffixed => i128, + isize_unsuffixed => isize, + } + + pub(crate) fn f32_unsuffixed(f: f32) -> Literal { + let mut s = f.to_string(); + if !s.contains('.') { + s.push_str(".0"); + } + Literal::_new(s) + } + + pub(crate) fn f64_unsuffixed(f: f64) -> Literal { + let mut s = f.to_string(); + if !s.contains('.') { + s.push_str(".0"); + } + Literal::_new(s) + } + + pub(crate) fn string(string: &str) -> Literal { + let mut repr = String::with_capacity(string.len() + 2); + repr.push('"'); + escape_utf8(string, &mut repr); + repr.push('"'); + Literal::_new(repr) + } + + pub(crate) fn character(ch: char) -> Literal { + let mut repr = String::new(); + repr.push('\''); + if ch == '"' { + // escape_debug turns this into '\"' which is unnecessary. + repr.push(ch); + } else { + repr.extend(ch.escape_debug()); + } + repr.push('\''); + Literal::_new(repr) + } + + pub(crate) fn byte_character(byte: u8) -> Literal { + let mut repr = "b'".to_string(); + #[allow(clippy::match_overlapping_arm)] + match byte { + b'\0' => repr.push_str(r"\0"), + b'\t' => repr.push_str(r"\t"), + b'\n' => repr.push_str(r"\n"), + b'\r' => repr.push_str(r"\r"), + b'\'' => repr.push_str(r"\'"), + b'\\' => repr.push_str(r"\\"), + b'\x20'..=b'\x7E' => repr.push(byte as char), + _ => { + let _ = write!(repr, r"\x{:02X}", byte); + } + } + repr.push('\''); + Literal::_new(repr) + } + + pub(crate) fn byte_string(bytes: &[u8]) -> Literal { + let mut repr = "b\"".to_string(); + let mut bytes = bytes.iter(); + while let Some(&b) = bytes.next() { + #[allow(clippy::match_overlapping_arm)] + match b { + b'\0' => repr.push_str(match bytes.as_slice().first() { + // circumvent clippy::octal_escapes lint + Some(b'0'..=b'7') => r"\x00", + _ => r"\0", + }), + b'\t' => repr.push_str(r"\t"), + b'\n' => repr.push_str(r"\n"), + b'\r' => repr.push_str(r"\r"), + b'"' => repr.push_str("\\\""), + b'\\' => repr.push_str(r"\\"), + b'\x20'..=b'\x7E' => repr.push(b as char), + _ => { + let _ = write!(repr, r"\x{:02X}", b); + } + } + } + repr.push('"'); + Literal::_new(repr) + } + + pub(crate) fn c_string(string: &CStr) -> Literal { + let mut repr = "c\"".to_string(); + let mut bytes = string.to_bytes(); + while !bytes.is_empty() { + let (valid, invalid) = match str::from_utf8(bytes) { + Ok(all_valid) => { + bytes = b""; + (all_valid, bytes) + } + Err(utf8_error) => { + let (valid, rest) = bytes.split_at(utf8_error.valid_up_to()); + let valid = str::from_utf8(valid).unwrap(); + let invalid = utf8_error + .error_len() + .map_or(rest, |error_len| &rest[..error_len]); + bytes = &bytes[valid.len() + invalid.len()..]; + (valid, invalid) + } + }; + escape_utf8(valid, &mut repr); + for &byte in invalid { + let _ = write!(repr, r"\x{:02X}", byte); + } + } + repr.push('"'); + Literal::_new(repr) + } + + pub(crate) fn span(&self) -> Span { + self.span + } + + pub(crate) fn set_span(&mut self, span: Span) { + self.span = span; + } + + pub(crate) fn subspan>(&self, range: R) -> Option { + #[cfg(not(span_locations))] + { + let _ = range; + None + } + + #[cfg(span_locations)] + { + use core::ops::Bound; + + let lo = match range.start_bound() { + Bound::Included(start) => { + let start = u32::try_from(*start).ok()?; + self.span.lo.checked_add(start)? + } + Bound::Excluded(start) => { + let start = u32::try_from(*start).ok()?; + self.span.lo.checked_add(start)?.checked_add(1)? + } + Bound::Unbounded => self.span.lo, + }; + let hi = match range.end_bound() { + Bound::Included(end) => { + let end = u32::try_from(*end).ok()?; + self.span.lo.checked_add(end)?.checked_add(1)? + } + Bound::Excluded(end) => { + let end = u32::try_from(*end).ok()?; + self.span.lo.checked_add(end)? + } + Bound::Unbounded => self.span.hi, + }; + if lo <= hi && hi <= self.span.hi { + Some(Span { lo, hi }) + } else { + None + } + } + } +} + +impl Display for Literal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.repr, f) + } +} + +impl Debug for Literal { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut debug = fmt.debug_struct("Literal"); + debug.field("lit", &format_args!("{}", self.repr)); + debug_span_field_if_nontrivial(&mut debug, self.span); + debug.finish() + } +} + +fn escape_utf8(string: &str, repr: &mut String) { + let mut chars = string.chars(); + while let Some(ch) = chars.next() { + if ch == '\0' { + repr.push_str( + if chars + .as_str() + .starts_with(|next| '0' <= next && next <= '7') + { + // circumvent clippy::octal_escapes lint + r"\x00" + } else { + r"\0" + }, + ); + } else if ch == '\'' { + // escape_debug turns this into "\'" which is unnecessary. + repr.push(ch); + } else { + repr.extend(ch.escape_debug()); + } + } +} + +#[cfg(feature = "proc-macro")] +pub(crate) trait FromStr2: FromStr { + #[cfg(wrap_proc_macro)] + fn valid(src: &str) -> bool; + + #[cfg(wrap_proc_macro)] + fn from_str_checked(src: &str) -> Result { + // Validate using fallback parser, because rustc is incapable of + // returning a recoverable Err for certain invalid token streams, and + // will instead permanently poison the compilation. + if !Self::valid(src) { + return Err(imp::LexError::CompilerPanic); + } + + // Catch panic to work around https://github.com/rust-lang/rust/issues/58736. + match panic::catch_unwind(|| Self::from_str(src)) { + Ok(Ok(ok)) => Ok(ok), + Ok(Err(lex)) => Err(imp::LexError::Compiler(lex)), + Err(_panic) => Err(imp::LexError::CompilerPanic), + } + } + + fn from_str_unchecked(src: &str) -> Self { + Self::from_str(src).unwrap() + } +} + +#[cfg(feature = "proc-macro")] +impl FromStr2 for proc_macro::TokenStream { + #[cfg(wrap_proc_macro)] + fn valid(src: &str) -> bool { + TokenStream::from_str_checked(src).is_ok() + } +} + +#[cfg(feature = "proc-macro")] +impl FromStr2 for proc_macro::Literal { + #[cfg(wrap_proc_macro)] + fn valid(src: &str) -> bool { + Literal::from_str_checked(src).is_ok() + } +} diff --git a/third_party/crates/proc-macro2-1.0.107/src/lib.rs b/third_party/crates/proc-macro2-1.0.107/src/lib.rs new file mode 100644 index 0000000..f590f9b --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/src/lib.rs @@ -0,0 +1,1527 @@ +//! [![github]](https://github.com/dtolnay/proc-macro2) [![crates-io]](https://crates.io/crates/proc-macro2) [![docs-rs]](crate) +//! +//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github +//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust +//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs +//! +//!
+//! +//! A wrapper around the procedural macro API of the compiler's [`proc_macro`] +//! crate. This library serves two purposes: +//! +//! - **Bring proc-macro-like functionality to other contexts like build.rs and +//! main.rs.** Types from `proc_macro` are entirely specific to procedural +//! macros and cannot ever exist in code outside of a procedural macro. +//! Meanwhile `proc_macro2` types may exist anywhere including non-macro code. +//! By developing foundational libraries like [syn] and [quote] against +//! `proc_macro2` rather than `proc_macro`, the procedural macro ecosystem +//! becomes easily applicable to many other use cases and we avoid +//! reimplementing non-macro equivalents of those libraries. +//! +//! - **Make procedural macros unit testable.** As a consequence of being +//! specific to procedural macros, nothing that uses `proc_macro` can be +//! executed from a unit test. In order for helper libraries or components of +//! a macro to be testable in isolation, they must be implemented using +//! `proc_macro2`. +//! +//! [syn]: https://github.com/dtolnay/syn +//! [quote]: https://github.com/dtolnay/quote +//! +//! # Usage +//! +//! The skeleton of a typical procedural macro typically looks like this: +//! +//! ``` +//! extern crate proc_macro; +//! +//! # const IGNORE: &str = stringify! { +//! #[proc_macro_derive(MyDerive)] +//! # }; +//! # #[cfg(wrap_proc_macro)] +//! pub fn my_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { +//! let input = proc_macro2::TokenStream::from(input); +//! +//! let output: proc_macro2::TokenStream = { +//! /* transform input */ +//! # input +//! }; +//! +//! proc_macro::TokenStream::from(output) +//! } +//! ``` +//! +//! If parsing with [Syn], you'll use [`parse_macro_input!`] instead to +//! propagate parse errors correctly back to the compiler when parsing fails. +//! +//! [`parse_macro_input!`]: https://docs.rs/syn/3/syn/macro.parse_macro_input.html +//! +//! # Unstable features +//! +//! The default feature set of proc-macro2 tracks the most recent stable +//! compiler API. Functionality in `proc_macro` that is not yet stable is not +//! exposed by proc-macro2 by default. +//! +//! To opt into the additional APIs available in the most recent nightly +//! compiler, the `procmacro2_semver_exempt` config flag must be passed to +//! rustc. We will polyfill those nightly-only APIs back to Rust 1.71.0. As +//! these are unstable APIs that track the nightly compiler, minor versions of +//! proc-macro2 may make breaking changes to them at any time. +//! +//! ```sh +//! RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo build +//! ``` +//! +//! Note that this must not only be done for your crate, but for any crate that +//! depends on your crate. This infectious nature is intentional, as it serves +//! as a reminder that you are outside of the normal semver guarantees. +//! +//! Semver exempt methods are marked as such in the proc-macro2 documentation. +//! +//! # Thread-Safety +//! +//! Most types in this crate are `!Sync` because the underlying compiler +//! types make use of thread-local memory, meaning they cannot be accessed from +//! a different thread. + +#![no_std] +#![doc(html_root_url = "https://docs.rs/proc-macro2/1.0.107")] +#![cfg_attr(any(proc_macro_span, super_unstable), feature(proc_macro_span))] +#![cfg_attr(super_unstable, feature(proc_macro_def_site))] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![deny(unsafe_op_in_unsafe_fn)] +#![allow( + clippy::cast_lossless, + clippy::cast_possible_truncation, + clippy::checked_conversions, + clippy::doc_markdown, + clippy::elidable_lifetime_names, + clippy::incompatible_msrv, + clippy::items_after_statements, + clippy::iter_without_into_iter, + clippy::let_underscore_untyped, + clippy::manual_assert, + clippy::manual_range_contains, + clippy::missing_panics_doc, + clippy::missing_safety_doc, + clippy::must_use_candidate, + clippy::needless_doctest_main, + clippy::needless_lifetimes, + clippy::new_without_default, + clippy::return_self_not_must_use, + clippy::shadow_unrelated, + clippy::trivially_copy_pass_by_ref, + clippy::uninlined_format_args, + clippy::unnecessary_wraps, + clippy::unused_self, + clippy::used_underscore_binding, + clippy::vec_init_then_push +)] +#![allow(unknown_lints, mismatched_lifetime_syntaxes)] + +#[cfg(all(procmacro2_semver_exempt, wrap_proc_macro, not(super_unstable)))] +compile_error! {"\ + Something is not right. If you've tried to turn on \ + procmacro2_semver_exempt, you need to ensure that it \ + is turned on for the compilation of the proc-macro2 \ + build script as well. +"} + +#[cfg(all( + procmacro2_nightly_testing, + feature = "proc-macro", + not(proc_macro_span) +))] +compile_error! {"\ + Build script probe failed to compile. +"} + +extern crate alloc; +extern crate std; + +#[cfg(feature = "proc-macro")] +extern crate proc_macro; + +mod marker; +mod parse; +mod probe; +mod rcvec; + +#[cfg(wrap_proc_macro)] +mod detection; + +// Public for proc_macro2::fallback::force() and unforce(), but those are quite +// a niche use case so we omit it from rustdoc. +#[doc(hidden)] +pub mod fallback; + +pub mod extra; + +#[cfg(not(wrap_proc_macro))] +use crate::fallback as imp; +#[path = "wrapper.rs"] +#[cfg(wrap_proc_macro)] +mod imp; + +#[cfg(span_locations)] +mod location; + +#[cfg(procmacro2_semver_exempt)] +mod num; +#[cfg(procmacro2_semver_exempt)] +#[allow(dead_code)] +mod rustc_literal_escaper; + +use crate::extra::DelimSpan; +use crate::marker::{ProcMacroAutoTraits, MARKER}; +#[cfg(procmacro2_semver_exempt)] +use crate::rustc_literal_escaper::MixedUnit; +#[cfg(procmacro2_semver_exempt)] +use alloc::borrow::ToOwned as _; +use alloc::string::{String, ToString as _}; +#[cfg(procmacro2_semver_exempt)] +use alloc::vec::Vec; +use core::cmp::Ordering; +use core::ffi::CStr; +use core::fmt::{self, Debug, Display}; +use core::hash::{Hash, Hasher}; +#[cfg(span_locations)] +use core::ops::Range; +use core::ops::RangeBounds; +use core::str::FromStr; +use std::error::Error; +#[cfg(span_locations)] +use std::path::PathBuf; + +#[cfg(span_locations)] +#[cfg_attr(docsrs, doc(cfg(feature = "span-locations")))] +pub use crate::location::LineColumn; + +#[cfg(procmacro2_semver_exempt)] +#[cfg_attr(docsrs, doc(cfg(procmacro2_semver_exempt)))] +pub use crate::rustc_literal_escaper::EscapeError; + +/// An abstract stream of tokens, or more concretely a sequence of token trees. +/// +/// This type provides interfaces for iterating over token trees and for +/// collecting token trees into one stream. +/// +/// Token stream is both the input and output of `#[proc_macro]`, +/// `#[proc_macro_attribute]` and `#[proc_macro_derive]` definitions. +#[derive(Clone)] +pub struct TokenStream { + inner: imp::TokenStream, + _marker: ProcMacroAutoTraits, +} + +/// Error returned from `TokenStream::from_str`. +pub struct LexError { + inner: imp::LexError, + _marker: ProcMacroAutoTraits, +} + +impl TokenStream { + fn _new(inner: imp::TokenStream) -> Self { + TokenStream { + inner, + _marker: MARKER, + } + } + + fn _new_fallback(inner: fallback::TokenStream) -> Self { + TokenStream { + inner: imp::TokenStream::from(inner), + _marker: MARKER, + } + } + + /// Returns an empty `TokenStream` containing no token trees. + pub fn new() -> Self { + TokenStream::_new(imp::TokenStream::new()) + } + + /// Checks if this `TokenStream` is empty. + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } +} + +/// `TokenStream::default()` returns an empty stream, +/// i.e. this is equivalent with `TokenStream::new()`. +impl Default for TokenStream { + fn default() -> Self { + TokenStream::new() + } +} + +/// Attempts to break the string into tokens and parse those tokens into a token +/// stream. +/// +/// May fail for a number of reasons, for example, if the string contains +/// unbalanced delimiters or characters not existing in the language. +/// +/// NOTE: Some errors may cause panics instead of returning `LexError`. We +/// reserve the right to change these errors into `LexError`s later. +impl FromStr for TokenStream { + type Err = LexError; + + fn from_str(src: &str) -> Result { + match imp::TokenStream::from_str_checked(src) { + Ok(tokens) => Ok(TokenStream::_new(tokens)), + Err(lex) => Err(LexError { + inner: lex, + _marker: MARKER, + }), + } + } +} + +#[cfg(feature = "proc-macro")] +#[cfg_attr(docsrs, doc(cfg(feature = "proc-macro")))] +impl From for TokenStream { + fn from(inner: proc_macro::TokenStream) -> Self { + TokenStream::_new(imp::TokenStream::from(inner)) + } +} + +#[cfg(feature = "proc-macro")] +#[cfg_attr(docsrs, doc(cfg(feature = "proc-macro")))] +impl From for proc_macro::TokenStream { + fn from(inner: TokenStream) -> Self { + proc_macro::TokenStream::from(inner.inner) + } +} + +impl From for TokenStream { + fn from(token: TokenTree) -> Self { + TokenStream::_new(imp::TokenStream::from(token)) + } +} + +impl Extend for TokenStream { + fn extend>(&mut self, tokens: I) { + self.inner.extend(tokens); + } +} + +impl Extend for TokenStream { + fn extend>(&mut self, streams: I) { + self.inner + .extend(streams.into_iter().map(|stream| stream.inner)); + } +} + +impl Extend for TokenStream { + fn extend>(&mut self, tokens: I) { + self.inner.extend(tokens.into_iter().map(TokenTree::Group)); + } +} + +impl Extend for TokenStream { + fn extend>(&mut self, tokens: I) { + self.inner.extend(tokens.into_iter().map(TokenTree::Ident)); + } +} + +impl Extend for TokenStream { + fn extend>(&mut self, tokens: I) { + self.inner.extend(tokens.into_iter().map(TokenTree::Punct)); + } +} + +impl Extend for TokenStream { + fn extend>(&mut self, tokens: I) { + self.inner + .extend(tokens.into_iter().map(TokenTree::Literal)); + } +} + +/// Collects a number of token trees into a single stream. +impl FromIterator for TokenStream { + fn from_iter>(tokens: I) -> Self { + TokenStream::_new(tokens.into_iter().collect()) + } +} + +impl FromIterator for TokenStream { + fn from_iter>(streams: I) -> Self { + TokenStream::_new(streams.into_iter().map(|i| i.inner).collect()) + } +} + +/// Prints the token stream as a string that is supposed to be losslessly +/// convertible back into the same token stream (modulo spans), except for +/// possibly `TokenTree::Group`s with `Delimiter::None` delimiters and negative +/// numeric literals. +impl Display for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.inner, f) + } +} + +/// Prints token in a form convenient for debugging. +impl Debug for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.inner, f) + } +} + +impl LexError { + pub fn span(&self) -> Span { + Span::_new(self.inner.span()) + } +} + +impl Debug for LexError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.inner, f) + } +} + +impl Display for LexError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.inner, f) + } +} + +impl Error for LexError {} + +/// A region of source code, along with macro expansion information. +#[derive(Copy, Clone)] +pub struct Span { + inner: imp::Span, + _marker: ProcMacroAutoTraits, +} + +impl Span { + fn _new(inner: imp::Span) -> Self { + Span { + inner, + _marker: MARKER, + } + } + + fn _new_fallback(inner: fallback::Span) -> Self { + Span { + inner: imp::Span::from(inner), + _marker: MARKER, + } + } + + /// The span of the invocation of the current procedural macro. + /// + /// Identifiers created with this span will be resolved as if they were + /// written directly at the macro call location (call-site hygiene) and + /// other code at the macro call site will be able to refer to them as well. + pub fn call_site() -> Self { + Span::_new(imp::Span::call_site()) + } + + /// The span located at the invocation of the procedural macro, but with + /// local variables, labels, and `$crate` resolved at the definition site + /// of the macro. This is the same hygiene behavior as `macro_rules`. + pub fn mixed_site() -> Self { + Span::_new(imp::Span::mixed_site()) + } + + /// A span that resolves at the macro definition site. + /// + /// This method is semver exempt and not exposed by default. + #[cfg(procmacro2_semver_exempt)] + #[cfg_attr(docsrs, doc(cfg(procmacro2_semver_exempt)))] + pub fn def_site() -> Self { + Span::_new(imp::Span::def_site()) + } + + /// Creates a new span with the same line/column information as `self` but + /// that resolves symbols as though it were at `other`. + pub fn resolved_at(&self, other: Span) -> Span { + Span::_new(self.inner.resolved_at(other.inner)) + } + + /// Creates a new span with the same name resolution behavior as `self` but + /// with the line/column information of `other`. + pub fn located_at(&self, other: Span) -> Span { + Span::_new(self.inner.located_at(other.inner)) + } + + /// Convert `proc_macro2::Span` to `proc_macro::Span`. + /// + /// This method is available when building with a nightly compiler, or when + /// building with rustc 1.29+ *without* semver exempt features. + /// + /// # Panics + /// + /// Panics if called from outside of a procedural macro. Unlike + /// `proc_macro2::Span`, the `proc_macro::Span` type can only exist within + /// the context of a procedural macro invocation. + #[cfg(wrap_proc_macro)] + pub fn unwrap(self) -> proc_macro::Span { + self.inner.unwrap() + } + + // Soft deprecated. Please use Span::unwrap. + #[cfg(wrap_proc_macro)] + #[doc(hidden)] + pub fn unstable(self) -> proc_macro::Span { + self.unwrap() + } + + /// Returns the span's byte position range in the source file. + /// + /// This method requires the `"span-locations"` feature to be enabled. + /// + /// When executing in a procedural macro context, the returned range is only + /// accurate if compiled with a nightly toolchain. The stable toolchain does + /// not have this information available. When executing outside of a + /// procedural macro, such as main.rs or build.rs, the byte range is always + /// accurate regardless of toolchain. + #[cfg(span_locations)] + #[cfg_attr(docsrs, doc(cfg(feature = "span-locations")))] + pub fn byte_range(&self) -> Range { + self.inner.byte_range() + } + + /// Get the starting line/column in the source file for this span. + /// + /// This method requires the `"span-locations"` feature to be enabled. + /// + /// When executing in a procedural macro context, the returned line/column + /// are only meaningful if compiled with a nightly toolchain. The stable + /// toolchain does not have this information available. When executing + /// outside of a procedural macro, such as main.rs or build.rs, the + /// line/column are always meaningful regardless of toolchain. + #[cfg(span_locations)] + #[cfg_attr(docsrs, doc(cfg(feature = "span-locations")))] + pub fn start(&self) -> LineColumn { + self.inner.start() + } + + /// Get the ending line/column in the source file for this span. + /// + /// This method requires the `"span-locations"` feature to be enabled. + /// + /// When executing in a procedural macro context, the returned line/column + /// are only meaningful if compiled with a nightly toolchain. The stable + /// toolchain does not have this information available. When executing + /// outside of a procedural macro, such as main.rs or build.rs, the + /// line/column are always meaningful regardless of toolchain. + #[cfg(span_locations)] + #[cfg_attr(docsrs, doc(cfg(feature = "span-locations")))] + pub fn end(&self) -> LineColumn { + self.inner.end() + } + + /// The path to the source file in which this span occurs, for display + /// purposes. + /// + /// This might not correspond to a valid file system path. It might be + /// remapped, or might be an artificial path such as `""`. + #[cfg(span_locations)] + #[cfg_attr(docsrs, doc(cfg(feature = "span-locations")))] + pub fn file(&self) -> String { + self.inner.file() + } + + /// The path to the source file in which this span occurs on disk. + /// + /// This is the actual path on disk. It is unaffected by path remapping. + /// + /// This path should not be embedded in the output of the macro; prefer + /// `file()` instead. + #[cfg(span_locations)] + #[cfg_attr(docsrs, doc(cfg(feature = "span-locations")))] + pub fn local_file(&self) -> Option { + self.inner.local_file() + } + + /// Create a new span encompassing `self` and `other`. + /// + /// Returns `None` if `self` and `other` are from different files. + /// + /// Warning: the underlying [`proc_macro::Span::join`] method is + /// nightly-only. When called from within a procedural macro not using a + /// nightly compiler, this method will always return `None`. + pub fn join(&self, other: Span) -> Option { + self.inner.join(other.inner).map(Span::_new) + } + + /// Compares two spans to see if they're equal. + /// + /// This method is semver exempt and not exposed by default. + #[cfg(procmacro2_semver_exempt)] + #[cfg_attr(docsrs, doc(cfg(procmacro2_semver_exempt)))] + pub fn eq(&self, other: &Span) -> bool { + self.inner.eq(&other.inner) + } + + /// Returns the source text behind a span. This preserves the original + /// source code, including spaces and comments. It only returns a result if + /// the span corresponds to real source code. + /// + /// Note: The observable result of a macro should only rely on the tokens + /// and not on this source text. The result of this function is a best + /// effort to be used for diagnostics only. + pub fn source_text(&self) -> Option { + self.inner.source_text() + } +} + +/// Prints a span in a form convenient for debugging. +impl Debug for Span { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.inner, f) + } +} + +/// A single token or a delimited sequence of token trees (e.g. `[1, (), ..]`). +#[derive(Clone)] +pub enum TokenTree { + /// A token stream surrounded by bracket delimiters. + Group(Group), + /// An identifier. + Ident(Ident), + /// A single punctuation character (`+`, `,`, `$`, etc.). + Punct(Punct), + /// A literal character (`'a'`), string (`"hello"`), number (`2.3`), etc. + Literal(Literal), +} + +impl TokenTree { + /// Returns the span of this tree, delegating to the `span` method of + /// the contained token or a delimited stream. + pub fn span(&self) -> Span { + match self { + TokenTree::Group(t) => t.span(), + TokenTree::Ident(t) => t.span(), + TokenTree::Punct(t) => t.span(), + TokenTree::Literal(t) => t.span(), + } + } + + /// Configures the span for *only this token*. + /// + /// Note that if this token is a `Group` then this method will not configure + /// the span of each of the internal tokens, this will simply delegate to + /// the `set_span` method of each variant. + pub fn set_span(&mut self, span: Span) { + match self { + TokenTree::Group(t) => t.set_span(span), + TokenTree::Ident(t) => t.set_span(span), + TokenTree::Punct(t) => t.set_span(span), + TokenTree::Literal(t) => t.set_span(span), + } + } +} + +impl From for TokenTree { + fn from(g: Group) -> Self { + TokenTree::Group(g) + } +} + +impl From for TokenTree { + fn from(g: Ident) -> Self { + TokenTree::Ident(g) + } +} + +impl From for TokenTree { + fn from(g: Punct) -> Self { + TokenTree::Punct(g) + } +} + +impl From for TokenTree { + fn from(g: Literal) -> Self { + TokenTree::Literal(g) + } +} + +/// Prints the token tree as a string that is supposed to be losslessly +/// convertible back into the same token tree (modulo spans), except for +/// possibly `TokenTree::Group`s with `Delimiter::None` delimiters and negative +/// numeric literals. +impl Display for TokenTree { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + TokenTree::Group(t) => Display::fmt(t, f), + TokenTree::Ident(t) => Display::fmt(t, f), + TokenTree::Punct(t) => Display::fmt(t, f), + TokenTree::Literal(t) => Display::fmt(t, f), + } + } +} + +/// Prints token tree in a form convenient for debugging. +impl Debug for TokenTree { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Each of these has the name in the struct type in the derived debug, + // so don't bother with an extra layer of indirection + match self { + TokenTree::Group(t) => Debug::fmt(t, f), + TokenTree::Ident(t) => { + let mut debug = f.debug_struct("Ident"); + debug.field("sym", &format_args!("{}", t)); + imp::debug_span_field_if_nontrivial(&mut debug, t.span().inner); + debug.finish() + } + TokenTree::Punct(t) => Debug::fmt(t, f), + TokenTree::Literal(t) => Debug::fmt(t, f), + } + } +} + +/// A delimited token stream. +/// +/// A `Group` internally contains a `TokenStream` which is surrounded by +/// `Delimiter`s. +#[derive(Clone)] +pub struct Group { + inner: imp::Group, +} + +/// Describes how a sequence of token trees is delimited. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum Delimiter { + /// `( ... )` + Parenthesis, + /// `{ ... }` + Brace, + /// `[ ... ]` + Bracket, + /// `∅ ... ∅` + /// + /// An invisible delimiter, that may, for example, appear around tokens + /// coming from a "macro variable" `$var`. It is important to preserve + /// operator priorities in cases like `$var * 3` where `$var` is `1 + 2`. + /// Invisible delimiters may not survive roundtrip of a token stream through + /// a string. + /// + ///
+ /// + /// Note: rustc currently can ignore the grouping of tokens delimited by `None` in the output + /// of a proc_macro. Only `None`-delimited groups created by a macro_rules macro in the input + /// of a proc_macro macro are preserved, and only in very specific circumstances. + /// Any `None`-delimited groups (re)created by a proc_macro will therefore not preserve + /// operator priorities as indicated above. The other `Delimiter` variants should be used + /// instead in this context. This is a rustc bug. For details, see + /// [rust-lang/rust#67062](https://github.com/rust-lang/rust/issues/67062). + /// + ///
+ None, +} + +impl Group { + fn _new(inner: imp::Group) -> Self { + Group { inner } + } + + fn _new_fallback(inner: fallback::Group) -> Self { + Group { + inner: imp::Group::from(inner), + } + } + + /// Creates a new `Group` with the given delimiter and token stream. + /// + /// This constructor will set the span for this group to + /// `Span::call_site()`. To change the span you can use the `set_span` + /// method below. + pub fn new(delimiter: Delimiter, stream: TokenStream) -> Self { + Group { + inner: imp::Group::new(delimiter, stream.inner), + } + } + + /// Returns the punctuation used as the delimiter for this group: a set of + /// parentheses, square brackets, or curly braces. + pub fn delimiter(&self) -> Delimiter { + self.inner.delimiter() + } + + /// Returns the `TokenStream` of tokens that are delimited in this `Group`. + /// + /// Note that the returned token stream does not include the delimiter + /// returned above. + pub fn stream(&self) -> TokenStream { + TokenStream::_new(self.inner.stream()) + } + + /// Returns the span for the delimiters of this token stream, spanning the + /// entire `Group`. + /// + /// ```text + /// pub fn span(&self) -> Span { + /// ^^^^^^^ + /// ``` + pub fn span(&self) -> Span { + Span::_new(self.inner.span()) + } + + /// Returns the span pointing to the opening delimiter of this group. + /// + /// ```text + /// pub fn span_open(&self) -> Span { + /// ^ + /// ``` + pub fn span_open(&self) -> Span { + Span::_new(self.inner.span_open()) + } + + /// Returns the span pointing to the closing delimiter of this group. + /// + /// ```text + /// pub fn span_close(&self) -> Span { + /// ^ + /// ``` + pub fn span_close(&self) -> Span { + Span::_new(self.inner.span_close()) + } + + /// Returns an object that holds this group's `span_open()` and + /// `span_close()` together (in a more compact representation than holding + /// those 2 spans individually). + pub fn delim_span(&self) -> DelimSpan { + DelimSpan::new(&self.inner) + } + + /// Configures the span for this `Group`'s delimiters, but not its internal + /// tokens. + /// + /// This method will **not** set the span of all the internal tokens spanned + /// by this group, but rather it will only set the span of the delimiter + /// tokens at the level of the `Group`. + pub fn set_span(&mut self, span: Span) { + self.inner.set_span(span.inner); + } +} + +/// Prints the group as a string that should be losslessly convertible back +/// into the same group (modulo spans), except for possibly `TokenTree::Group`s +/// with `Delimiter::None` delimiters. +impl Display for Group { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.inner, formatter) + } +} + +impl Debug for Group { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.inner, formatter) + } +} + +/// A `Punct` is a single punctuation character like `+`, `-` or `#`. +/// +/// Multicharacter operators like `+=` are represented as two instances of +/// `Punct` with different forms of `Spacing` returned. +#[derive(Clone)] +pub struct Punct { + ch: char, + spacing: Spacing, + span: Span, +} + +/// Whether a `Punct` is followed immediately by another `Punct` or followed by +/// another token or whitespace. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum Spacing { + /// E.g. `+` is `Alone` in `+ =`, `+ident` or `+()`. + Alone, + /// E.g. `+` is `Joint` in `+=` or `'` is `Joint` in `'#`. + /// + /// Additionally, single quote `'` can join with identifiers to form + /// lifetimes `'ident`. + Joint, +} + +impl Punct { + /// Creates a new `Punct` from the given character and spacing. + /// + /// The `ch` argument must be a valid punctuation character permitted by the + /// language, otherwise the function will panic. + /// + /// The returned `Punct` will have the default span of `Span::call_site()` + /// which can be further configured with the `set_span` method below. + pub fn new(ch: char, spacing: Spacing) -> Self { + if let '!' | '#' | '$' | '%' | '&' | '\'' | '*' | '+' | ',' | '-' | '.' | '/' | ':' | ';' + | '<' | '=' | '>' | '?' | '@' | '^' | '|' | '~' = ch + { + Punct { + ch, + spacing, + span: Span::call_site(), + } + } else { + panic!("unsupported proc macro punctuation character {:?}", ch); + } + } + + /// Returns the value of this punctuation character as `char`. + pub fn as_char(&self) -> char { + self.ch + } + + /// Returns the spacing of this punctuation character, indicating whether + /// it's immediately followed by another `Punct` in the token stream, so + /// they can potentially be combined into a multicharacter operator + /// (`Joint`), or it's followed by some other token or whitespace (`Alone`) + /// so the operator has certainly ended. + pub fn spacing(&self) -> Spacing { + self.spacing + } + + /// Returns the span for this punctuation character. + pub fn span(&self) -> Span { + self.span + } + + /// Configure the span for this punctuation character. + pub fn set_span(&mut self, span: Span) { + self.span = span; + } +} + +/// Prints the punctuation character as a string that should be losslessly +/// convertible back into the same character. +impl Display for Punct { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.ch, f) + } +} + +impl Debug for Punct { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut debug = fmt.debug_struct("Punct"); + debug.field("char", &self.ch); + debug.field("spacing", &self.spacing); + imp::debug_span_field_if_nontrivial(&mut debug, self.span.inner); + debug.finish() + } +} + +/// A word of Rust code, which may be a keyword or legal variable name. +/// +/// An identifier consists of at least one Unicode code point, the first of +/// which has the XID_Start property and the rest of which have the XID_Continue +/// property. +/// +/// - The empty string is not an identifier. Use `Option`. +/// - A lifetime is not an identifier. Use `syn::Lifetime` instead. +/// +/// An identifier constructed with `Ident::new` is permitted to be a Rust +/// keyword, though parsing one through its [`Parse`] implementation rejects +/// Rust keywords. Use `input.call(Ident::parse_any)` when parsing to match the +/// behaviour of `Ident::new`. +/// +/// [`Parse`]: https://docs.rs/syn/3/syn/parse/trait.Parse.html +/// +/// # Examples +/// +/// A new ident can be created from a string using the `Ident::new` function. +/// A span must be provided explicitly which governs the name resolution +/// behavior of the resulting identifier. +/// +/// ``` +/// use proc_macro2::{Ident, Span}; +/// +/// fn main() { +/// let call_ident = Ident::new("calligraphy", Span::call_site()); +/// +/// println!("{}", call_ident); +/// } +/// ``` +/// +/// An ident can be interpolated into a token stream using the `quote!` macro. +/// +/// ``` +/// use proc_macro2::{Ident, Span}; +/// use quote::quote; +/// +/// fn main() { +/// let ident = Ident::new("demo", Span::call_site()); +/// +/// // Create a variable binding whose name is this ident. +/// let expanded = quote! { let #ident = 10; }; +/// +/// // Create a variable binding with a slightly different name. +/// let temp_ident = Ident::new(&format!("new_{}", ident), Span::call_site()); +/// let expanded = quote! { let #temp_ident = 10; }; +/// } +/// ``` +/// +/// A string representation of the ident is available through the `to_string()` +/// method. +/// +/// ``` +/// # use proc_macro2::{Ident, Span}; +/// # +/// # let ident = Ident::new("another_identifier", Span::call_site()); +/// # +/// // Examine the ident as a string. +/// let ident_string = ident.to_string(); +/// if ident_string.len() > 60 { +/// println!("Very long identifier: {}", ident_string) +/// } +/// ``` +#[derive(Clone)] +pub struct Ident { + inner: imp::Ident, + _marker: ProcMacroAutoTraits, +} + +impl Ident { + fn _new(inner: imp::Ident) -> Self { + Ident { + inner, + _marker: MARKER, + } + } + + fn _new_fallback(inner: fallback::Ident) -> Self { + Ident { + inner: imp::Ident::from(inner), + _marker: MARKER, + } + } + + /// Creates a new `Ident` with the given `string` as well as the specified + /// `span`. + /// + /// The `string` argument must be a valid identifier permitted by the + /// language, otherwise the function will panic. + /// + /// Note that `span`, currently in rustc, configures the hygiene information + /// for this identifier. + /// + /// As of this time `Span::call_site()` explicitly opts-in to "call-site" + /// hygiene meaning that identifiers created with this span will be resolved + /// as if they were written directly at the location of the macro call, and + /// other code at the macro call site will be able to refer to them as well. + /// + /// Later spans like `Span::def_site()` will allow to opt-in to + /// "definition-site" hygiene meaning that identifiers created with this + /// span will be resolved at the location of the macro definition and other + /// code at the macro call site will not be able to refer to them. + /// + /// Due to the current importance of hygiene this constructor, unlike other + /// tokens, requires a `Span` to be specified at construction. + /// + /// # Panics + /// + /// Panics if the input string is neither a keyword nor a legal variable + /// name. If you are not sure whether the string contains an identifier and + /// need to handle an error case, use + /// syn::parse_str::<Ident> + /// rather than `Ident::new`. + #[track_caller] + pub fn new(string: &str, span: Span) -> Self { + Ident::_new(imp::Ident::new_checked(string, span.inner)) + } + + /// Same as `Ident::new`, but creates a raw identifier (`r#ident`). The + /// `string` argument must be a valid identifier permitted by the language + /// (including keywords, e.g. `fn`). Keywords which are usable in path + /// segments (e.g. `self`, `super`) are not supported, and will cause a + /// panic. + #[track_caller] + pub fn new_raw(string: &str, span: Span) -> Self { + Ident::_new(imp::Ident::new_raw_checked(string, span.inner)) + } + + /// Returns the span of this `Ident`. + pub fn span(&self) -> Span { + Span::_new(self.inner.span()) + } + + /// Configures the span of this `Ident`, possibly changing its hygiene + /// context. + pub fn set_span(&mut self, span: Span) { + self.inner.set_span(span.inner); + } +} + +impl PartialEq for Ident { + fn eq(&self, other: &Ident) -> bool { + self.inner == other.inner + } +} + +impl PartialEq for Ident +where + T: ?Sized + AsRef, +{ + fn eq(&self, other: &T) -> bool { + self.inner == other + } +} + +impl Eq for Ident {} + +impl PartialOrd for Ident { + fn partial_cmp(&self, other: &Ident) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Ident { + fn cmp(&self, other: &Ident) -> Ordering { + self.to_string().cmp(&other.to_string()) + } +} + +impl Hash for Ident { + fn hash(&self, hasher: &mut H) { + self.to_string().hash(hasher); + } +} + +/// Prints the identifier as a string that should be losslessly convertible back +/// into the same identifier. +impl Display for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.inner, f) + } +} + +impl Debug for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.inner, f) + } +} + +/// A literal string (`"hello"`), byte string (`b"hello"`), character (`'a'`), +/// byte character (`b'a'`), an integer or floating point number with or without +/// a suffix (`1`, `1u8`, `2.3`, `2.3f32`). +/// +/// Boolean literals like `true` and `false` do not belong here, they are +/// `Ident`s. +#[derive(Clone)] +pub struct Literal { + inner: imp::Literal, + _marker: ProcMacroAutoTraits, +} + +macro_rules! suffixed_int_literals { + ($($name:ident => $kind:ident,)*) => ($( + /// Creates a new suffixed integer literal with the specified value. + /// + /// This function will create an integer like `1u32` where the integer + /// value specified is the first part of the token and the integral is + /// also suffixed at the end. Literals created from negative numbers may + /// not survive roundtrips through `TokenStream` or strings and may be + /// broken into two tokens (`-` and positive literal). + /// + /// Literals created through this method have the `Span::call_site()` + /// span by default, which can be configured with the `set_span` method + /// below. + pub fn $name(n: $kind) -> Literal { + Literal::_new(imp::Literal::$name(n)) + } + )*) +} + +macro_rules! unsuffixed_int_literals { + ($($name:ident => $kind:ident,)*) => ($( + /// Creates a new unsuffixed integer literal with the specified value. + /// + /// This function will create an integer like `1` where the integer + /// value specified is the first part of the token. No suffix is + /// specified on this token, meaning that invocations like + /// `Literal::i8_unsuffixed(1)` are equivalent to + /// `Literal::u32_unsuffixed(1)`. Literals created from negative numbers + /// may not survive roundtrips through `TokenStream` or strings and may + /// be broken into two tokens (`-` and positive literal). + /// + /// Literals created through this method have the `Span::call_site()` + /// span by default, which can be configured with the `set_span` method + /// below. + pub fn $name(n: $kind) -> Literal { + Literal::_new(imp::Literal::$name(n)) + } + )*) +} + +impl Literal { + fn _new(inner: imp::Literal) -> Self { + Literal { + inner, + _marker: MARKER, + } + } + + fn _new_fallback(inner: fallback::Literal) -> Self { + Literal { + inner: imp::Literal::from(inner), + _marker: MARKER, + } + } + + suffixed_int_literals! { + u8_suffixed => u8, + u16_suffixed => u16, + u32_suffixed => u32, + u64_suffixed => u64, + u128_suffixed => u128, + usize_suffixed => usize, + i8_suffixed => i8, + i16_suffixed => i16, + i32_suffixed => i32, + i64_suffixed => i64, + i128_suffixed => i128, + isize_suffixed => isize, + } + + unsuffixed_int_literals! { + u8_unsuffixed => u8, + u16_unsuffixed => u16, + u32_unsuffixed => u32, + u64_unsuffixed => u64, + u128_unsuffixed => u128, + usize_unsuffixed => usize, + i8_unsuffixed => i8, + i16_unsuffixed => i16, + i32_unsuffixed => i32, + i64_unsuffixed => i64, + i128_unsuffixed => i128, + isize_unsuffixed => isize, + } + + /// Creates a new unsuffixed floating-point literal. + /// + /// This constructor is similar to those like `Literal::i8_unsuffixed` where + /// the float's value is emitted directly into the token but no suffix is + /// used, so it may be inferred to be a `f64` later in the compiler. + /// Literals created from negative numbers may not survive round-trips + /// through `TokenStream` or strings and may be broken into two tokens (`-` + /// and positive literal). + /// + /// # Panics + /// + /// This function requires that the specified float is finite, for example + /// if it is infinity or NaN this function will panic. + pub fn f64_unsuffixed(f: f64) -> Literal { + assert!(f.is_finite()); + Literal::_new(imp::Literal::f64_unsuffixed(f)) + } + + /// Creates a new suffixed floating-point literal. + /// + /// This constructor will create a literal like `1.0f64` where the value + /// specified is the preceding part of the token and `f64` is the suffix of + /// the token. This token will always be inferred to be an `f64` in the + /// compiler. Literals created from negative numbers may not survive + /// round-trips through `TokenStream` or strings and may be broken into two + /// tokens (`-` and positive literal). + /// + /// # Panics + /// + /// This function requires that the specified float is finite, for example + /// if it is infinity or NaN this function will panic. + pub fn f64_suffixed(f: f64) -> Literal { + assert!(f.is_finite()); + Literal::_new(imp::Literal::f64_suffixed(f)) + } + + /// Creates a new unsuffixed floating-point literal. + /// + /// This constructor is similar to those like `Literal::i8_unsuffixed` where + /// the float's value is emitted directly into the token but no suffix is + /// used, so it may be inferred to be a `f64` later in the compiler. + /// Literals created from negative numbers may not survive round-trips + /// through `TokenStream` or strings and may be broken into two tokens (`-` + /// and positive literal). + /// + /// # Panics + /// + /// This function requires that the specified float is finite, for example + /// if it is infinity or NaN this function will panic. + pub fn f32_unsuffixed(f: f32) -> Literal { + assert!(f.is_finite()); + Literal::_new(imp::Literal::f32_unsuffixed(f)) + } + + /// Creates a new suffixed floating-point literal. + /// + /// This constructor will create a literal like `1.0f32` where the value + /// specified is the preceding part of the token and `f32` is the suffix of + /// the token. This token will always be inferred to be an `f32` in the + /// compiler. Literals created from negative numbers may not survive + /// round-trips through `TokenStream` or strings and may be broken into two + /// tokens (`-` and positive literal). + /// + /// # Panics + /// + /// This function requires that the specified float is finite, for example + /// if it is infinity or NaN this function will panic. + pub fn f32_suffixed(f: f32) -> Literal { + assert!(f.is_finite()); + Literal::_new(imp::Literal::f32_suffixed(f)) + } + + /// String literal. + pub fn string(string: &str) -> Literal { + Literal::_new(imp::Literal::string(string)) + } + + /// Character literal. + pub fn character(ch: char) -> Literal { + Literal::_new(imp::Literal::character(ch)) + } + + /// Byte character literal. + pub fn byte_character(byte: u8) -> Literal { + Literal::_new(imp::Literal::byte_character(byte)) + } + + /// Byte string literal. + pub fn byte_string(bytes: &[u8]) -> Literal { + Literal::_new(imp::Literal::byte_string(bytes)) + } + + /// C string literal. + pub fn c_string(string: &CStr) -> Literal { + Literal::_new(imp::Literal::c_string(string)) + } + + /// Returns the span encompassing this literal. + pub fn span(&self) -> Span { + Span::_new(self.inner.span()) + } + + /// Configures the span associated for this literal. + pub fn set_span(&mut self, span: Span) { + self.inner.set_span(span.inner); + } + + /// Returns a `Span` that is a subset of `self.span()` containing only + /// the source bytes in range `range`. Returns `None` if the would-be + /// trimmed span is outside the bounds of `self`. + /// + /// Warning: the underlying [`proc_macro::Literal::subspan`] method is + /// nightly-only. When called from within a procedural macro not using a + /// nightly compiler, this method will always return `None`. + pub fn subspan>(&self, range: R) -> Option { + self.inner.subspan(range).map(Span::_new) + } + + /// Returns the unescaped string value if this is a string literal. + #[cfg(procmacro2_semver_exempt)] + pub fn str_value(&self) -> Result { + let repr = self.to_string(); + + if repr.starts_with('"') && repr[1..].ends_with('"') { + let quoted = &repr[1..repr.len() - 1]; + let mut value = String::with_capacity(quoted.len()); + let mut error = None; + rustc_literal_escaper::unescape_str(quoted, |_range, res| match res { + Ok(ch) => value.push(ch), + Err(err) => { + if err.is_fatal() { + error = Some(ConversionErrorKind::FailedToUnescape(err)); + } + } + }); + return match error { + Some(error) => Err(error), + None => Ok(value), + }; + } + + if repr.starts_with('r') { + if let Some(raw) = get_raw(&repr[1..]) { + return Ok(raw.to_owned()); + } + } + + Err(ConversionErrorKind::InvalidLiteralKind) + } + + /// Returns the unescaped string value (including nul terminator) if this is + /// a c-string literal. + #[cfg(procmacro2_semver_exempt)] + pub fn cstr_value(&self) -> Result, ConversionErrorKind> { + let repr = self.to_string(); + + if repr.starts_with("c\"") && repr[2..].ends_with('"') { + let quoted = &repr[2..repr.len() - 1]; + let mut value = Vec::with_capacity(quoted.len()); + let mut error = None; + rustc_literal_escaper::unescape_c_str(quoted, |_range, res| match res { + Ok(MixedUnit::Char(ch)) => { + value.extend_from_slice(ch.get().encode_utf8(&mut [0; 4]).as_bytes()); + } + Ok(MixedUnit::HighByte(byte)) => value.push(byte.get()), + Err(err) => { + if err.is_fatal() { + error = Some(ConversionErrorKind::FailedToUnescape(err)); + } + } + }); + return match error { + Some(error) => Err(error), + None => { + value.push(b'\0'); + Ok(value) + } + }; + } + + if repr.starts_with("cr") { + if let Some(raw) = get_raw(&repr[2..]) { + let mut value = Vec::with_capacity(raw.len() + 1); + value.extend_from_slice(raw.as_bytes()); + value.push(b'\0'); + return Ok(value); + } + } + + Err(ConversionErrorKind::InvalidLiteralKind) + } + + /// Returns the unescaped string value if this is a byte string literal. + #[cfg(procmacro2_semver_exempt)] + pub fn byte_str_value(&self) -> Result, ConversionErrorKind> { + let repr = self.to_string(); + + if repr.starts_with("b\"") && repr[2..].ends_with('"') { + let quoted = &repr[2..repr.len() - 1]; + let mut value = Vec::with_capacity(quoted.len()); + let mut error = None; + rustc_literal_escaper::unescape_byte_str(quoted, |_range, res| match res { + Ok(byte) => value.push(byte), + Err(err) => { + if err.is_fatal() { + error = Some(ConversionErrorKind::FailedToUnescape(err)); + } + } + }); + return match error { + Some(error) => Err(error), + None => Ok(value), + }; + } + + if repr.starts_with("br") { + if let Some(raw) = get_raw(&repr[2..]) { + return Ok(raw.as_bytes().to_owned()); + } + } + + Err(ConversionErrorKind::InvalidLiteralKind) + } + + // Intended for the `quote!` macro to use when constructing a proc-macro2 + // token out of a macro_rules $:literal token, which is already known to be + // a valid literal. This avoids reparsing/validating the literal's string + // representation. This is not public API other than for quote. + #[doc(hidden)] + pub unsafe fn from_str_unchecked(repr: &str) -> Self { + Literal::_new(unsafe { imp::Literal::from_str_unchecked(repr) }) + } +} + +impl FromStr for Literal { + type Err = LexError; + + fn from_str(repr: &str) -> Result { + match imp::Literal::from_str_checked(repr) { + Ok(lit) => Ok(Literal::_new(lit)), + Err(lex) => Err(LexError { + inner: lex, + _marker: MARKER, + }), + } + } +} + +impl Debug for Literal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.inner, f) + } +} + +impl Display for Literal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.inner, f) + } +} + +/// Error when retrieving a string literal's unescaped value. +#[cfg(procmacro2_semver_exempt)] +#[derive(Debug, PartialEq, Eq)] +pub enum ConversionErrorKind { + /// The literal is of the right string kind, but its contents are malformed + /// in a way that cannot be unescaped to a value. + FailedToUnescape(EscapeError), + /// The literal is not of the string kind whose value was requested, for + /// example byte string vs UTF-8 string. + InvalidLiteralKind, +} + +// ###"..."### -> ... +#[cfg(procmacro2_semver_exempt)] +fn get_raw(repr: &str) -> Option<&str> { + let pounds = repr.len() - repr.trim_start_matches('#').len(); + if repr.len() >= pounds + 1 + 1 + pounds + && repr[pounds..].starts_with('"') + && repr.trim_end_matches('#').len() + pounds == repr.len() + && repr[..repr.len() - pounds].ends_with('"') + { + Some(&repr[pounds + 1..repr.len() - pounds - 1]) + } else { + None + } +} + +/// Public implementation details for the `TokenStream` type, such as iterators. +pub mod token_stream { + use crate::marker::{ProcMacroAutoTraits, MARKER}; + use crate::{imp, TokenTree}; + use core::fmt::{self, Debug}; + + pub use crate::TokenStream; + + /// An iterator over `TokenStream`'s `TokenTree`s. + /// + /// The iteration is "shallow", e.g. the iterator doesn't recurse into + /// delimited groups, and returns whole groups as token trees. + #[derive(Clone)] + pub struct IntoIter { + inner: imp::TokenTreeIter, + _marker: ProcMacroAutoTraits, + } + + impl Iterator for IntoIter { + type Item = TokenTree; + + fn next(&mut self) -> Option { + self.inner.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + } + + impl Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("TokenStream ")?; + f.debug_list().entries(self.clone()).finish() + } + } + + impl IntoIterator for TokenStream { + type Item = TokenTree; + type IntoIter = IntoIter; + + fn into_iter(self) -> IntoIter { + IntoIter { + inner: self.inner.into_iter(), + _marker: MARKER, + } + } + } +} diff --git a/third_party/crates/proc-macro2-1.0.107/src/location.rs b/third_party/crates/proc-macro2-1.0.107/src/location.rs new file mode 100644 index 0000000..7190e2d --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/src/location.rs @@ -0,0 +1,29 @@ +use core::cmp::Ordering; + +/// A line-column pair representing the start or end of a `Span`. +/// +/// This type is semver exempt and not exposed by default. +#[cfg_attr(docsrs, doc(cfg(feature = "span-locations")))] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct LineColumn { + /// The 1-indexed line in the source file on which the span starts or ends + /// (inclusive). + pub line: usize, + /// The 0-indexed column (in UTF-8 characters) in the source file on which + /// the span starts or ends (inclusive). + pub column: usize, +} + +impl Ord for LineColumn { + fn cmp(&self, other: &Self) -> Ordering { + self.line + .cmp(&other.line) + .then(self.column.cmp(&other.column)) + } +} + +impl PartialOrd for LineColumn { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} diff --git a/third_party/crates/proc-macro2-1.0.107/src/marker.rs b/third_party/crates/proc-macro2-1.0.107/src/marker.rs new file mode 100644 index 0000000..23b94ce --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/src/marker.rs @@ -0,0 +1,17 @@ +use alloc::rc::Rc; +use core::marker::PhantomData; +use core::panic::{RefUnwindSafe, UnwindSafe}; + +// Zero sized marker with the correct set of autotrait impls we want all proc +// macro types to have. +#[derive(Copy, Clone)] +#[cfg_attr( + all(procmacro2_semver_exempt, any(not(wrap_proc_macro), super_unstable)), + derive(PartialEq, Eq) +)] +pub(crate) struct ProcMacroAutoTraits(PhantomData>); + +pub(crate) const MARKER: ProcMacroAutoTraits = ProcMacroAutoTraits(PhantomData); + +impl UnwindSafe for ProcMacroAutoTraits {} +impl RefUnwindSafe for ProcMacroAutoTraits {} diff --git a/third_party/crates/proc-macro2-1.0.107/src/num.rs b/third_party/crates/proc-macro2-1.0.107/src/num.rs new file mode 100644 index 0000000..3ac82c8 --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/src/num.rs @@ -0,0 +1,17 @@ +// TODO: use NonZero in Rust 1.89+ +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct NonZeroChar(char); + +impl NonZeroChar { + pub fn new(ch: char) -> Option { + if ch == '\0' { + None + } else { + Some(NonZeroChar(ch)) + } + } + + pub fn get(self) -> char { + self.0 + } +} diff --git a/third_party/crates/proc-macro2-1.0.107/src/parse.rs b/third_party/crates/proc-macro2-1.0.107/src/parse.rs new file mode 100644 index 0000000..7de0a5c --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/src/parse.rs @@ -0,0 +1,991 @@ +use crate::fallback::{ + self, is_ident_continue, is_ident_start, Group, Ident, LexError, Literal, Span, TokenStream, + TokenStreamBuilder, +}; +use crate::{Delimiter, Punct, Spacing, TokenTree}; +use alloc::borrow::ToOwned as _; +use alloc::string::ToString as _; +use alloc::vec::Vec; +use core::char; +use core::str::{Bytes, CharIndices, Chars}; + +#[derive(Copy, Clone, Eq, PartialEq)] +pub(crate) struct Cursor<'a> { + pub(crate) rest: &'a str, + #[cfg(span_locations)] + pub(crate) off: u32, +} + +impl<'a> Cursor<'a> { + pub(crate) fn advance(&self, bytes: usize) -> Cursor<'a> { + let (_front, rest) = self.rest.split_at(bytes); + Cursor { + rest, + #[cfg(span_locations)] + off: self.off + _front.chars().count() as u32, + } + } + + pub(crate) fn starts_with(&self, s: &str) -> bool { + self.rest.starts_with(s) + } + + pub(crate) fn starts_with_char(&self, ch: char) -> bool { + self.rest.starts_with(ch) + } + + pub(crate) fn starts_with_fn(&self, f: Pattern) -> bool + where + Pattern: FnMut(char) -> bool, + { + self.rest.starts_with(f) + } + + pub(crate) fn is_empty(&self) -> bool { + self.rest.is_empty() + } + + fn len(&self) -> usize { + self.rest.len() + } + + fn as_bytes(&self) -> &'a [u8] { + self.rest.as_bytes() + } + + fn bytes(&self) -> Bytes<'a> { + self.rest.bytes() + } + + fn chars(&self) -> Chars<'a> { + self.rest.chars() + } + + fn char_indices(&self) -> CharIndices<'a> { + self.rest.char_indices() + } + + fn parse(&self, tag: &str) -> Result, Reject> { + if self.starts_with(tag) { + Ok(self.advance(tag.len())) + } else { + Err(Reject) + } + } +} + +pub(crate) struct Reject; +type PResult<'a, O> = Result<(Cursor<'a>, O), Reject>; + +fn skip_whitespace(input: Cursor) -> Cursor { + let mut s = input; + + while !s.is_empty() { + let byte = s.as_bytes()[0]; + if byte == b'/' { + if s.starts_with("//") + && (!s.starts_with("///") || s.starts_with("////")) + && !s.starts_with("//!") + { + let (cursor, _) = take_until_newline_or_eof(s); + s = cursor; + continue; + } else if s.starts_with("/**/") { + s = s.advance(4); + continue; + } else if s.starts_with("/*") + && (!s.starts_with("/**") || s.starts_with("/***")) + && !s.starts_with("/*!") + { + match block_comment(s) { + Ok((rest, _)) => { + s = rest; + continue; + } + Err(Reject) => return s, + } + } + } + match byte { + b' ' | 0x09..=0x0d => { + s = s.advance(1); + continue; + } + b if b.is_ascii() => {} + _ => { + let ch = s.chars().next().unwrap(); + if is_whitespace(ch) { + s = s.advance(ch.len_utf8()); + continue; + } + } + } + return s; + } + s +} + +fn block_comment(input: Cursor) -> PResult<&str> { + if !input.starts_with("/*") { + return Err(Reject); + } + + let mut depth = 0usize; + let bytes = input.as_bytes(); + let mut i = 0usize; + let upper = bytes.len() - 1; + + while i < upper { + if bytes[i] == b'/' && bytes[i + 1] == b'*' { + depth += 1; + i += 1; // eat '*' + } else if bytes[i] == b'*' && bytes[i + 1] == b'/' { + depth -= 1; + if depth == 0 { + return Ok((input.advance(i + 2), &input.rest[..i + 2])); + } + i += 1; // eat '/' + } + i += 1; + } + + Err(Reject) +} + +fn is_whitespace(ch: char) -> bool { + // Rust treats left-to-right mark and right-to-left mark as whitespace + ch.is_whitespace() || ch == '\u{200e}' || ch == '\u{200f}' +} + +fn word_break(input: Cursor) -> Result { + match input.chars().next() { + Some(ch) if is_ident_continue(ch) => Err(Reject), + Some(_) | None => Ok(input), + } +} + +// Rustc's representation of a macro expansion error in expression position or +// type position. +const ERROR: &str = "(/*ERROR*/)"; + +pub(crate) fn token_stream(mut input: Cursor) -> Result { + let mut tokens = TokenStreamBuilder::new(); + let mut stack = Vec::new(); + + loop { + input = skip_whitespace(input); + + if let Ok((rest, ())) = doc_comment(input, &mut tokens) { + input = rest; + continue; + } + + #[cfg(span_locations)] + let lo = input.off; + + let Some(first) = input.bytes().next() else { + return match stack.last() { + None => Ok(tokens.build()), + #[cfg(span_locations)] + Some((lo, _frame)) => Err(LexError { + span: Span { lo: *lo, hi: *lo }, + }), + #[cfg(not(span_locations))] + Some(_frame) => Err(LexError { span: Span {} }), + }; + }; + + if let Some(open_delimiter) = match first { + b'(' if !input.starts_with(ERROR) => Some(Delimiter::Parenthesis), + b'[' => Some(Delimiter::Bracket), + b'{' => Some(Delimiter::Brace), + _ => None, + } { + input = input.advance(1); + let frame = (open_delimiter, tokens); + #[cfg(span_locations)] + let frame = (lo, frame); + stack.push(frame); + tokens = TokenStreamBuilder::new(); + } else if let Some(close_delimiter) = match first { + b')' => Some(Delimiter::Parenthesis), + b']' => Some(Delimiter::Bracket), + b'}' => Some(Delimiter::Brace), + _ => None, + } { + let Some(frame) = stack.pop() else { + return Err(lex_error(input)); + }; + #[cfg(span_locations)] + let (lo, frame) = frame; + let (open_delimiter, outer) = frame; + if open_delimiter != close_delimiter { + return Err(lex_error(input)); + } + input = input.advance(1); + let mut g = Group::new(open_delimiter, tokens.build()); + g.set_span(Span { + #[cfg(span_locations)] + lo, + #[cfg(span_locations)] + hi: input.off, + }); + tokens = outer; + tokens.push_token_from_parser(TokenTree::Group(crate::Group::_new_fallback(g))); + } else { + let (rest, mut tt) = match leaf_token(input) { + Ok((rest, tt)) => (rest, tt), + Err(Reject) => return Err(lex_error(input)), + }; + tt.set_span(crate::Span::_new_fallback(Span { + #[cfg(span_locations)] + lo, + #[cfg(span_locations)] + hi: rest.off, + })); + tokens.push_token_from_parser(tt); + input = rest; + } + } +} + +fn lex_error(cursor: Cursor) -> LexError { + #[cfg(not(span_locations))] + let _ = cursor; + LexError { + span: Span { + #[cfg(span_locations)] + lo: cursor.off, + #[cfg(span_locations)] + hi: cursor.off, + }, + } +} + +fn leaf_token(input: Cursor) -> PResult { + if let Ok((input, l)) = literal(input) { + // must be parsed before ident + Ok((input, TokenTree::Literal(crate::Literal::_new_fallback(l)))) + } else if let Ok((input, p)) = punct(input) { + Ok((input, TokenTree::Punct(p))) + } else if let Ok((input, i)) = ident(input) { + Ok((input, TokenTree::Ident(i))) + } else if input.starts_with(ERROR) { + let rest = input.advance(ERROR.len()); + let repr = crate::Literal::_new_fallback(Literal::_new(ERROR.to_owned())); + Ok((rest, TokenTree::Literal(repr))) + } else { + Err(Reject) + } +} + +fn ident(input: Cursor) -> PResult { + if [ + "r\"", "r#\"", "r##", "b\"", "b\'", "br\"", "br#", "c\"", "cr\"", "cr#", + ] + .iter() + .any(|prefix| input.starts_with(prefix)) + { + Err(Reject) + } else { + ident_any(input) + } +} + +fn ident_any(input: Cursor) -> PResult { + let raw = input.starts_with("r#"); + let rest = input.advance((raw as usize) << 1); + + let (rest, sym) = ident_not_raw(rest)?; + + if !raw { + let ident = + crate::Ident::_new_fallback(Ident::new_unchecked(sym, fallback::Span::call_site())); + return Ok((rest, ident)); + } + + match sym { + "_" | "super" | "self" | "Self" | "crate" => return Err(Reject), + _ => {} + } + + let ident = + crate::Ident::_new_fallback(Ident::new_raw_unchecked(sym, fallback::Span::call_site())); + Ok((rest, ident)) +} + +fn ident_not_raw(input: Cursor) -> PResult<&str> { + let mut chars = input.char_indices(); + + match chars.next() { + Some((_, ch)) if is_ident_start(ch) => {} + _ => return Err(Reject), + } + + let mut end = input.len(); + for (i, ch) in chars { + if !is_ident_continue(ch) { + end = i; + break; + } + } + + Ok((input.advance(end), &input.rest[..end])) +} + +pub(crate) fn literal(input: Cursor) -> PResult { + let rest = literal_nocapture(input)?; + let end = input.len() - rest.len(); + Ok((rest, Literal::_new(input.rest[..end].to_string()))) +} + +fn literal_nocapture(input: Cursor) -> Result { + if let Ok(ok) = string(input) { + Ok(ok) + } else if let Ok(ok) = byte_string(input) { + Ok(ok) + } else if let Ok(ok) = c_string(input) { + Ok(ok) + } else if let Ok(ok) = byte(input) { + Ok(ok) + } else if let Ok(ok) = character(input) { + Ok(ok) + } else if let Ok(ok) = float(input) { + Ok(ok) + } else if let Ok(ok) = int(input) { + Ok(ok) + } else { + Err(Reject) + } +} + +fn literal_suffix(input: Cursor) -> Cursor { + match ident_not_raw(input) { + Ok((input, _)) => input, + Err(Reject) => input, + } +} + +fn string(input: Cursor) -> Result { + if let Ok(input) = input.parse("\"") { + cooked_string(input) + } else if let Ok(input) = input.parse("r") { + raw_string(input) + } else { + Err(Reject) + } +} + +fn cooked_string(mut input: Cursor) -> Result { + let mut chars = input.char_indices(); + + while let Some((i, ch)) = chars.next() { + match ch { + '"' => { + let input = input.advance(i + 1); + return Ok(literal_suffix(input)); + } + '\r' => match chars.next() { + Some((_, '\n')) => {} + _ => break, + }, + '\\' => match chars.next() { + Some((_, 'x')) => { + backslash_x_char(&mut chars)?; + } + Some((_, 'n' | 'r' | 't' | '\\' | '\'' | '"' | '0')) => {} + Some((_, 'u')) => { + backslash_u(&mut chars)?; + } + Some((newline, ch @ ('\n' | '\r'))) => { + input = input.advance(newline + 1); + trailing_backslash(&mut input, ch as u8)?; + chars = input.char_indices(); + } + _ => break, + }, + _ch => {} + } + } + Err(Reject) +} + +fn raw_string(input: Cursor) -> Result { + let (input, delimiter) = delimiter_of_raw_string(input)?; + let mut bytes = input.bytes().enumerate(); + while let Some((i, byte)) = bytes.next() { + match byte { + b'"' if input.rest[i + 1..].starts_with(delimiter) => { + let rest = input.advance(i + 1 + delimiter.len()); + return Ok(literal_suffix(rest)); + } + b'\r' => match bytes.next() { + Some((_, b'\n')) => {} + _ => break, + }, + _ => {} + } + } + Err(Reject) +} + +fn byte_string(input: Cursor) -> Result { + if let Ok(input) = input.parse("b\"") { + cooked_byte_string(input) + } else if let Ok(input) = input.parse("br") { + raw_byte_string(input) + } else { + Err(Reject) + } +} + +fn cooked_byte_string(mut input: Cursor) -> Result { + let mut bytes = input.bytes().enumerate(); + while let Some((offset, b)) = bytes.next() { + match b { + b'"' => { + let input = input.advance(offset + 1); + return Ok(literal_suffix(input)); + } + b'\r' => match bytes.next() { + Some((_, b'\n')) => {} + _ => break, + }, + b'\\' => match bytes.next() { + Some((_, b'x')) => { + backslash_x_byte(&mut bytes)?; + } + Some((_, b'n' | b'r' | b't' | b'\\' | b'0' | b'\'' | b'"')) => {} + Some((newline, b @ (b'\n' | b'\r'))) => { + input = input.advance(newline + 1); + trailing_backslash(&mut input, b)?; + bytes = input.bytes().enumerate(); + } + _ => break, + }, + b if b.is_ascii() => {} + _ => break, + } + } + Err(Reject) +} + +fn delimiter_of_raw_string(input: Cursor) -> PResult<&str> { + for (i, byte) in input.bytes().enumerate() { + match byte { + b'"' => { + if i > 255 { + // https://github.com/rust-lang/rust/pull/95251 + return Err(Reject); + } + return Ok((input.advance(i + 1), &input.rest[..i])); + } + b'#' => {} + _ => break, + } + } + Err(Reject) +} + +fn raw_byte_string(input: Cursor) -> Result { + let (input, delimiter) = delimiter_of_raw_string(input)?; + let mut bytes = input.bytes().enumerate(); + while let Some((i, byte)) = bytes.next() { + match byte { + b'"' if input.rest[i + 1..].starts_with(delimiter) => { + let rest = input.advance(i + 1 + delimiter.len()); + return Ok(literal_suffix(rest)); + } + b'\r' => match bytes.next() { + Some((_, b'\n')) => {} + _ => break, + }, + other => { + if !other.is_ascii() { + break; + } + } + } + } + Err(Reject) +} + +fn c_string(input: Cursor) -> Result { + if let Ok(input) = input.parse("c\"") { + cooked_c_string(input) + } else if let Ok(input) = input.parse("cr") { + raw_c_string(input) + } else { + Err(Reject) + } +} + +fn raw_c_string(input: Cursor) -> Result { + let (input, delimiter) = delimiter_of_raw_string(input)?; + let mut bytes = input.bytes().enumerate(); + while let Some((i, byte)) = bytes.next() { + match byte { + b'"' if input.rest[i + 1..].starts_with(delimiter) => { + let rest = input.advance(i + 1 + delimiter.len()); + return Ok(literal_suffix(rest)); + } + b'\r' => match bytes.next() { + Some((_, b'\n')) => {} + _ => break, + }, + b'\0' => break, + _ => {} + } + } + Err(Reject) +} + +fn cooked_c_string(mut input: Cursor) -> Result { + let mut chars = input.char_indices(); + + while let Some((i, ch)) = chars.next() { + match ch { + '"' => { + let input = input.advance(i + 1); + return Ok(literal_suffix(input)); + } + '\r' => match chars.next() { + Some((_, '\n')) => {} + _ => break, + }, + '\\' => match chars.next() { + Some((_, 'x')) => { + backslash_x_nonzero(&mut chars)?; + } + Some((_, 'n' | 'r' | 't' | '\\' | '\'' | '"')) => {} + Some((_, 'u')) => { + if backslash_u(&mut chars)? == '\0' { + break; + } + } + Some((newline, ch @ ('\n' | '\r'))) => { + input = input.advance(newline + 1); + trailing_backslash(&mut input, ch as u8)?; + chars = input.char_indices(); + } + _ => break, + }, + '\0' => break, + _ch => {} + } + } + Err(Reject) +} + +fn byte(input: Cursor) -> Result { + let input = input.parse("b'")?; + let mut bytes = input.bytes().enumerate(); + let ok = match bytes.next().map(|(_, b)| b) { + Some(b'\\') => match bytes.next().map(|(_, b)| b) { + Some(b'x') => backslash_x_byte(&mut bytes).is_ok(), + Some(b'n' | b'r' | b't' | b'\\' | b'0' | b'\'' | b'"') => true, + _ => false, + }, + b => b.is_some(), + }; + if !ok { + return Err(Reject); + } + let (offset, _) = bytes.next().ok_or(Reject)?; + if !input.chars().as_str().is_char_boundary(offset) { + return Err(Reject); + } + let input = input.advance(offset).parse("'")?; + Ok(literal_suffix(input)) +} + +fn character(input: Cursor) -> Result { + let input = input.parse("'")?; + let mut chars = input.char_indices(); + let ok = match chars.next().map(|(_, ch)| ch) { + Some('\\') => match chars.next().map(|(_, ch)| ch) { + Some('x') => backslash_x_char(&mut chars).is_ok(), + Some('u') => backslash_u(&mut chars).is_ok(), + Some('n' | 'r' | 't' | '\\' | '0' | '\'' | '"') => true, + _ => false, + }, + ch => ch.is_some(), + }; + if !ok { + return Err(Reject); + } + let (idx, _) = chars.next().ok_or(Reject)?; + let input = input.advance(idx).parse("'")?; + Ok(literal_suffix(input)) +} + +macro_rules! next_ch { + ($chars:ident @ $pat:pat) => { + match $chars.next() { + Some((_, ch)) => match ch { + $pat => ch, + _ => return Err(Reject), + }, + None => return Err(Reject), + } + }; +} + +fn backslash_x_char(chars: &mut I) -> Result<(), Reject> +where + I: Iterator, +{ + next_ch!(chars @ '0'..='7'); + next_ch!(chars @ '0'..='9' | 'a'..='f' | 'A'..='F'); + Ok(()) +} + +fn backslash_x_byte(chars: &mut I) -> Result<(), Reject> +where + I: Iterator, +{ + next_ch!(chars @ b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F'); + next_ch!(chars @ b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F'); + Ok(()) +} + +fn backslash_x_nonzero(chars: &mut I) -> Result<(), Reject> +where + I: Iterator, +{ + let first = next_ch!(chars @ '0'..='9' | 'a'..='f' | 'A'..='F'); + let second = next_ch!(chars @ '0'..='9' | 'a'..='f' | 'A'..='F'); + if first == '0' && second == '0' { + Err(Reject) + } else { + Ok(()) + } +} + +fn backslash_u(chars: &mut I) -> Result +where + I: Iterator, +{ + next_ch!(chars @ '{'); + let mut value = 0; + let mut len = 0; + for (_, ch) in chars { + let digit = match ch { + '0'..='9' => ch as u8 - b'0', + 'a'..='f' => 10 + ch as u8 - b'a', + 'A'..='F' => 10 + ch as u8 - b'A', + '_' if len > 0 => continue, + '}' if len > 0 => return char::from_u32(value).ok_or(Reject), + _ => break, + }; + if len == 6 { + break; + } + value *= 0x10; + value += u32::from(digit); + len += 1; + } + Err(Reject) +} + +fn trailing_backslash(input: &mut Cursor, mut last: u8) -> Result<(), Reject> { + let mut whitespace = input.bytes().enumerate(); + loop { + if last == b'\r' && whitespace.next().map_or(true, |(_, b)| b != b'\n') { + return Err(Reject); + } + match whitespace.next() { + Some((_, b @ (b' ' | b'\t' | b'\n' | b'\r'))) => { + last = b; + } + Some((offset, _)) => { + *input = input.advance(offset); + return Ok(()); + } + None => return Err(Reject), + } + } +} + +fn float(input: Cursor) -> Result { + let mut rest = float_digits(input)?; + if let Some(ch) = rest.chars().next() { + if is_ident_start(ch) { + rest = ident_not_raw(rest)?.0; + } + } + word_break(rest) +} + +fn float_digits(input: Cursor) -> Result { + let mut chars = input.chars().peekable(); + match chars.next() { + Some(ch) if '0' <= ch && ch <= '9' => {} + _ => return Err(Reject), + } + + let mut len = 1; + let mut has_dot = false; + let mut has_exp = false; + while let Some(&ch) = chars.peek() { + match ch { + '0'..='9' | '_' => { + chars.next(); + len += 1; + } + '.' => { + if has_dot { + break; + } + chars.next(); + if chars + .peek() + .is_some_and(|&ch| ch == '.' || is_ident_start(ch)) + { + return Err(Reject); + } + len += 1; + has_dot = true; + } + 'e' | 'E' => { + chars.next(); + len += 1; + has_exp = true; + break; + } + _ => break, + } + } + + if !(has_dot || has_exp) { + return Err(Reject); + } + + if has_exp { + let token_before_exp = if has_dot { + Ok(input.advance(len - 1)) + } else { + Err(Reject) + }; + let mut has_sign = false; + let mut has_exp_value = false; + while let Some(&ch) = chars.peek() { + match ch { + '+' | '-' => { + if has_exp_value { + break; + } + if has_sign { + return token_before_exp; + } + chars.next(); + len += 1; + has_sign = true; + } + '0'..='9' => { + chars.next(); + len += 1; + has_exp_value = true; + } + '_' => { + chars.next(); + len += 1; + } + _ => break, + } + } + if !has_exp_value { + return token_before_exp; + } + } + + Ok(input.advance(len)) +} + +fn int(input: Cursor) -> Result { + let mut rest = digits(input)?; + if let Some(ch) = rest.chars().next() { + if is_ident_start(ch) { + rest = ident_not_raw(rest)?.0; + } + } + word_break(rest) +} + +fn digits(mut input: Cursor) -> Result { + let base = if input.starts_with("0x") { + input = input.advance(2); + 16 + } else if input.starts_with("0o") { + input = input.advance(2); + 8 + } else if input.starts_with("0b") { + input = input.advance(2); + 2 + } else { + 10 + }; + + let mut len = 0; + let mut empty = true; + for b in input.bytes() { + match b { + b'0'..=b'9' => { + let digit = (b - b'0') as u64; + if digit >= base { + return Err(Reject); + } + } + b'a'..=b'f' => { + let digit = 10 + (b - b'a') as u64; + if digit >= base { + break; + } + } + b'A'..=b'F' => { + let digit = 10 + (b - b'A') as u64; + if digit >= base { + break; + } + } + b'_' => { + if empty && base == 10 { + return Err(Reject); + } + len += 1; + continue; + } + _ => break, + } + len += 1; + empty = false; + } + if empty { + Err(Reject) + } else { + Ok(input.advance(len)) + } +} + +fn punct(input: Cursor) -> PResult { + let (rest, ch) = punct_char(input)?; + if ch == '\'' { + let (after_lifetime, _ident) = ident_any(rest)?; + if after_lifetime.starts_with_char('\'') + || (after_lifetime.starts_with_char('#') && !rest.starts_with("r#")) + { + Err(Reject) + } else { + Ok((rest, Punct::new('\'', Spacing::Joint))) + } + } else { + let kind = match punct_char(rest) { + Ok(_) => Spacing::Joint, + Err(Reject) => Spacing::Alone, + }; + Ok((rest, Punct::new(ch, kind))) + } +} + +fn punct_char(input: Cursor) -> PResult { + if input.starts_with("//") || input.starts_with("/*") { + // Do not accept `/` of a comment as a punct. + return Err(Reject); + } + + let mut chars = input.chars(); + let Some(first) = chars.next() else { + return Err(Reject); + }; + let recognized = "~!@#$%^&*-=+|;:,<.>/?'"; + if recognized.contains(first) { + Ok((input.advance(first.len_utf8()), first)) + } else { + Err(Reject) + } +} + +fn doc_comment<'a>(input: Cursor<'a>, tokens: &mut TokenStreamBuilder) -> PResult<'a, ()> { + #[cfg(span_locations)] + let lo = input.off; + let (rest, (comment, inner)) = doc_comment_contents(input)?; + let fallback_span = Span { + #[cfg(span_locations)] + lo, + #[cfg(span_locations)] + hi: rest.off, + }; + let span = crate::Span::_new_fallback(fallback_span); + + let mut scan_for_bare_cr = comment; + while let Some(cr) = scan_for_bare_cr.find('\r') { + let rest = &scan_for_bare_cr[cr + 1..]; + if !rest.starts_with('\n') { + return Err(Reject); + } + scan_for_bare_cr = rest; + } + + let mut pound = Punct::new('#', Spacing::Alone); + pound.set_span(span); + tokens.push_token_from_parser(TokenTree::Punct(pound)); + + if inner { + let mut bang = Punct::new('!', Spacing::Alone); + bang.set_span(span); + tokens.push_token_from_parser(TokenTree::Punct(bang)); + } + + let doc_ident = crate::Ident::_new_fallback(Ident::new_unchecked("doc", fallback_span)); + let mut equal = Punct::new('=', Spacing::Alone); + equal.set_span(span); + let mut literal = crate::Literal::_new_fallback(Literal::string(comment)); + literal.set_span(span); + let mut bracketed = TokenStreamBuilder::with_capacity(3); + bracketed.push_token_from_parser(TokenTree::Ident(doc_ident)); + bracketed.push_token_from_parser(TokenTree::Punct(equal)); + bracketed.push_token_from_parser(TokenTree::Literal(literal)); + let group = Group::new(Delimiter::Bracket, bracketed.build()); + let mut group = crate::Group::_new_fallback(group); + group.set_span(span); + tokens.push_token_from_parser(TokenTree::Group(group)); + + Ok((rest, ())) +} + +fn doc_comment_contents(input: Cursor) -> PResult<(&str, bool)> { + if input.starts_with("//!") { + let input = input.advance(3); + let (input, s) = take_until_newline_or_eof(input); + Ok((input, (s, true))) + } else if input.starts_with("/*!") { + let (input, s) = block_comment(input)?; + Ok((input, (&s[3..s.len() - 2], true))) + } else if input.starts_with("///") { + let input = input.advance(3); + if input.starts_with_char('/') { + return Err(Reject); + } + let (input, s) = take_until_newline_or_eof(input); + Ok((input, (s, false))) + } else if input.starts_with("/**") && !input.rest[3..].starts_with('*') { + let (input, s) = block_comment(input)?; + Ok((input, (&s[3..s.len() - 2], false))) + } else { + Err(Reject) + } +} + +fn take_until_newline_or_eof(input: Cursor) -> (Cursor, &str) { + let chars = input.char_indices(); + + for (i, ch) in chars { + if ch == '\n' { + return (input.advance(i), &input.rest[..i]); + } else if ch == '\r' && input.rest[i + 1..].starts_with('\n') { + return (input.advance(i + 1), &input.rest[..i]); + } + } + + (input.advance(input.len()), input.rest) +} diff --git a/third_party/crates/proc-macro2-1.0.107/src/probe.rs b/third_party/crates/proc-macro2-1.0.107/src/probe.rs new file mode 100644 index 0000000..b67f520 --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/src/probe.rs @@ -0,0 +1,10 @@ +#![allow(dead_code)] + +#[cfg(proc_macro_span)] +pub(crate) mod proc_macro_span; + +#[cfg(proc_macro_span_file)] +pub(crate) mod proc_macro_span_file; + +#[cfg(proc_macro_span_location)] +pub(crate) mod proc_macro_span_location; diff --git a/third_party/crates/proc-macro2-1.0.107/src/probe/proc_macro_span.rs b/third_party/crates/proc-macro2-1.0.107/src/probe/proc_macro_span.rs new file mode 100644 index 0000000..0a8137b --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/src/probe/proc_macro_span.rs @@ -0,0 +1,55 @@ +// This code exercises the surface area that we expect of Span's unstable API. +// If the current toolchain is able to compile it, then proc-macro2 is able to +// offer these APIs too. + +#![cfg_attr(procmacro2_build_probe, no_std)] +#![cfg_attr(procmacro2_build_probe, feature(proc_macro_span))] + +extern crate alloc; +extern crate proc_macro; +extern crate std; + +use alloc::string::String; +use core::ops::{Range, RangeBounds}; +use proc_macro::{Literal, Span}; +use std::path::PathBuf; + +pub fn byte_range(this: &Span) -> Range { + this.byte_range() +} + +pub fn start(this: &Span) -> Span { + this.start() +} + +pub fn end(this: &Span) -> Span { + this.end() +} + +pub fn line(this: &Span) -> usize { + this.line() +} + +pub fn column(this: &Span) -> usize { + this.column() +} + +pub fn file(this: &Span) -> String { + this.file() +} + +pub fn local_file(this: &Span) -> Option { + this.local_file() +} + +pub fn join(this: &Span, other: Span) -> Option { + this.join(other) +} + +pub fn subspan>(this: &Literal, range: R) -> Option { + this.subspan(range) +} + +// Include in sccache cache key. +#[cfg(procmacro2_build_probe)] +const _: Option<&str> = option_env!("RUSTC_BOOTSTRAP"); diff --git a/third_party/crates/proc-macro2-1.0.107/src/probe/proc_macro_span_file.rs b/third_party/crates/proc-macro2-1.0.107/src/probe/proc_macro_span_file.rs new file mode 100644 index 0000000..56ba9d5 --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/src/probe/proc_macro_span_file.rs @@ -0,0 +1,19 @@ +// The subset of Span's API stabilized in Rust 1.88. + +#![cfg_attr(procmacro2_build_probe, no_std)] + +extern crate alloc; +extern crate proc_macro; +extern crate std; + +use alloc::string::String; +use proc_macro::Span; +use std::path::PathBuf; + +pub fn file(this: &Span) -> String { + this.file() +} + +pub fn local_file(this: &Span) -> Option { + this.local_file() +} diff --git a/third_party/crates/proc-macro2-1.0.107/src/probe/proc_macro_span_location.rs b/third_party/crates/proc-macro2-1.0.107/src/probe/proc_macro_span_location.rs new file mode 100644 index 0000000..18ab278 --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/src/probe/proc_macro_span_location.rs @@ -0,0 +1,25 @@ +// The subset of Span's API stabilized in Rust 1.88. + +#![cfg_attr(procmacro2_build_probe, no_std)] + +extern crate alloc; +extern crate proc_macro; +extern crate std; + +use proc_macro::Span; + +pub fn start(this: &Span) -> Span { + this.start() +} + +pub fn end(this: &Span) -> Span { + this.end() +} + +pub fn line(this: &Span) -> usize { + this.line() +} + +pub fn column(this: &Span) -> usize { + this.column() +} diff --git a/third_party/crates/proc-macro2-1.0.107/src/rcvec.rs b/third_party/crates/proc-macro2-1.0.107/src/rcvec.rs new file mode 100644 index 0000000..8d49526 --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/src/rcvec.rs @@ -0,0 +1,146 @@ +use alloc::rc::Rc; +use alloc::vec::{self, Vec}; +use core::mem; +use core::panic::RefUnwindSafe; +use core::slice; + +pub(crate) struct RcVec { + inner: Rc>, +} + +pub(crate) struct RcVecBuilder { + inner: Vec, +} + +pub(crate) struct RcVecMut<'a, T> { + inner: &'a mut Vec, +} + +#[derive(Clone)] +pub(crate) struct RcVecIntoIter { + inner: vec::IntoIter, +} + +impl RcVec { + pub(crate) fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + pub(crate) fn len(&self) -> usize { + self.inner.len() + } + + pub(crate) fn iter(&self) -> slice::Iter { + self.inner.iter() + } + + pub(crate) fn make_mut(&mut self) -> RcVecMut + where + T: Clone, + { + RcVecMut { + inner: Rc::make_mut(&mut self.inner), + } + } + + pub(crate) fn get_mut(&mut self) -> Option> { + let inner = Rc::get_mut(&mut self.inner)?; + Some(RcVecMut { inner }) + } + + pub(crate) fn make_owned(mut self) -> RcVecBuilder + where + T: Clone, + { + let vec = if let Some(owned) = Rc::get_mut(&mut self.inner) { + mem::take(owned) + } else { + Vec::clone(&self.inner) + }; + RcVecBuilder { inner: vec } + } +} + +impl RcVecBuilder { + pub(crate) fn new() -> Self { + RcVecBuilder { inner: Vec::new() } + } + + pub(crate) fn with_capacity(cap: usize) -> Self { + RcVecBuilder { + inner: Vec::with_capacity(cap), + } + } + + pub(crate) fn push(&mut self, element: T) { + self.inner.push(element); + } + + pub(crate) fn extend(&mut self, iter: impl IntoIterator) { + self.inner.extend(iter); + } + + pub(crate) fn as_mut(&mut self) -> RcVecMut { + RcVecMut { + inner: &mut self.inner, + } + } + + pub(crate) fn build(self) -> RcVec { + RcVec { + inner: Rc::new(self.inner), + } + } +} + +impl<'a, T> RcVecMut<'a, T> { + pub(crate) fn push(&mut self, element: T) { + self.inner.push(element); + } + + pub(crate) fn extend(&mut self, iter: impl IntoIterator) { + self.inner.extend(iter); + } + + pub(crate) fn as_mut(&mut self) -> RcVecMut { + RcVecMut { inner: self.inner } + } + + pub(crate) fn take(self) -> RcVecBuilder { + let vec = mem::take(self.inner); + RcVecBuilder { inner: vec } + } +} + +impl Clone for RcVec { + fn clone(&self) -> Self { + RcVec { + inner: Rc::clone(&self.inner), + } + } +} + +impl IntoIterator for RcVecBuilder { + type Item = T; + type IntoIter = RcVecIntoIter; + + fn into_iter(self) -> Self::IntoIter { + RcVecIntoIter { + inner: self.inner.into_iter(), + } + } +} + +impl Iterator for RcVecIntoIter { + type Item = T; + + fn next(&mut self) -> Option { + self.inner.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +impl RefUnwindSafe for RcVec where T: RefUnwindSafe {} diff --git a/third_party/crates/proc-macro2-1.0.107/src/rustc_literal_escaper.rs b/third_party/crates/proc-macro2-1.0.107/src/rustc_literal_escaper.rs new file mode 100644 index 0000000..66b4c3b --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/src/rustc_literal_escaper.rs @@ -0,0 +1,701 @@ +// Vendored from rustc-literal-escaper v0.0.5 +// https://github.com/rust-lang/literal-escaper/tree/v0.0.5 + +//! Utilities for validating (raw) string, char, and byte literals and +//! turning escape sequences into the values they represent. + +use crate::num::NonZeroChar; +use core::ffi::CStr; +use core::num::NonZeroU8; +use core::ops::Range; +use core::str::Chars; + +/// Errors and warnings that can occur during string, char, and byte unescaping. +/// +/// Mostly relating to malformed escape sequences, but also a few other problems. +#[derive(Debug, PartialEq, Eq)] +pub enum EscapeError { + /// Expected 1 char, but 0 were found. + ZeroChars, + /// Expected 1 char, but more than 1 were found. + MoreThanOneChar, + + /// Escaped '\' character without continuation. + LoneSlash, + /// Invalid escape character (e.g. '\z'). + InvalidEscape, + /// Raw '\r' encountered. + BareCarriageReturn, + /// Raw '\r' encountered in raw string. + BareCarriageReturnInRawString, + /// Unescaped character that was expected to be escaped (e.g. raw '\t'). + EscapeOnlyChar, + + /// Numeric character escape is too short (e.g. '\x1'). + TooShortHexEscape, + /// Invalid character in numeric escape (e.g. '\xz') + InvalidCharInHexEscape, + /// Character code in numeric escape is non-ascii (e.g. '\xFF'). + OutOfRangeHexEscape, + + /// '\u' not followed by '{'. + NoBraceInUnicodeEscape, + /// Non-hexadecimal value in '\u{..}'. + InvalidCharInUnicodeEscape, + /// '\u{}' + EmptyUnicodeEscape, + /// No closing brace in '\u{..}', e.g. '\u{12'. + UnclosedUnicodeEscape, + /// '\u{_12}' + LeadingUnderscoreUnicodeEscape, + /// More than 6 characters in '\u{..}', e.g. '\u{10FFFF_FF}' + OverlongUnicodeEscape, + /// Invalid in-bound unicode character code, e.g. '\u{DFFF}'. + LoneSurrogateUnicodeEscape, + /// Out of bounds unicode character code, e.g. '\u{FFFFFF}'. + OutOfRangeUnicodeEscape, + + /// Unicode escape code in byte literal. + UnicodeEscapeInByte, + /// Non-ascii character in byte literal, byte string literal, or raw byte string literal. + NonAsciiCharInByte, + + /// `\0` in a C string literal. + NulInCStr, + + /// After a line ending with '\', the next line contains whitespace + /// characters that are not skipped. + UnskippedWhitespaceWarning, + + /// After a line ending with '\', multiple lines are skipped. + MultipleSkippedLinesWarning, +} + +impl EscapeError { + /// Returns true for actual errors, as opposed to warnings. + pub fn is_fatal(&self) -> bool { + !matches!( + self, + EscapeError::UnskippedWhitespaceWarning | EscapeError::MultipleSkippedLinesWarning + ) + } +} + +/// Check a raw string literal for validity +/// +/// Takes the contents of a raw string literal (without quotes) +/// and produces a sequence of characters or errors, +/// which are returned by invoking `callback`. +/// NOTE: Does no escaping, but produces errors for bare carriage return ('\r'). +pub fn check_raw_str(src: &str, callback: impl FnMut(Range, Result)) { + str::check_raw(src, callback); +} + +/// Check a raw byte string literal for validity +/// +/// Takes the contents of a raw byte string literal (without quotes) +/// and produces a sequence of bytes or errors, +/// which are returned by invoking `callback`. +/// NOTE: Does no escaping, but produces errors for bare carriage return ('\r'). +pub fn check_raw_byte_str(src: &str, callback: impl FnMut(Range, Result)) { + <[u8]>::check_raw(src, callback); +} + +/// Check a raw C string literal for validity +/// +/// Takes the contents of a raw C string literal (without quotes) +/// and produces a sequence of characters or errors, +/// which are returned by invoking `callback`. +/// NOTE: Does no escaping, but produces errors for bare carriage return ('\r'). +pub fn check_raw_c_str( + src: &str, + callback: impl FnMut(Range, Result), +) { + CStr::check_raw(src, callback); +} + +/// Trait for checking raw string literals for validity +trait CheckRaw { + /// Unit type of the implementing string type (`char` for string, `u8` for byte string) + type RawUnit; + + /// Converts chars to the unit type of the literal type + fn char2raw_unit(c: char) -> Result; + + /// Takes the contents of a raw literal (without quotes) + /// and produces a sequence of `Result` + /// which are returned via `callback`. + /// + /// NOTE: Does no escaping, but produces errors for bare carriage return ('\r'). + fn check_raw( + src: &str, + mut callback: impl FnMut(Range, Result), + ) { + let mut chars = src.chars(); + while let Some(c) = chars.next() { + let start = src.len() - chars.as_str().len() - c.len_utf8(); + let res = match c { + '\r' => Err(EscapeError::BareCarriageReturnInRawString), + _ => Self::char2raw_unit(c), + }; + let end = src.len() - chars.as_str().len(); + callback(start..end, res); + } + + // Unfortunately, it is a bit unclear whether the following equivalent code is slower or faster: bug 141855 + // src.char_indices().for_each(|(pos, c)| { + // callback( + // pos..pos + c.len_utf8(), + // if c == '\r' { + // Err(EscapeError::BareCarriageReturnInRawString) + // } else { + // Self::char2raw_unit(c) + // }, + // ); + // }); + } +} + +impl CheckRaw for str { + type RawUnit = char; + + #[inline] + fn char2raw_unit(c: char) -> Result { + Ok(c) + } +} + +impl CheckRaw for [u8] { + type RawUnit = u8; + + #[inline] + fn char2raw_unit(c: char) -> Result { + char2byte(c) + } +} + +/// Turn an ascii char into a byte +#[inline] +fn char2byte(c: char) -> Result { + // do NOT do: c.try_into().ok_or(EscapeError::NonAsciiCharInByte) + if c.is_ascii() { + Ok(c as u8) + } else { + Err(EscapeError::NonAsciiCharInByte) + } +} + +impl CheckRaw for CStr { + type RawUnit = NonZeroChar; + + #[inline] + fn char2raw_unit(c: char) -> Result { + NonZeroChar::new(c).ok_or(EscapeError::NulInCStr) + } +} + +/// Unescape a char literal +/// +/// Takes the contents of a char literal (without quotes), +/// and returns an unescaped char or an error. +#[inline] +pub fn unescape_char(src: &str) -> Result { + str::unescape_single(&mut src.chars()) +} + +/// Unescape a byte literal +/// +/// Takes the contents of a byte literal (without quotes), +/// and returns an unescaped byte or an error. +#[inline] +pub fn unescape_byte(src: &str) -> Result { + <[u8]>::unescape_single(&mut src.chars()) +} + +/// Unescape a string literal +/// +/// Takes the contents of a string literal (without quotes) +/// and produces a sequence of escaped characters or errors, +/// which are returned by invoking `callback`. +pub fn unescape_str(src: &str, callback: impl FnMut(Range, Result)) { + str::unescape(src, callback) +} + +/// Unescape a byte string literal +/// +/// Takes the contents of a byte string literal (without quotes) +/// and produces a sequence of escaped bytes or errors, +/// which are returned by invoking `callback`. +pub fn unescape_byte_str(src: &str, callback: impl FnMut(Range, Result)) { + <[u8]>::unescape(src, callback) +} + +/// Unescape a C string literal +/// +/// Takes the contents of a C string literal (without quotes) +/// and produces a sequence of escaped MixedUnits or errors, +/// which are returned by invoking `callback`. +pub fn unescape_c_str( + src: &str, + callback: impl FnMut(Range, Result), +) { + CStr::unescape(src, callback) +} + +/// Enum representing either a char or a byte +/// +/// Used for mixed utf8 string literals, i.e. those that allow both unicode +/// chars and high bytes. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum MixedUnit { + /// Used for ASCII chars (written directly or via `\x00`..`\x7f` escapes) + /// and Unicode chars (written directly or via `\u` escapes). + /// + /// For example, if '¥' appears in a string it is represented here as + /// `MixedUnit::Char('¥')`, and it will be appended to the relevant byte + /// string as the two-byte UTF-8 sequence `[0xc2, 0xa5]` + Char(NonZeroChar), + + /// Used for high bytes (`\x80`..`\xff`). + /// + /// For example, if `\xa5` appears in a string it is represented here as + /// `MixedUnit::HighByte(0xa5)`, and it will be appended to the relevant + /// byte string as the single byte `0xa5`. + HighByte(NonZeroU8), +} + +impl From for MixedUnit { + #[inline] + fn from(c: NonZeroChar) -> Self { + MixedUnit::Char(c) + } +} + +impl From for MixedUnit { + #[inline] + fn from(byte: NonZeroU8) -> Self { + if byte.get().is_ascii() { + MixedUnit::Char(NonZeroChar::new(byte.get() as char).unwrap()) + } else { + MixedUnit::HighByte(byte) + } + } +} + +impl TryFrom for MixedUnit { + type Error = EscapeError; + + #[inline] + fn try_from(c: char) -> Result { + NonZeroChar::new(c) + .map(MixedUnit::Char) + .ok_or(EscapeError::NulInCStr) + } +} + +impl TryFrom for MixedUnit { + type Error = EscapeError; + + #[inline] + fn try_from(byte: u8) -> Result { + NonZeroU8::new(byte) + .map(From::from) + .ok_or(EscapeError::NulInCStr) + } +} + +/// Trait for unescaping escape sequences in strings +trait Unescape { + /// Unit type of the implementing string type (`char` for string, `u8` for byte string) + type Unit; + + /// Result of unescaping the zero char ('\0') + const ZERO_RESULT: Result; + + /// Converts non-zero bytes to the unit type + fn nonzero_byte2unit(b: NonZeroU8) -> Self::Unit; + + /// Converts chars to the unit type + fn char2unit(c: char) -> Result; + + /// Converts the byte of a hex escape to the unit type + fn hex2unit(b: u8) -> Result; + + /// Converts the result of a unicode escape to the unit type + fn unicode2unit(r: Result) -> Result; + + /// Unescape a single unit (single quote syntax) + fn unescape_single(chars: &mut Chars<'_>) -> Result { + let res = match chars.next().ok_or(EscapeError::ZeroChars)? { + '\\' => Self::unescape_1(chars), + '\n' | '\t' | '\'' => Err(EscapeError::EscapeOnlyChar), + '\r' => Err(EscapeError::BareCarriageReturn), + c => Self::char2unit(c), + }?; + if chars.next().is_some() { + return Err(EscapeError::MoreThanOneChar); + } + Ok(res) + } + + /// Unescape the first unit of a string (double quoted syntax) + fn unescape_1(chars: &mut Chars<'_>) -> Result { + // Previous character was '\\', unescape what follows. + let c = chars.next().ok_or(EscapeError::LoneSlash)?; + if c == '0' { + Self::ZERO_RESULT + } else { + simple_escape(c) + .map(|b| Self::nonzero_byte2unit(b)) + .or_else(|c| match c { + 'x' => Self::hex2unit(hex_escape(chars)?), + 'u' => Self::unicode2unit({ + let value = unicode_escape(chars)?; + if value > char::MAX as u32 { + Err(EscapeError::OutOfRangeUnicodeEscape) + } else { + char::from_u32(value).ok_or(EscapeError::LoneSurrogateUnicodeEscape) + } + }), + _ => Err(EscapeError::InvalidEscape), + }) + } + } + + /// Unescape a string literal + /// + /// Takes the contents of a raw string literal (without quotes) + /// and produces a sequence of `Result` + /// which are returned via `callback`. + fn unescape( + src: &str, + mut callback: impl FnMut(Range, Result), + ) { + let mut chars = src.chars(); + while let Some(c) = chars.next() { + let start = src.len() - chars.as_str().len() - c.len_utf8(); + let res = match c { + '\\' => { + if let Some(b'\n') = chars.as_str().as_bytes().first() { + let _ = chars.next(); + // skip whitespace for backslash newline, see [Rust language reference] + // (https://doc.rust-lang.org/reference/tokens.html#string-literals). + let callback_err = |range, err| callback(range, Err(err)); + skip_ascii_whitespace(&mut chars, start, callback_err); + continue; + } else { + Self::unescape_1(&mut chars) + } + } + '"' => Err(EscapeError::EscapeOnlyChar), + '\r' => Err(EscapeError::BareCarriageReturn), + c => Self::char2unit(c), + }; + let end = src.len() - chars.as_str().len(); + callback(start..end, res); + } + } +} + +/// Interpret a non-nul ASCII escape +/// +/// Parses the character of an ASCII escape (except nul) without the leading backslash. +#[inline] // single use in Unescape::unescape_1 +fn simple_escape(c: char) -> Result { + // Previous character was '\\', unescape what follows. + Ok(NonZeroU8::new(match c { + '"' => b'"', + 'n' => b'\n', + 'r' => b'\r', + 't' => b'\t', + '\\' => b'\\', + '\'' => b'\'', + _ => Err(c)?, + }) + .unwrap()) +} + +/// Interpret a hexadecimal escape +/// +/// Parses the two hexadecimal characters of a hexadecimal escape without the leading r"\x". +#[inline] // single use in Unescape::unescape_1 +fn hex_escape(chars: &mut impl Iterator) -> Result { + let hi = chars.next().ok_or(EscapeError::TooShortHexEscape)?; + let hi = hi.to_digit(16).ok_or(EscapeError::InvalidCharInHexEscape)?; + + let lo = chars.next().ok_or(EscapeError::TooShortHexEscape)?; + let lo = lo.to_digit(16).ok_or(EscapeError::InvalidCharInHexEscape)?; + + Ok((hi * 16 + lo) as u8) +} + +/// Interpret a unicode escape +/// +/// Parse the braces with hexadecimal characters (and underscores) part of a unicode escape. +/// This r"{...}" normally comes after r"\u" and cannot start with an underscore. +#[inline] // single use in Unescape::unescape_1 +fn unicode_escape(chars: &mut impl Iterator) -> Result { + if chars.next() != Some('{') { + return Err(EscapeError::NoBraceInUnicodeEscape); + } + + // First character must be a hexadecimal digit. + let mut value: u32 = match chars.next().ok_or(EscapeError::UnclosedUnicodeEscape)? { + '_' => return Err(EscapeError::LeadingUnderscoreUnicodeEscape), + '}' => return Err(EscapeError::EmptyUnicodeEscape), + c => c + .to_digit(16) + .ok_or(EscapeError::InvalidCharInUnicodeEscape)?, + }; + + // First character is valid, now parse the rest of the number + // and closing brace. + let mut n_digits = 1; + loop { + match chars.next() { + None => return Err(EscapeError::UnclosedUnicodeEscape), + Some('_') => continue, + Some('}') => { + // Incorrect syntax has higher priority for error reporting + // than unallowed value for a literal. + return if n_digits > 6 { + Err(EscapeError::OverlongUnicodeEscape) + } else { + Ok(value) + }; + } + Some(c) => { + let digit: u32 = c + .to_digit(16) + .ok_or(EscapeError::InvalidCharInUnicodeEscape)?; + n_digits += 1; + if n_digits > 6 { + // Stop updating value since we're sure that it's incorrect already. + continue; + } + value = value * 16 + digit; + } + }; + } +} + +/// Interpret a string continuation escape (https://doc.rust-lang.org/reference/expressions/literal-expr.html#string-continuation-escapes) +/// +/// Skip ASCII whitespace, except for the formfeed character +/// (see [this issue](https://github.com/rust-lang/rust/issues/136600)). +/// Warns on unescaped newline and following non-ASCII whitespace. +#[inline] // single use in Unescape::unescape +fn skip_ascii_whitespace( + chars: &mut Chars<'_>, + start: usize, + mut callback: impl FnMut(Range, EscapeError), +) { + let rest = chars.as_str(); + let first_non_space = rest + .bytes() + .position(|b| b != b' ' && b != b'\t' && b != b'\n' && b != b'\r') + .unwrap_or(rest.len()); + let (space, rest) = rest.split_at(first_non_space); + // backslash newline adds 2 bytes + let end = start + 2 + first_non_space; + if space.contains('\n') { + callback(start..end, EscapeError::MultipleSkippedLinesWarning); + } + *chars = rest.chars(); + if let Some(c) = chars.clone().next() { + if c.is_whitespace() { + // for error reporting, include the character that was not skipped in the span + callback( + start..end + c.len_utf8(), + EscapeError::UnskippedWhitespaceWarning, + ); + } + } +} + +impl Unescape for str { + type Unit = char; + + const ZERO_RESULT: Result = Ok('\0'); + + #[inline] + fn nonzero_byte2unit(b: NonZeroU8) -> Self::Unit { + b.get().into() + } + + #[inline] + fn char2unit(c: char) -> Result { + Ok(c) + } + + #[inline] + fn hex2unit(b: u8) -> Result { + if b.is_ascii() { + Ok(b as char) + } else { + Err(EscapeError::OutOfRangeHexEscape) + } + } + + #[inline] + fn unicode2unit(r: Result) -> Result { + r + } +} + +impl Unescape for [u8] { + type Unit = u8; + + const ZERO_RESULT: Result = Ok(b'\0'); + + #[inline] + fn nonzero_byte2unit(b: NonZeroU8) -> Self::Unit { + b.get() + } + + #[inline] + fn char2unit(c: char) -> Result { + char2byte(c) + } + + #[inline] + fn hex2unit(b: u8) -> Result { + Ok(b) + } + + #[inline] + fn unicode2unit(_r: Result) -> Result { + Err(EscapeError::UnicodeEscapeInByte) + } +} + +impl Unescape for CStr { + type Unit = MixedUnit; + + const ZERO_RESULT: Result = Err(EscapeError::NulInCStr); + + #[inline] + fn nonzero_byte2unit(b: NonZeroU8) -> Self::Unit { + b.into() + } + + #[inline] + fn char2unit(c: char) -> Result { + c.try_into() + } + + #[inline] + fn hex2unit(byte: u8) -> Result { + byte.try_into() + } + + #[inline] + fn unicode2unit(r: Result) -> Result { + Self::char2unit(r?) + } +} + +/// Enum of the different kinds of literal +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum Mode { + /// `'a'` + Char, + + /// `b'a'` + Byte, + + /// `"hello"` + Str, + /// `r"hello"` + RawStr, + + /// `b"hello"` + ByteStr, + /// `br"hello"` + RawByteStr, + + /// `c"hello"` + CStr, + /// `cr"hello"` + RawCStr, +} + +impl Mode { + pub fn in_double_quotes(self) -> bool { + match self { + Mode::Str + | Mode::RawStr + | Mode::ByteStr + | Mode::RawByteStr + | Mode::CStr + | Mode::RawCStr => true, + Mode::Char | Mode::Byte => false, + } + } + + pub fn prefix_noraw(self) -> &'static str { + match self { + Mode::Char | Mode::Str | Mode::RawStr => "", + Mode::Byte | Mode::ByteStr | Mode::RawByteStr => "b", + Mode::CStr | Mode::RawCStr => "c", + } + } +} + +/// Check a literal only for errors +/// +/// Takes the contents of a literal (without quotes) +/// and produces a sequence of only errors, +/// which are returned by invoking `error_callback`. +/// +/// NB Does not produce any output other than errors +pub fn check_for_errors( + src: &str, + mode: Mode, + mut error_callback: impl FnMut(Range, EscapeError), +) { + match mode { + Mode::Char => { + let mut chars = src.chars(); + if let Err(e) = str::unescape_single(&mut chars) { + error_callback(0..(src.len() - chars.as_str().len()), e); + } + } + Mode::Byte => { + let mut chars = src.chars(); + if let Err(e) = <[u8]>::unescape_single(&mut chars) { + error_callback(0..(src.len() - chars.as_str().len()), e); + } + } + Mode::Str => unescape_str(src, |range, res| { + if let Err(e) = res { + error_callback(range, e); + } + }), + Mode::ByteStr => unescape_byte_str(src, |range, res| { + if let Err(e) = res { + error_callback(range, e); + } + }), + Mode::CStr => unescape_c_str(src, |range, res| { + if let Err(e) = res { + error_callback(range, e); + } + }), + Mode::RawStr => check_raw_str(src, |range, res| { + if let Err(e) = res { + error_callback(range, e); + } + }), + Mode::RawByteStr => check_raw_byte_str(src, |range, res| { + if let Err(e) = res { + error_callback(range, e); + } + }), + Mode::RawCStr => check_raw_c_str(src, |range, res| { + if let Err(e) = res { + error_callback(range, e); + } + }), + } +} diff --git a/third_party/crates/proc-macro2-1.0.107/src/wrapper.rs b/third_party/crates/proc-macro2-1.0.107/src/wrapper.rs new file mode 100644 index 0000000..6043c16 --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/src/wrapper.rs @@ -0,0 +1,987 @@ +use crate::detection::inside_proc_macro; +use crate::fallback::{self, FromStr2 as _}; +#[cfg(span_locations)] +use crate::location::LineColumn; +#[cfg(proc_macro_span)] +use crate::probe::proc_macro_span; +#[cfg(all(span_locations, proc_macro_span_file))] +use crate::probe::proc_macro_span_file; +#[cfg(all(span_locations, proc_macro_span_location))] +use crate::probe::proc_macro_span_location; +use crate::{Delimiter, Punct, Spacing, TokenTree}; +#[cfg(all(span_locations, not(proc_macro_span_file)))] +use alloc::borrow::ToOwned as _; +use alloc::string::{String, ToString as _}; +use alloc::vec::Vec; +use core::ffi::CStr; +use core::fmt::{self, Debug, Display}; +#[cfg(span_locations)] +use core::ops::Range; +use core::ops::RangeBounds; +#[cfg(span_locations)] +use std::path::PathBuf; + +#[derive(Clone)] +pub(crate) enum TokenStream { + Compiler(DeferredTokenStream), + Fallback(fallback::TokenStream), +} + +// Work around https://github.com/rust-lang/rust/issues/65080. +// In `impl Extend for TokenStream` which is used heavily by quote, +// we hold on to the appended tokens and do proc_macro::TokenStream::extend as +// late as possible to batch together consecutive uses of the Extend impl. +#[derive(Clone)] +pub(crate) struct DeferredTokenStream { + stream: proc_macro::TokenStream, + extra: Vec, +} + +pub(crate) enum LexError { + Compiler(proc_macro::LexError), + Fallback(fallback::LexError), + + // Rustc was supposed to return a LexError, but it panicked instead. + // https://github.com/rust-lang/rust/issues/58736 + CompilerPanic, +} + +#[cold] +fn mismatch(line: u32) -> ! { + #[cfg(procmacro2_backtrace)] + { + let backtrace = std::backtrace::Backtrace::force_capture(); + panic!("compiler/fallback mismatch L{}\n\n{}", line, backtrace) + } + #[cfg(not(procmacro2_backtrace))] + { + panic!("compiler/fallback mismatch L{}", line) + } +} + +impl DeferredTokenStream { + fn new(stream: proc_macro::TokenStream) -> Self { + DeferredTokenStream { + stream, + extra: Vec::new(), + } + } + + fn is_empty(&self) -> bool { + self.stream.is_empty() && self.extra.is_empty() + } + + fn evaluate_now(&mut self) { + // If-check provides a fast short circuit for the common case of `extra` + // being empty, which saves a round trip over the proc macro bridge. + // Improves macro expansion time in winrt by 6% in debug mode. + if !self.extra.is_empty() { + self.stream.extend(self.extra.drain(..)); + } + } + + fn into_token_stream(mut self) -> proc_macro::TokenStream { + self.evaluate_now(); + self.stream + } +} + +impl TokenStream { + pub(crate) fn new() -> Self { + if inside_proc_macro() { + TokenStream::Compiler(DeferredTokenStream::new(proc_macro::TokenStream::new())) + } else { + TokenStream::Fallback(fallback::TokenStream::new()) + } + } + + pub(crate) fn from_str_checked(src: &str) -> Result { + if inside_proc_macro() { + Ok(TokenStream::Compiler(DeferredTokenStream::new( + proc_macro::TokenStream::from_str_checked(src)?, + ))) + } else { + Ok(TokenStream::Fallback( + fallback::TokenStream::from_str_checked(src)?, + )) + } + } + + pub(crate) fn is_empty(&self) -> bool { + match self { + TokenStream::Compiler(tts) => tts.is_empty(), + TokenStream::Fallback(tts) => tts.is_empty(), + } + } + + fn unwrap_nightly(self) -> proc_macro::TokenStream { + match self { + TokenStream::Compiler(s) => s.into_token_stream(), + TokenStream::Fallback(_) => mismatch(line!()), + } + } + + fn unwrap_stable(self) -> fallback::TokenStream { + match self { + TokenStream::Compiler(_) => mismatch(line!()), + TokenStream::Fallback(s) => s, + } + } +} + +impl Display for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + TokenStream::Compiler(tts) => Display::fmt(&tts.clone().into_token_stream(), f), + TokenStream::Fallback(tts) => Display::fmt(tts, f), + } + } +} + +impl From for TokenStream { + fn from(inner: proc_macro::TokenStream) -> Self { + TokenStream::Compiler(DeferredTokenStream::new(inner)) + } +} + +impl From for proc_macro::TokenStream { + fn from(inner: TokenStream) -> Self { + match inner { + TokenStream::Compiler(inner) => inner.into_token_stream(), + TokenStream::Fallback(inner) => { + proc_macro::TokenStream::from_str_unchecked(&inner.to_string()) + } + } + } +} + +impl From for TokenStream { + fn from(inner: fallback::TokenStream) -> Self { + TokenStream::Fallback(inner) + } +} + +// Assumes inside_proc_macro(). +fn into_compiler_token(token: TokenTree) -> proc_macro::TokenTree { + match token { + TokenTree::Group(tt) => proc_macro::TokenTree::Group(tt.inner.unwrap_nightly()), + TokenTree::Punct(tt) => { + let spacing = match tt.spacing() { + Spacing::Joint => proc_macro::Spacing::Joint, + Spacing::Alone => proc_macro::Spacing::Alone, + }; + let mut punct = proc_macro::Punct::new(tt.as_char(), spacing); + punct.set_span(tt.span().inner.unwrap_nightly()); + proc_macro::TokenTree::Punct(punct) + } + TokenTree::Ident(tt) => proc_macro::TokenTree::Ident(tt.inner.unwrap_nightly()), + TokenTree::Literal(tt) => proc_macro::TokenTree::Literal(tt.inner.unwrap_nightly()), + } +} + +impl From for TokenStream { + fn from(token: TokenTree) -> Self { + if inside_proc_macro() { + TokenStream::Compiler(DeferredTokenStream::new(proc_macro::TokenStream::from( + into_compiler_token(token), + ))) + } else { + TokenStream::Fallback(fallback::TokenStream::from(token)) + } + } +} + +impl FromIterator for TokenStream { + fn from_iter>(tokens: I) -> Self { + if inside_proc_macro() { + TokenStream::Compiler(DeferredTokenStream::new( + tokens.into_iter().map(into_compiler_token).collect(), + )) + } else { + TokenStream::Fallback(tokens.into_iter().collect()) + } + } +} + +impl FromIterator for TokenStream { + fn from_iter>(streams: I) -> Self { + let mut streams = streams.into_iter(); + match streams.next() { + Some(TokenStream::Compiler(mut first)) => { + first.evaluate_now(); + first.stream.extend(streams.map(|s| match s { + TokenStream::Compiler(s) => s.into_token_stream(), + TokenStream::Fallback(_) => mismatch(line!()), + })); + TokenStream::Compiler(first) + } + Some(TokenStream::Fallback(mut first)) => { + first.extend(streams.map(|s| match s { + TokenStream::Fallback(s) => s, + TokenStream::Compiler(_) => mismatch(line!()), + })); + TokenStream::Fallback(first) + } + None => TokenStream::new(), + } + } +} + +impl Extend for TokenStream { + fn extend>(&mut self, tokens: I) { + match self { + TokenStream::Compiler(tts) => { + // Here is the reason for DeferredTokenStream. + for token in tokens { + tts.extra.push(into_compiler_token(token)); + } + } + TokenStream::Fallback(tts) => tts.extend(tokens), + } + } +} + +impl Extend for TokenStream { + fn extend>(&mut self, streams: I) { + match self { + TokenStream::Compiler(tts) => { + tts.evaluate_now(); + tts.stream + .extend(streams.into_iter().map(TokenStream::unwrap_nightly)); + } + TokenStream::Fallback(tts) => { + tts.extend(streams.into_iter().map(TokenStream::unwrap_stable)); + } + } + } +} + +impl Debug for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + TokenStream::Compiler(tts) => Debug::fmt(&tts.clone().into_token_stream(), f), + TokenStream::Fallback(tts) => Debug::fmt(tts, f), + } + } +} + +impl LexError { + pub(crate) fn span(&self) -> Span { + match self { + LexError::Compiler(_) | LexError::CompilerPanic => Span::call_site(), + LexError::Fallback(e) => Span::Fallback(e.span()), + } + } +} + +impl From for LexError { + fn from(e: proc_macro::LexError) -> Self { + LexError::Compiler(e) + } +} + +impl From for LexError { + fn from(e: fallback::LexError) -> Self { + LexError::Fallback(e) + } +} + +impl Debug for LexError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + LexError::Compiler(e) => Debug::fmt(e, f), + LexError::Fallback(e) => Debug::fmt(e, f), + LexError::CompilerPanic => { + let fallback = fallback::LexError::call_site(); + Debug::fmt(&fallback, f) + } + } + } +} + +impl Display for LexError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + LexError::Compiler(e) => Display::fmt(e, f), + LexError::Fallback(e) => Display::fmt(e, f), + LexError::CompilerPanic => { + let fallback = fallback::LexError::call_site(); + Display::fmt(&fallback, f) + } + } + } +} + +#[derive(Clone)] +pub(crate) enum TokenTreeIter { + Compiler(proc_macro::token_stream::IntoIter), + Fallback(fallback::TokenTreeIter), +} + +impl IntoIterator for TokenStream { + type Item = TokenTree; + type IntoIter = TokenTreeIter; + + fn into_iter(self) -> TokenTreeIter { + match self { + TokenStream::Compiler(tts) => { + TokenTreeIter::Compiler(tts.into_token_stream().into_iter()) + } + TokenStream::Fallback(tts) => TokenTreeIter::Fallback(tts.into_iter()), + } + } +} + +impl Iterator for TokenTreeIter { + type Item = TokenTree; + + fn next(&mut self) -> Option { + let token = match self { + TokenTreeIter::Compiler(iter) => iter.next()?, + TokenTreeIter::Fallback(iter) => return iter.next(), + }; + Some(match token { + proc_macro::TokenTree::Group(tt) => { + TokenTree::Group(crate::Group::_new(Group::Compiler(tt))) + } + proc_macro::TokenTree::Punct(tt) => { + let spacing = match tt.spacing() { + proc_macro::Spacing::Joint => Spacing::Joint, + proc_macro::Spacing::Alone => Spacing::Alone, + }; + let mut o = Punct::new(tt.as_char(), spacing); + o.set_span(crate::Span::_new(Span::Compiler(tt.span()))); + TokenTree::Punct(o) + } + proc_macro::TokenTree::Ident(s) => { + TokenTree::Ident(crate::Ident::_new(Ident::Compiler(s))) + } + proc_macro::TokenTree::Literal(l) => { + TokenTree::Literal(crate::Literal::_new(Literal::Compiler(l))) + } + }) + } + + fn size_hint(&self) -> (usize, Option) { + match self { + TokenTreeIter::Compiler(tts) => tts.size_hint(), + TokenTreeIter::Fallback(tts) => tts.size_hint(), + } + } +} + +#[derive(Copy, Clone)] +pub(crate) enum Span { + Compiler(proc_macro::Span), + Fallback(fallback::Span), +} + +impl Span { + pub(crate) fn call_site() -> Self { + if inside_proc_macro() { + Span::Compiler(proc_macro::Span::call_site()) + } else { + Span::Fallback(fallback::Span::call_site()) + } + } + + pub(crate) fn mixed_site() -> Self { + if inside_proc_macro() { + Span::Compiler(proc_macro::Span::mixed_site()) + } else { + Span::Fallback(fallback::Span::mixed_site()) + } + } + + #[cfg(super_unstable)] + pub(crate) fn def_site() -> Self { + if inside_proc_macro() { + Span::Compiler(proc_macro::Span::def_site()) + } else { + Span::Fallback(fallback::Span::def_site()) + } + } + + pub(crate) fn resolved_at(&self, other: Span) -> Span { + match (self, other) { + (Span::Compiler(a), Span::Compiler(b)) => Span::Compiler(a.resolved_at(b)), + (Span::Fallback(a), Span::Fallback(b)) => Span::Fallback(a.resolved_at(b)), + (Span::Compiler(_), Span::Fallback(_)) => mismatch(line!()), + (Span::Fallback(_), Span::Compiler(_)) => mismatch(line!()), + } + } + + pub(crate) fn located_at(&self, other: Span) -> Span { + match (self, other) { + (Span::Compiler(a), Span::Compiler(b)) => Span::Compiler(a.located_at(b)), + (Span::Fallback(a), Span::Fallback(b)) => Span::Fallback(a.located_at(b)), + (Span::Compiler(_), Span::Fallback(_)) => mismatch(line!()), + (Span::Fallback(_), Span::Compiler(_)) => mismatch(line!()), + } + } + + pub(crate) fn unwrap(self) -> proc_macro::Span { + match self { + Span::Compiler(s) => s, + Span::Fallback(_) => panic!("proc_macro::Span is only available in procedural macros"), + } + } + + #[cfg(span_locations)] + pub(crate) fn byte_range(&self) -> Range { + match self { + #[cfg(proc_macro_span)] + Span::Compiler(s) => proc_macro_span::byte_range(s), + #[cfg(not(proc_macro_span))] + Span::Compiler(_) => 0..0, + Span::Fallback(s) => s.byte_range(), + } + } + + #[cfg(span_locations)] + pub(crate) fn start(&self) -> LineColumn { + match self { + #[cfg(proc_macro_span_location)] + Span::Compiler(s) => LineColumn { + line: proc_macro_span_location::line(s), + column: proc_macro_span_location::column(s).saturating_sub(1), + }, + #[cfg(not(proc_macro_span_location))] + Span::Compiler(_) => LineColumn { line: 0, column: 0 }, + Span::Fallback(s) => s.start(), + } + } + + #[cfg(span_locations)] + pub(crate) fn end(&self) -> LineColumn { + match self { + #[cfg(proc_macro_span_location)] + Span::Compiler(s) => { + let end = proc_macro_span_location::end(s); + LineColumn { + line: proc_macro_span_location::line(&end), + column: proc_macro_span_location::column(&end).saturating_sub(1), + } + } + #[cfg(not(proc_macro_span_location))] + Span::Compiler(_) => LineColumn { line: 0, column: 0 }, + Span::Fallback(s) => s.end(), + } + } + + #[cfg(span_locations)] + pub(crate) fn file(&self) -> String { + match self { + #[cfg(proc_macro_span_file)] + Span::Compiler(s) => proc_macro_span_file::file(s), + #[cfg(not(proc_macro_span_file))] + Span::Compiler(_) => "".to_owned(), + Span::Fallback(s) => s.file(), + } + } + + #[cfg(span_locations)] + pub(crate) fn local_file(&self) -> Option { + match self { + #[cfg(proc_macro_span_file)] + Span::Compiler(s) => proc_macro_span_file::local_file(s), + #[cfg(not(proc_macro_span_file))] + Span::Compiler(_) => None, + Span::Fallback(s) => s.local_file(), + } + } + + pub(crate) fn join(&self, other: Span) -> Option { + let ret = match (self, other) { + #[cfg(proc_macro_span)] + (Span::Compiler(a), Span::Compiler(b)) => Span::Compiler(proc_macro_span::join(a, b)?), + (Span::Fallback(a), Span::Fallback(b)) => Span::Fallback(a.join(b)?), + _ => return None, + }; + Some(ret) + } + + #[cfg(super_unstable)] + pub(crate) fn eq(&self, other: &Span) -> bool { + match (self, other) { + (Span::Compiler(a), Span::Compiler(b)) => a.eq(b), + (Span::Fallback(a), Span::Fallback(b)) => a.eq(b), + _ => false, + } + } + + pub(crate) fn source_text(&self) -> Option { + match self { + #[cfg(not(no_source_text))] + Span::Compiler(s) => s.source_text(), + #[cfg(no_source_text)] + Span::Compiler(_) => None, + Span::Fallback(s) => s.source_text(), + } + } + + fn unwrap_nightly(self) -> proc_macro::Span { + match self { + Span::Compiler(s) => s, + Span::Fallback(_) => mismatch(line!()), + } + } +} + +impl From for crate::Span { + fn from(proc_span: proc_macro::Span) -> Self { + crate::Span::_new(Span::Compiler(proc_span)) + } +} + +impl From for Span { + fn from(inner: fallback::Span) -> Self { + Span::Fallback(inner) + } +} + +impl Debug for Span { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Span::Compiler(s) => Debug::fmt(s, f), + Span::Fallback(s) => Debug::fmt(s, f), + } + } +} + +pub(crate) fn debug_span_field_if_nontrivial(debug: &mut fmt::DebugStruct, span: Span) { + match span { + Span::Compiler(s) => { + debug.field("span", &s); + } + Span::Fallback(s) => fallback::debug_span_field_if_nontrivial(debug, s), + } +} + +#[derive(Clone)] +pub(crate) enum Group { + Compiler(proc_macro::Group), + Fallback(fallback::Group), +} + +impl Group { + pub(crate) fn new(delimiter: Delimiter, stream: TokenStream) -> Self { + match stream { + TokenStream::Compiler(tts) => { + let delimiter = match delimiter { + Delimiter::Parenthesis => proc_macro::Delimiter::Parenthesis, + Delimiter::Bracket => proc_macro::Delimiter::Bracket, + Delimiter::Brace => proc_macro::Delimiter::Brace, + Delimiter::None => proc_macro::Delimiter::None, + }; + Group::Compiler(proc_macro::Group::new(delimiter, tts.into_token_stream())) + } + TokenStream::Fallback(stream) => { + Group::Fallback(fallback::Group::new(delimiter, stream)) + } + } + } + + pub(crate) fn delimiter(&self) -> Delimiter { + match self { + Group::Compiler(g) => match g.delimiter() { + proc_macro::Delimiter::Parenthesis => Delimiter::Parenthesis, + proc_macro::Delimiter::Bracket => Delimiter::Bracket, + proc_macro::Delimiter::Brace => Delimiter::Brace, + proc_macro::Delimiter::None => Delimiter::None, + }, + Group::Fallback(g) => g.delimiter(), + } + } + + pub(crate) fn stream(&self) -> TokenStream { + match self { + Group::Compiler(g) => TokenStream::Compiler(DeferredTokenStream::new(g.stream())), + Group::Fallback(g) => TokenStream::Fallback(g.stream()), + } + } + + pub(crate) fn span(&self) -> Span { + match self { + Group::Compiler(g) => Span::Compiler(g.span()), + Group::Fallback(g) => Span::Fallback(g.span()), + } + } + + pub(crate) fn span_open(&self) -> Span { + match self { + Group::Compiler(g) => Span::Compiler(g.span_open()), + Group::Fallback(g) => Span::Fallback(g.span_open()), + } + } + + pub(crate) fn span_close(&self) -> Span { + match self { + Group::Compiler(g) => Span::Compiler(g.span_close()), + Group::Fallback(g) => Span::Fallback(g.span_close()), + } + } + + pub(crate) fn set_span(&mut self, span: Span) { + match (self, span) { + (Group::Compiler(g), Span::Compiler(s)) => g.set_span(s), + (Group::Fallback(g), Span::Fallback(s)) => g.set_span(s), + (Group::Compiler(_), Span::Fallback(_)) => mismatch(line!()), + (Group::Fallback(_), Span::Compiler(_)) => mismatch(line!()), + } + } + + fn unwrap_nightly(self) -> proc_macro::Group { + match self { + Group::Compiler(g) => g, + Group::Fallback(_) => mismatch(line!()), + } + } +} + +impl From for Group { + fn from(g: fallback::Group) -> Self { + Group::Fallback(g) + } +} + +impl Display for Group { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + Group::Compiler(group) => Display::fmt(group, formatter), + Group::Fallback(group) => Display::fmt(group, formatter), + } + } +} + +impl Debug for Group { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + Group::Compiler(group) => Debug::fmt(group, formatter), + Group::Fallback(group) => Debug::fmt(group, formatter), + } + } +} + +#[derive(Clone)] +pub(crate) enum Ident { + Compiler(proc_macro::Ident), + Fallback(fallback::Ident), +} + +impl Ident { + #[track_caller] + pub(crate) fn new_checked(string: &str, span: Span) -> Self { + match span { + Span::Compiler(s) => Ident::Compiler(proc_macro::Ident::new(string, s)), + Span::Fallback(s) => Ident::Fallback(fallback::Ident::new_checked(string, s)), + } + } + + #[track_caller] + pub(crate) fn new_raw_checked(string: &str, span: Span) -> Self { + match span { + Span::Compiler(s) => Ident::Compiler(proc_macro::Ident::new_raw(string, s)), + Span::Fallback(s) => Ident::Fallback(fallback::Ident::new_raw_checked(string, s)), + } + } + + pub(crate) fn span(&self) -> Span { + match self { + Ident::Compiler(t) => Span::Compiler(t.span()), + Ident::Fallback(t) => Span::Fallback(t.span()), + } + } + + pub(crate) fn set_span(&mut self, span: Span) { + match (self, span) { + (Ident::Compiler(t), Span::Compiler(s)) => t.set_span(s), + (Ident::Fallback(t), Span::Fallback(s)) => t.set_span(s), + (Ident::Compiler(_), Span::Fallback(_)) => mismatch(line!()), + (Ident::Fallback(_), Span::Compiler(_)) => mismatch(line!()), + } + } + + fn unwrap_nightly(self) -> proc_macro::Ident { + match self { + Ident::Compiler(s) => s, + Ident::Fallback(_) => mismatch(line!()), + } + } +} + +impl From for Ident { + fn from(inner: fallback::Ident) -> Self { + Ident::Fallback(inner) + } +} + +impl PartialEq for Ident { + fn eq(&self, other: &Ident) -> bool { + match (self, other) { + (Ident::Compiler(t), Ident::Compiler(o)) => t.to_string() == o.to_string(), + (Ident::Fallback(t), Ident::Fallback(o)) => t == o, + (Ident::Compiler(_), Ident::Fallback(_)) => mismatch(line!()), + (Ident::Fallback(_), Ident::Compiler(_)) => mismatch(line!()), + } + } +} + +impl PartialEq for Ident +where + T: ?Sized + AsRef, +{ + fn eq(&self, other: &T) -> bool { + let other = other.as_ref(); + match self { + Ident::Compiler(t) => t.to_string() == other, + Ident::Fallback(t) => t == other, + } + } +} + +impl Display for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Ident::Compiler(t) => Display::fmt(t, f), + Ident::Fallback(t) => Display::fmt(t, f), + } + } +} + +impl Debug for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Ident::Compiler(t) => Debug::fmt(t, f), + Ident::Fallback(t) => Debug::fmt(t, f), + } + } +} + +#[derive(Clone)] +pub(crate) enum Literal { + Compiler(proc_macro::Literal), + Fallback(fallback::Literal), +} + +macro_rules! suffixed_numbers { + ($($name:ident => $kind:ident,)*) => ($( + pub(crate) fn $name(n: $kind) -> Literal { + if inside_proc_macro() { + Literal::Compiler(proc_macro::Literal::$name(n)) + } else { + Literal::Fallback(fallback::Literal::$name(n)) + } + } + )*) +} + +macro_rules! unsuffixed_integers { + ($($name:ident => $kind:ident,)*) => ($( + pub(crate) fn $name(n: $kind) -> Literal { + if inside_proc_macro() { + Literal::Compiler(proc_macro::Literal::$name(n)) + } else { + Literal::Fallback(fallback::Literal::$name(n)) + } + } + )*) +} + +impl Literal { + pub(crate) fn from_str_checked(repr: &str) -> Result { + if inside_proc_macro() { + let literal = proc_macro::Literal::from_str_checked(repr)?; + Ok(Literal::Compiler(literal)) + } else { + let literal = fallback::Literal::from_str_checked(repr)?; + Ok(Literal::Fallback(literal)) + } + } + + pub(crate) unsafe fn from_str_unchecked(repr: &str) -> Self { + if inside_proc_macro() { + Literal::Compiler(proc_macro::Literal::from_str_unchecked(repr)) + } else { + Literal::Fallback(unsafe { fallback::Literal::from_str_unchecked(repr) }) + } + } + + suffixed_numbers! { + u8_suffixed => u8, + u16_suffixed => u16, + u32_suffixed => u32, + u64_suffixed => u64, + u128_suffixed => u128, + usize_suffixed => usize, + i8_suffixed => i8, + i16_suffixed => i16, + i32_suffixed => i32, + i64_suffixed => i64, + i128_suffixed => i128, + isize_suffixed => isize, + + f32_suffixed => f32, + f64_suffixed => f64, + } + + unsuffixed_integers! { + u8_unsuffixed => u8, + u16_unsuffixed => u16, + u32_unsuffixed => u32, + u64_unsuffixed => u64, + u128_unsuffixed => u128, + usize_unsuffixed => usize, + i8_unsuffixed => i8, + i16_unsuffixed => i16, + i32_unsuffixed => i32, + i64_unsuffixed => i64, + i128_unsuffixed => i128, + isize_unsuffixed => isize, + } + + pub(crate) fn f32_unsuffixed(f: f32) -> Literal { + if inside_proc_macro() { + Literal::Compiler(proc_macro::Literal::f32_unsuffixed(f)) + } else { + Literal::Fallback(fallback::Literal::f32_unsuffixed(f)) + } + } + + pub(crate) fn f64_unsuffixed(f: f64) -> Literal { + if inside_proc_macro() { + Literal::Compiler(proc_macro::Literal::f64_unsuffixed(f)) + } else { + Literal::Fallback(fallback::Literal::f64_unsuffixed(f)) + } + } + + pub(crate) fn string(string: &str) -> Literal { + if inside_proc_macro() { + Literal::Compiler(proc_macro::Literal::string(string)) + } else { + Literal::Fallback(fallback::Literal::string(string)) + } + } + + pub(crate) fn character(ch: char) -> Literal { + if inside_proc_macro() { + Literal::Compiler(proc_macro::Literal::character(ch)) + } else { + Literal::Fallback(fallback::Literal::character(ch)) + } + } + + pub(crate) fn byte_character(byte: u8) -> Literal { + if inside_proc_macro() { + Literal::Compiler({ + #[cfg(not(no_literal_byte_character))] + { + proc_macro::Literal::byte_character(byte) + } + + #[cfg(no_literal_byte_character)] + { + let fallback = fallback::Literal::byte_character(byte); + proc_macro::Literal::from_str_unchecked(&fallback.repr) + } + }) + } else { + Literal::Fallback(fallback::Literal::byte_character(byte)) + } + } + + pub(crate) fn byte_string(bytes: &[u8]) -> Literal { + if inside_proc_macro() { + Literal::Compiler(proc_macro::Literal::byte_string(bytes)) + } else { + Literal::Fallback(fallback::Literal::byte_string(bytes)) + } + } + + pub(crate) fn c_string(string: &CStr) -> Literal { + if inside_proc_macro() { + Literal::Compiler({ + #[cfg(not(no_literal_c_string))] + { + proc_macro::Literal::c_string(string) + } + + #[cfg(no_literal_c_string)] + { + let fallback = fallback::Literal::c_string(string); + proc_macro::Literal::from_str_unchecked(&fallback.repr) + } + }) + } else { + Literal::Fallback(fallback::Literal::c_string(string)) + } + } + + pub(crate) fn span(&self) -> Span { + match self { + Literal::Compiler(lit) => Span::Compiler(lit.span()), + Literal::Fallback(lit) => Span::Fallback(lit.span()), + } + } + + pub(crate) fn set_span(&mut self, span: Span) { + match (self, span) { + (Literal::Compiler(lit), Span::Compiler(s)) => lit.set_span(s), + (Literal::Fallback(lit), Span::Fallback(s)) => lit.set_span(s), + (Literal::Compiler(_), Span::Fallback(_)) => mismatch(line!()), + (Literal::Fallback(_), Span::Compiler(_)) => mismatch(line!()), + } + } + + pub(crate) fn subspan>(&self, range: R) -> Option { + match self { + #[cfg(proc_macro_span)] + Literal::Compiler(lit) => proc_macro_span::subspan(lit, range).map(Span::Compiler), + #[cfg(not(proc_macro_span))] + Literal::Compiler(_lit) => None, + Literal::Fallback(lit) => lit.subspan(range).map(Span::Fallback), + } + } + + fn unwrap_nightly(self) -> proc_macro::Literal { + match self { + Literal::Compiler(s) => s, + Literal::Fallback(_) => mismatch(line!()), + } + } +} + +impl From for Literal { + fn from(s: fallback::Literal) -> Self { + Literal::Fallback(s) + } +} + +impl Display for Literal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Literal::Compiler(t) => Display::fmt(t, f), + Literal::Fallback(t) => Display::fmt(t, f), + } + } +} + +impl Debug for Literal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Literal::Compiler(t) => Debug::fmt(t, f), + Literal::Fallback(t) => Debug::fmt(t, f), + } + } +} + +#[cfg(span_locations)] +pub(crate) fn invalidate_current_thread_spans() { + if inside_proc_macro() { + panic!( + "proc_macro2::extra::invalidate_current_thread_spans is not available in procedural macros" + ); + } + crate::fallback::invalidate_current_thread_spans(); +} diff --git a/third_party/crates/proc-macro2-1.0.107/tests/comments.rs b/third_party/crates/proc-macro2-1.0.107/tests/comments.rs new file mode 100644 index 0000000..34951f7 --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/tests/comments.rs @@ -0,0 +1,105 @@ +#![allow(clippy::assertions_on_result_states, clippy::uninlined_format_args)] + +use proc_macro2::{Delimiter, Literal, Spacing, TokenStream, TokenTree}; + +// #[doc = "..."] -> "..." +fn lit_of_outer_doc_comment(tokens: &TokenStream) -> Literal { + lit_of_doc_comment(tokens, false) +} + +// #![doc = "..."] -> "..." +fn lit_of_inner_doc_comment(tokens: &TokenStream) -> Literal { + lit_of_doc_comment(tokens, true) +} + +fn lit_of_doc_comment(tokens: &TokenStream, inner: bool) -> Literal { + let mut iter = tokens.clone().into_iter(); + match iter.next().unwrap() { + TokenTree::Punct(punct) => { + assert_eq!(punct.as_char(), '#'); + assert_eq!(punct.spacing(), Spacing::Alone); + } + _ => panic!("wrong token {:?}", tokens), + } + if inner { + match iter.next().unwrap() { + TokenTree::Punct(punct) => { + assert_eq!(punct.as_char(), '!'); + assert_eq!(punct.spacing(), Spacing::Alone); + } + _ => panic!("wrong token {:?}", tokens), + } + } + iter = match iter.next().unwrap() { + TokenTree::Group(group) => { + assert_eq!(group.delimiter(), Delimiter::Bracket); + assert!(iter.next().is_none(), "unexpected token {:?}", tokens); + group.stream().into_iter() + } + _ => panic!("wrong token {:?}", tokens), + }; + match iter.next().unwrap() { + TokenTree::Ident(ident) => assert_eq!(ident.to_string(), "doc"), + _ => panic!("wrong token {:?}", tokens), + } + match iter.next().unwrap() { + TokenTree::Punct(punct) => { + assert_eq!(punct.as_char(), '='); + assert_eq!(punct.spacing(), Spacing::Alone); + } + _ => panic!("wrong token {:?}", tokens), + } + match iter.next().unwrap() { + TokenTree::Literal(literal) => { + assert!(iter.next().is_none(), "unexpected token {:?}", tokens); + literal + } + _ => panic!("wrong token {:?}", tokens), + } +} + +#[test] +fn closed_immediately() { + let stream = "/**/".parse::().unwrap(); + let tokens = stream.into_iter().collect::>(); + assert!(tokens.is_empty(), "not empty -- {:?}", tokens); +} + +#[test] +fn incomplete() { + assert!("/*/".parse::().is_err()); +} + +#[test] +fn lit() { + let stream = "/// doc".parse::().unwrap(); + let lit = lit_of_outer_doc_comment(&stream); + assert_eq!(lit.to_string(), "\" doc\""); + + let stream = "//! doc".parse::().unwrap(); + let lit = lit_of_inner_doc_comment(&stream); + assert_eq!(lit.to_string(), "\" doc\""); + + let stream = "/** doc */".parse::().unwrap(); + let lit = lit_of_outer_doc_comment(&stream); + assert_eq!(lit.to_string(), "\" doc \""); + + let stream = "/*! doc */".parse::().unwrap(); + let lit = lit_of_inner_doc_comment(&stream); + assert_eq!(lit.to_string(), "\" doc \""); +} + +#[test] +fn carriage_return() { + let stream = "///\r\n".parse::().unwrap(); + let lit = lit_of_outer_doc_comment(&stream); + assert_eq!(lit.to_string(), "\"\""); + + let stream = "/**\r\n*/".parse::().unwrap(); + let lit = lit_of_outer_doc_comment(&stream); + assert_eq!(lit.to_string(), "\"\\r\\n\""); + + "///\r".parse::().unwrap_err(); + "///\r \n".parse::().unwrap_err(); + "/**\r \n*/".parse::().unwrap_err(); +} diff --git a/third_party/crates/proc-macro2-1.0.107/tests/features.rs b/third_party/crates/proc-macro2-1.0.107/tests/features.rs new file mode 100644 index 0000000..ea1704d --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/tests/features.rs @@ -0,0 +1,10 @@ +#![allow(clippy::assertions_on_constants, clippy::ignore_without_reason)] + +#[test] +#[ignore] +fn make_sure_no_proc_macro() { + assert!( + !cfg!(feature = "proc-macro"), + "still compiled with proc_macro?" + ); +} diff --git a/third_party/crates/proc-macro2-1.0.107/tests/marker.rs b/third_party/crates/proc-macro2-1.0.107/tests/marker.rs new file mode 100644 index 0000000..af8932a --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/tests/marker.rs @@ -0,0 +1,97 @@ +#![allow(clippy::extra_unused_type_parameters)] + +use proc_macro2::{ + Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree, +}; + +macro_rules! assert_impl { + ($ty:ident is $($marker:ident) and +) => { + #[test] + #[allow(non_snake_case)] + fn $ty() { + fn assert_implemented() {} + assert_implemented::<$ty>(); + } + }; + + ($ty:ident is not $($marker:ident) or +) => { + #[test] + #[allow(non_snake_case)] + fn $ty() { + $( + { + // Implemented for types that implement $marker. + #[allow(dead_code)] + trait IsNotImplemented { + fn assert_not_implemented() {} + } + impl IsNotImplemented for T {} + + // Implemented for the type being tested. + trait IsImplemented { + fn assert_not_implemented() {} + } + impl IsImplemented for $ty {} + + // If $ty does not implement $marker, there is no ambiguity + // in the following trait method call. + <$ty>::assert_not_implemented(); + } + )+ + } + }; +} + +assert_impl!(Delimiter is Send and Sync); +assert_impl!(Spacing is Send and Sync); + +assert_impl!(Group is not Send or Sync); +assert_impl!(Ident is not Send or Sync); +assert_impl!(LexError is not Send or Sync); +assert_impl!(Literal is not Send or Sync); +assert_impl!(Punct is not Send or Sync); +assert_impl!(Span is not Send or Sync); +assert_impl!(TokenStream is not Send or Sync); +assert_impl!(TokenTree is not Send or Sync); + +#[cfg(procmacro2_semver_exempt)] +mod semver_exempt { + use proc_macro2::LineColumn; + + assert_impl!(LineColumn is Send and Sync); +} + +mod unwind_safe { + #[cfg(procmacro2_semver_exempt)] + use proc_macro2::LineColumn; + use proc_macro2::{ + Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree, + }; + use std::panic::{RefUnwindSafe, UnwindSafe}; + + macro_rules! assert_unwind_safe { + ($($types:ident)*) => { + $( + assert_impl!($types is UnwindSafe and RefUnwindSafe); + )* + }; + } + + assert_unwind_safe! { + Delimiter + Group + Ident + LexError + Literal + Punct + Spacing + Span + TokenStream + TokenTree + } + + #[cfg(procmacro2_semver_exempt)] + assert_unwind_safe! { + LineColumn + } +} diff --git a/third_party/crates/proc-macro2-1.0.107/tests/test.rs b/third_party/crates/proc-macro2-1.0.107/tests/test.rs new file mode 100644 index 0000000..1989330 --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/tests/test.rs @@ -0,0 +1,1093 @@ +#![allow( + clippy::assertions_on_result_states, + clippy::items_after_statements, + clippy::needless_pass_by_value, + clippy::needless_raw_string_hashes, + clippy::non_ascii_literal, + clippy::octal_escapes, + clippy::uninlined_format_args +)] + +use proc_macro2::{Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; +use std::ffi::CStr; +use std::iter; +use std::str::{self, FromStr}; + +#[test] +fn idents() { + assert_eq!( + Ident::new("String", Span::call_site()).to_string(), + "String" + ); + assert_eq!(Ident::new("fn", Span::call_site()).to_string(), "fn"); + assert_eq!(Ident::new("_", Span::call_site()).to_string(), "_"); +} + +#[test] +fn raw_idents() { + assert_eq!( + Ident::new_raw("String", Span::call_site()).to_string(), + "r#String" + ); + assert_eq!(Ident::new_raw("fn", Span::call_site()).to_string(), "r#fn"); +} + +#[test] +#[should_panic(expected = "`r#_` cannot be a raw identifier")] +fn ident_raw_underscore() { + Ident::new_raw("_", Span::call_site()); +} + +#[test] +#[should_panic(expected = "`r#super` cannot be a raw identifier")] +fn ident_raw_reserved() { + Ident::new_raw("super", Span::call_site()); +} + +#[test] +#[should_panic(expected = "Ident is not allowed to be empty; use Option")] +fn ident_empty() { + Ident::new("", Span::call_site()); +} + +#[test] +#[should_panic(expected = "Ident cannot be a number; use Literal instead")] +fn ident_number() { + Ident::new("255", Span::call_site()); +} + +#[test] +#[should_panic(expected = "\"a#\" is not a valid Ident")] +fn ident_invalid() { + Ident::new("a#", Span::call_site()); +} + +#[test] +#[should_panic(expected = "not a valid Ident")] +fn raw_ident_empty() { + Ident::new("r#", Span::call_site()); +} + +#[test] +#[should_panic(expected = "not a valid Ident")] +fn raw_ident_number() { + Ident::new("r#255", Span::call_site()); +} + +#[test] +#[should_panic(expected = "\"r#a#\" is not a valid Ident")] +fn raw_ident_invalid() { + Ident::new("r#a#", Span::call_site()); +} + +#[test] +#[should_panic(expected = "not a valid Ident")] +fn lifetime_empty() { + Ident::new("'", Span::call_site()); +} + +#[test] +#[should_panic(expected = "not a valid Ident")] +fn lifetime_number() { + Ident::new("'255", Span::call_site()); +} + +#[test] +#[should_panic(expected = r#""'a#" is not a valid Ident"#)] +fn lifetime_invalid() { + Ident::new("'a#", Span::call_site()); +} + +#[test] +fn literal_string() { + #[track_caller] + fn assert(literal: Literal, expected: &str) { + assert_eq!(literal.to_string(), expected.trim()); + } + + assert(Literal::string(""), r#" "" "#); + assert(Literal::string("aA"), r#" "aA" "#); + assert(Literal::string("\t"), r#" "\t" "#); + assert(Literal::string("❤"), r#" "❤" "#); + assert(Literal::string("'"), r#" "'" "#); + assert(Literal::string("\""), r#" "\"" "#); + assert(Literal::string("\0"), r#" "\0" "#); + assert(Literal::string("\u{1}"), r#" "\u{1}" "#); + assert( + Literal::string("a\00b\07c\08d\0e\0"), + r#" "a\x000b\x007c\08d\0e\0" "#, + ); + + "\"\\\r\n x\"".parse::().unwrap(); + "\"\\\r\n \rx\"".parse::().unwrap_err(); +} + +#[test] +fn literal_raw_string() { + "r\"\r\n\"".parse::().unwrap(); + + fn raw_string_literal_with_hashes(n: usize) -> String { + let mut literal = String::new(); + literal.push('r'); + literal.extend(iter::repeat('#').take(n)); + literal.push('"'); + literal.push('"'); + literal.extend(iter::repeat('#').take(n)); + literal + } + + raw_string_literal_with_hashes(255) + .parse::() + .unwrap(); + + // https://github.com/rust-lang/rust/pull/95251 + raw_string_literal_with_hashes(256) + .parse::() + .unwrap_err(); +} + +#[cfg(procmacro2_semver_exempt)] +#[test] +fn literal_string_value() { + for string in ["", "...", "...\t...", "...\\...", "...\0...", "...\u{1}..."] { + assert_eq!(string, Literal::string(string).str_value().unwrap()); + assert_eq!( + string, + format!("r\"{string}\"") + .parse::() + .unwrap() + .str_value() + .unwrap(), + ); + assert_eq!( + string, + format!("r##\"{string}\"##") + .parse::() + .unwrap() + .str_value() + .unwrap(), + ); + } +} + +#[test] +fn literal_byte_character() { + #[track_caller] + fn assert(literal: Literal, expected: &str) { + assert_eq!(literal.to_string(), expected.trim()); + } + + assert(Literal::byte_character(b'a'), r#" b'a' "#); + assert(Literal::byte_character(b'\0'), r#" b'\0' "#); + assert(Literal::byte_character(b'\t'), r#" b'\t' "#); + assert(Literal::byte_character(b'\n'), r#" b'\n' "#); + assert(Literal::byte_character(b'\r'), r#" b'\r' "#); + assert(Literal::byte_character(b'\''), r#" b'\'' "#); + assert(Literal::byte_character(b'\\'), r#" b'\\' "#); + assert(Literal::byte_character(b'\x1f'), r#" b'\x1F' "#); + assert(Literal::byte_character(b'"'), r#" b'"' "#); +} + +#[test] +fn literal_byte_string() { + #[track_caller] + fn assert(literal: Literal, expected: &str) { + assert_eq!(literal.to_string(), expected.trim()); + } + + assert(Literal::byte_string(b""), r#" b"" "#); + assert(Literal::byte_string(b"\0"), r#" b"\0" "#); + assert(Literal::byte_string(b"\t"), r#" b"\t" "#); + assert(Literal::byte_string(b"\n"), r#" b"\n" "#); + assert(Literal::byte_string(b"\r"), r#" b"\r" "#); + assert(Literal::byte_string(b"\""), r#" b"\"" "#); + assert(Literal::byte_string(b"\\"), r#" b"\\" "#); + assert(Literal::byte_string(b"\x1f"), r#" b"\x1F" "#); + assert(Literal::byte_string(b"'"), r#" b"'" "#); + assert( + Literal::byte_string(b"a\00b\07c\08d\0e\0"), + r#" b"a\x000b\x007c\08d\0e\0" "#, + ); + + "b\"\\\r\n x\"".parse::().unwrap(); + "b\"\\\r\n \rx\"".parse::().unwrap_err(); + "b\"\\\r\n \u{a0}x\"".parse::().unwrap_err(); + "br\"\u{a0}\"".parse::().unwrap_err(); +} + +#[cfg(procmacro2_semver_exempt)] +#[test] +fn literal_byte_string_value() { + for bytestr in [ + &b""[..], + b"...", + b"...\t...", + b"...\\...", + b"...\0...", + b"...\xF0...", + ] { + assert_eq!( + bytestr, + Literal::byte_string(bytestr).byte_str_value().unwrap(), + ); + if let Ok(string) = str::from_utf8(bytestr) { + assert_eq!( + bytestr, + format!("br\"{string}\"") + .parse::() + .unwrap() + .byte_str_value() + .unwrap(), + ); + assert_eq!( + bytestr, + format!("br##\"{string}\"##") + .parse::() + .unwrap() + .byte_str_value() + .unwrap(), + ); + } + } +} + +#[test] +fn literal_c_string() { + #[track_caller] + fn assert(literal: Literal, expected: &str) { + assert_eq!(literal.to_string(), expected.trim()); + } + + assert(Literal::c_string(<&CStr>::default()), r#" c"" "#); + assert( + Literal::c_string(CStr::from_bytes_with_nul(b"aA\0").unwrap()), + r#" c"aA" "#, + ); + assert( + Literal::c_string(CStr::from_bytes_with_nul(b"aA\0").unwrap()), + r#" c"aA" "#, + ); + assert( + Literal::c_string(CStr::from_bytes_with_nul(b"\t\0").unwrap()), + r#" c"\t" "#, + ); + assert( + Literal::c_string(CStr::from_bytes_with_nul(b"\xE2\x9D\xA4\0").unwrap()), + r#" c"❤" "#, + ); + assert( + Literal::c_string(CStr::from_bytes_with_nul(b"'\0").unwrap()), + r#" c"'" "#, + ); + assert( + Literal::c_string(CStr::from_bytes_with_nul(b"\"\0").unwrap()), + r#" c"\"" "#, + ); + assert( + Literal::c_string(CStr::from_bytes_with_nul(b"\x7F\xFF\xFE\xCC\xB3\0").unwrap()), + r#" c"\u{7f}\xFF\xFE\u{333}" "#, + ); + + let strings = r###" + c"hello\x80我叫\u{1F980}" // from the RFC + cr"\" + cr##"Hello "world"!"## + c"\t\n\r\"\\" + "###; + + let mut tokens = strings.parse::().unwrap().into_iter(); + + for expected in &[ + r#"c"hello\x80我叫\u{1F980}""#, + r#"cr"\""#, + r###"cr##"Hello "world"!"##"###, + r#"c"\t\n\r\"\\""#, + ] { + match tokens.next().unwrap() { + TokenTree::Literal(literal) => { + assert_eq!(literal.to_string(), *expected); + } + unexpected => panic!("unexpected token: {:?}", unexpected), + } + } + + if let Some(unexpected) = tokens.next() { + panic!("unexpected token: {:?}", unexpected); + } + + for invalid in &[r#"c"\0""#, r#"c"\x00""#, r#"c"\u{0}""#, "c\"\0\""] { + if let Ok(unexpected) = invalid.parse::() { + panic!("unexpected token: {:?}", unexpected); + } + } +} + +#[cfg(procmacro2_semver_exempt)] +#[test] +fn literal_c_string_value() { + for cstr in [ + c"", + c"...", + c"...\t...", + c"...\\...", + c"...\u{1}...", + c"...\xF0...", + ] { + assert_eq!( + cstr.to_bytes_with_nul(), + Literal::c_string(cstr).cstr_value().unwrap(), + ); + if let Ok(string) = cstr.to_str() { + assert_eq!( + cstr.to_bytes_with_nul(), + format!("cr\"{string}\"") + .parse::() + .unwrap() + .cstr_value() + .unwrap(), + ); + assert_eq!( + cstr.to_bytes_with_nul(), + format!("cr##\"{string}\"##") + .parse::() + .unwrap() + .cstr_value() + .unwrap(), + ); + } + } +} + +#[test] +fn literal_character() { + #[track_caller] + fn assert(literal: Literal, expected: &str) { + assert_eq!(literal.to_string(), expected.trim()); + } + + assert(Literal::character('a'), r#" 'a' "#); + assert(Literal::character('\t'), r#" '\t' "#); + assert(Literal::character('❤'), r#" '❤' "#); + assert(Literal::character('\''), r#" '\'' "#); + assert(Literal::character('"'), r#" '"' "#); + assert(Literal::character('\0'), r#" '\0' "#); + assert(Literal::character('\u{1}'), r#" '\u{1}' "#); +} + +#[test] +fn literal_integer() { + #[track_caller] + fn assert(literal: Literal, expected: &str) { + assert_eq!(literal.to_string(), expected); + } + + assert(Literal::u8_suffixed(10), "10u8"); + assert(Literal::u16_suffixed(10), "10u16"); + assert(Literal::u32_suffixed(10), "10u32"); + assert(Literal::u64_suffixed(10), "10u64"); + assert(Literal::u128_suffixed(10), "10u128"); + assert(Literal::usize_suffixed(10), "10usize"); + + assert(Literal::i8_suffixed(10), "10i8"); + assert(Literal::i16_suffixed(10), "10i16"); + assert(Literal::i32_suffixed(10), "10i32"); + assert(Literal::i64_suffixed(10), "10i64"); + assert(Literal::i128_suffixed(10), "10i128"); + assert(Literal::isize_suffixed(10), "10isize"); + + assert(Literal::u8_unsuffixed(10), "10"); + assert(Literal::u16_unsuffixed(10), "10"); + assert(Literal::u32_unsuffixed(10), "10"); + assert(Literal::u64_unsuffixed(10), "10"); + assert(Literal::u128_unsuffixed(10), "10"); + assert(Literal::usize_unsuffixed(10), "10"); + + assert(Literal::i8_unsuffixed(10), "10"); + assert(Literal::i16_unsuffixed(10), "10"); + assert(Literal::i32_unsuffixed(10), "10"); + assert(Literal::i64_unsuffixed(10), "10"); + assert(Literal::i128_unsuffixed(10), "10"); + assert(Literal::isize_unsuffixed(10), "10"); + + assert(Literal::i32_suffixed(-10), "-10i32"); + assert(Literal::i32_unsuffixed(-10), "-10"); +} + +#[test] +fn literal_float() { + #[track_caller] + fn assert(literal: Literal, expected: &str) { + assert_eq!(literal.to_string(), expected); + } + + assert(Literal::f32_suffixed(10.0), "10f32"); + assert(Literal::f32_suffixed(-10.0), "-10f32"); + assert(Literal::f64_suffixed(10.0), "10f64"); + assert(Literal::f64_suffixed(-10.0), "-10f64"); + + assert(Literal::f32_unsuffixed(10.0), "10.0"); + assert(Literal::f32_unsuffixed(-10.0), "-10.0"); + assert(Literal::f64_unsuffixed(10.0), "10.0"); + assert(Literal::f64_unsuffixed(-10.0), "-10.0"); + + assert( + Literal::f64_unsuffixed(1e100), + "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0", + ); +} + +#[test] +fn literal_suffix() { + fn token_count(p: &str) -> usize { + p.parse::().unwrap().into_iter().count() + } + + assert_eq!(token_count("999u256"), 1); + assert_eq!(token_count("999r#u256"), 3); + assert_eq!(token_count("1."), 1); + assert_eq!(token_count("1.f32"), 3); + assert_eq!(token_count("1.0_0"), 1); + assert_eq!(token_count("1._0"), 3); + assert_eq!(token_count("1._m"), 3); + assert_eq!(token_count("\"\"s"), 1); + assert_eq!(token_count("r\"\"r"), 1); + assert_eq!(token_count("r#\"\"#r"), 1); + assert_eq!(token_count("b\"\"b"), 1); + assert_eq!(token_count("br\"\"br"), 1); + assert_eq!(token_count("br#\"\"#br"), 1); + assert_eq!(token_count("c\"\"c"), 1); + assert_eq!(token_count("cr\"\"cr"), 1); + assert_eq!(token_count("cr#\"\"#cr"), 1); + assert_eq!(token_count("'c'c"), 1); + assert_eq!(token_count("b'b'b"), 1); + assert_eq!(token_count("0E"), 1); + assert_eq!(token_count("0o0A"), 1); + assert_eq!(token_count("0E--0"), 4); + assert_eq!(token_count("0.0ECMA"), 1); +} + +#[test] +fn literal_iter_negative() { + let negative_literal = Literal::i32_suffixed(-3); + let tokens = TokenStream::from(TokenTree::Literal(negative_literal)); + let mut iter = tokens.into_iter(); + match iter.next().unwrap() { + TokenTree::Punct(punct) => { + assert_eq!(punct.as_char(), '-'); + assert_eq!(punct.spacing(), Spacing::Alone); + } + unexpected => panic!("unexpected token {:?}", unexpected), + } + match iter.next().unwrap() { + TokenTree::Literal(literal) => { + assert_eq!(literal.to_string(), "3i32"); + } + unexpected => panic!("unexpected token {:?}", unexpected), + } + assert!(iter.next().is_none()); +} + +#[test] +fn literal_parse() { + assert!("1".parse::().is_ok()); + assert!("-1".parse::().is_ok()); + assert!("-1u12".parse::().is_ok()); + assert!("1.0".parse::().is_ok()); + assert!("-1.0".parse::().is_ok()); + assert!("-1.0f12".parse::().is_ok()); + assert!("'a'".parse::().is_ok()); + assert!("\"\n\"".parse::().is_ok()); + assert!("0 1".parse::().is_err()); + assert!(" 0".parse::().is_err()); + assert!("0 ".parse::().is_err()); + assert!("/* comment */0".parse::().is_err()); + assert!("0/* comment */".parse::().is_err()); + assert!("0// comment".parse::().is_err()); + assert!("- 1".parse::().is_err()); + assert!("- 1.0".parse::().is_err()); + assert!("-\"\"".parse::().is_err()); +} + +#[test] +fn literal_span() { + let positive = "0.1".parse::().unwrap(); + let negative = "-0.1".parse::().unwrap(); + let subspan = positive.subspan(1..2); + + #[cfg(not(span_locations))] + { + let _ = negative; + assert!(subspan.is_none()); + } + + #[cfg(span_locations)] + { + assert_eq!(positive.span().start().column, 0); + assert_eq!(positive.span().end().column, 3); + assert_eq!(negative.span().start().column, 0); + assert_eq!(negative.span().end().column, 4); + assert_eq!(subspan.unwrap().source_text().unwrap(), "."); + } + + assert!(positive.subspan(1..4).is_none()); +} + +#[cfg(span_locations)] +#[test] +fn source_text() { + let input = " 𓀕 a z "; + let mut tokens = input + .parse::() + .unwrap() + .into_iter(); + + let first = tokens.next().unwrap(); + assert_eq!("𓀕", first.span().source_text().unwrap()); + + let second = tokens.next().unwrap(); + let third = tokens.next().unwrap(); + assert_eq!("z", third.span().source_text().unwrap()); + assert_eq!("a", second.span().source_text().unwrap()); +} + +#[test] +fn lifetimes() { + let mut tokens = "'a 'static 'struct 'r#gen 'r#prefix#lifetime" + .parse::() + .unwrap() + .into_iter(); + assert!(match tokens.next() { + Some(TokenTree::Punct(punct)) => { + punct.as_char() == '\'' && punct.spacing() == Spacing::Joint + } + _ => false, + }); + assert!(match tokens.next() { + Some(TokenTree::Ident(ident)) => ident == "a", + _ => false, + }); + assert!(match tokens.next() { + Some(TokenTree::Punct(punct)) => { + punct.as_char() == '\'' && punct.spacing() == Spacing::Joint + } + _ => false, + }); + assert!(match tokens.next() { + Some(TokenTree::Ident(ident)) => ident == "static", + _ => false, + }); + assert!(match tokens.next() { + Some(TokenTree::Punct(punct)) => { + punct.as_char() == '\'' && punct.spacing() == Spacing::Joint + } + _ => false, + }); + assert!(match tokens.next() { + Some(TokenTree::Ident(ident)) => ident == "struct", + _ => false, + }); + assert!(match tokens.next() { + Some(TokenTree::Punct(punct)) => { + punct.as_char() == '\'' && punct.spacing() == Spacing::Joint + } + _ => false, + }); + assert!(match tokens.next() { + Some(TokenTree::Ident(ident)) => ident == "r#gen", + _ => false, + }); + assert!(match tokens.next() { + Some(TokenTree::Punct(punct)) => { + punct.as_char() == '\'' && punct.spacing() == Spacing::Joint + } + _ => false, + }); + assert!(match tokens.next() { + Some(TokenTree::Ident(ident)) => ident == "r#prefix", + _ => false, + }); + assert!(match tokens.next() { + Some(TokenTree::Punct(punct)) => { + punct.as_char() == '#' && punct.spacing() == Spacing::Alone + } + _ => false, + }); + assert!(match tokens.next() { + Some(TokenTree::Ident(ident)) => ident == "lifetime", + _ => false, + }); + + "' a".parse::().unwrap_err(); + "' r#gen".parse::().unwrap_err(); + "' prefix#lifetime".parse::().unwrap_err(); + "'prefix#lifetime".parse::().unwrap_err(); + "'aa'bb".parse::().unwrap_err(); + "'r#gen'a".parse::().unwrap_err(); +} + +#[test] +fn roundtrip() { + fn roundtrip(p: &str) { + println!("parse: {}", p); + let s = p.parse::().unwrap().to_string(); + println!("first: {}", s); + let s2 = s.parse::().unwrap().to_string(); + assert_eq!(s, s2); + } + roundtrip("a"); + roundtrip("<<"); + roundtrip("<<="); + roundtrip( + " + 1 + 1.0 + 1f32 + 2f64 + 1usize + 4isize + 4e10 + 1_000 + 1_0i32 + 8u8 + 9 + 0 + 0xffffffffffffffffffffffffffffffff + 1x + 1u80 + 1f320 + ", + ); + roundtrip("'a"); + roundtrip("'_"); + roundtrip("'static"); + roundtrip(r"'\u{10__FFFF}'"); + roundtrip("\"\\u{10_F0FF__}foo\\u{1_0_0_0__}\""); +} + +#[test] +fn fail() { + fn fail(p: &str) { + if let Ok(s) = p.parse::() { + panic!("should have failed to parse: {}\n{:#?}", p, s); + } + } + fail("' static"); + fail("r#1"); + fail("r#_"); + fail("\"\\u{0000000}\""); // overlong unicode escape (rust allows at most 6 hex digits) + fail("\"\\u{999999}\""); // outside of valid range of char + fail("\"\\u{_0}\""); // leading underscore + fail("\"\\u{}\""); // empty + fail("b\"\r\""); // bare carriage return in byte string + fail("r\"\r\""); // bare carriage return in raw string + fail("\"\\\r \""); // backslash carriage return + fail("'aa'aa"); + fail("br##\"\"#"); + fail("cr##\"\"#"); + fail("\"\\\n\u{85}\r\""); +} + +#[cfg(span_locations)] +#[test] +fn span_test() { + check_spans( + "\ +/// This is a document comment +testing 123 +{ + testing 234 +}", + &[ + (1, 0, 1, 30), // # + (1, 0, 1, 30), // [ ... ] + (1, 0, 1, 30), // doc + (1, 0, 1, 30), // = + (1, 0, 1, 30), // "This is..." + (2, 0, 2, 7), // testing + (2, 8, 2, 11), // 123 + (3, 0, 5, 1), // { ... } + (4, 2, 4, 9), // testing + (4, 10, 4, 13), // 234 + ], + ); +} + +#[cfg(procmacro2_semver_exempt)] +#[test] +fn default_span() { + let start = Span::call_site().start(); + assert_eq!(start.line, 1); + assert_eq!(start.column, 0); + let end = Span::call_site().end(); + assert_eq!(end.line, 1); + assert_eq!(end.column, 0); + assert_eq!(Span::call_site().file(), ""); + assert!(Span::call_site().local_file().is_none()); +} + +#[cfg(procmacro2_semver_exempt)] +#[test] +fn span_join() { + let source1 = "aaa\nbbb" + .parse::() + .unwrap() + .into_iter() + .collect::>(); + let source2 = "ccc\nddd" + .parse::() + .unwrap() + .into_iter() + .collect::>(); + + assert!(source1[0].span().file() != source2[0].span().file()); + assert_eq!(source1[0].span().file(), source1[1].span().file()); + + let joined1 = source1[0].span().join(source1[1].span()); + let joined2 = source1[0].span().join(source2[0].span()); + assert!(joined1.is_some()); + assert!(joined2.is_none()); + + let start = joined1.unwrap().start(); + let end = joined1.unwrap().end(); + assert_eq!(start.line, 1); + assert_eq!(start.column, 0); + assert_eq!(end.line, 2); + assert_eq!(end.column, 3); + + assert_eq!(joined1.unwrap().file(), source1[0].span().file()); +} + +#[test] +fn no_panic() { + let s = str::from_utf8(b"b\'\xc2\x86 \x00\x00\x00^\"").unwrap(); + assert!(s.parse::().is_err()); +} + +#[test] +fn punct_before_comment() { + let mut tts = TokenStream::from_str("~// comment").unwrap().into_iter(); + match tts.next().unwrap() { + TokenTree::Punct(tt) => { + assert_eq!(tt.as_char(), '~'); + assert_eq!(tt.spacing(), Spacing::Alone); + } + wrong => panic!("wrong token {:?}", wrong), + } +} + +#[test] +fn joint_last_token() { + // This test verifies that we match the behavior of libproc_macro *not* in + // the range nightly-2020-09-06 through nightly-2020-09-10, in which this + // behavior was temporarily broken. + // See https://github.com/rust-lang/rust/issues/76399 + + let joint_punct = Punct::new(':', Spacing::Joint); + let stream = TokenStream::from(TokenTree::Punct(joint_punct)); + let TokenTree::Punct(punct) = stream.into_iter().next().unwrap() else { + unreachable!(); + }; + assert_eq!(punct.spacing(), Spacing::Joint); +} + +#[test] +fn raw_identifier() { + let mut tts = TokenStream::from_str("r#dyn").unwrap().into_iter(); + match tts.next().unwrap() { + TokenTree::Ident(raw) => assert_eq!("r#dyn", raw.to_string()), + wrong => panic!("wrong token {:?}", wrong), + } + assert!(tts.next().is_none()); +} + +#[test] +fn test_display_ident() { + let ident = Ident::new("proc_macro", Span::call_site()); + assert_eq!(format!("{ident}"), "proc_macro"); + assert_eq!(format!("{ident:-^14}"), "proc_macro"); + + let ident = Ident::new_raw("proc_macro", Span::call_site()); + assert_eq!(format!("{ident}"), "r#proc_macro"); + assert_eq!(format!("{ident:-^14}"), "r#proc_macro"); +} + +#[test] +fn test_debug_ident() { + let ident = Ident::new("proc_macro", Span::call_site()); + let expected = if cfg!(span_locations) { + "Ident { sym: proc_macro }" + } else { + "Ident(proc_macro)" + }; + assert_eq!(expected, format!("{:?}", ident)); + + let ident = Ident::new_raw("proc_macro", Span::call_site()); + let expected = if cfg!(span_locations) { + "Ident { sym: r#proc_macro }" + } else { + "Ident(r#proc_macro)" + }; + assert_eq!(expected, format!("{:?}", ident)); +} + +#[test] +fn test_display_tokenstream() { + let tts = TokenStream::from_str("[a + 1]").unwrap(); + assert_eq!(format!("{tts}"), "[a + 1]"); + assert_eq!(format!("{tts:-^5}"), "[a + 1]"); +} + +#[test] +fn test_debug_tokenstream() { + let tts = TokenStream::from_str("[a + 1]").unwrap(); + + #[cfg(not(span_locations))] + let expected = "\ +TokenStream [ + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + sym: a, + }, + Punct { + char: '+', + spacing: Alone, + }, + Literal { + lit: 1, + }, + ], + }, +]\ + "; + + #[cfg(not(span_locations))] + let expected_before_trailing_commas = "\ +TokenStream [ + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + sym: a + }, + Punct { + char: '+', + spacing: Alone + }, + Literal { + lit: 1 + } + ] + } +]\ + "; + + #[cfg(span_locations)] + let expected = "\ +TokenStream [ + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + sym: a, + span: bytes(2..3), + }, + Punct { + char: '+', + spacing: Alone, + span: bytes(4..5), + }, + Literal { + lit: 1, + span: bytes(6..7), + }, + ], + span: bytes(1..8), + }, +]\ + "; + + #[cfg(span_locations)] + let expected_before_trailing_commas = "\ +TokenStream [ + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + sym: a, + span: bytes(2..3) + }, + Punct { + char: '+', + spacing: Alone, + span: bytes(4..5) + }, + Literal { + lit: 1, + span: bytes(6..7) + } + ], + span: bytes(1..8) + } +]\ + "; + + let actual = format!("{:#?}", tts); + if actual.ends_with(",\n]") { + assert_eq!(expected, actual); + } else { + assert_eq!(expected_before_trailing_commas, actual); + } +} + +#[test] +fn default_tokenstream_is_empty() { + let default_token_stream = ::default(); + + assert!(default_token_stream.is_empty()); +} + +#[test] +fn tokenstream_size_hint() { + let tokens = "a b (c d) e".parse::().unwrap(); + + assert_eq!(tokens.into_iter().size_hint(), (4, Some(4))); +} + +#[test] +fn tuple_indexing() { + // This behavior may change depending on https://github.com/rust-lang/rust/pull/71322 + let mut tokens = "tuple.0.0".parse::().unwrap().into_iter(); + assert_eq!("tuple", tokens.next().unwrap().to_string()); + assert_eq!(".", tokens.next().unwrap().to_string()); + assert_eq!("0.0", tokens.next().unwrap().to_string()); + assert!(tokens.next().is_none()); +} + +#[cfg(span_locations)] +#[test] +fn non_ascii_tokens() { + check_spans("// abc", &[]); + check_spans("// ábc", &[]); + check_spans("// abc x", &[]); + check_spans("// ábc x", &[]); + check_spans("/* abc */ x", &[(1, 10, 1, 11)]); + check_spans("/* ábc */ x", &[(1, 10, 1, 11)]); + check_spans("/* ab\nc */ x", &[(2, 5, 2, 6)]); + check_spans("/* áb\nc */ x", &[(2, 5, 2, 6)]); + check_spans("/*** abc */ x", &[(1, 12, 1, 13)]); + check_spans("/*** ábc */ x", &[(1, 12, 1, 13)]); + check_spans(r#""abc""#, &[(1, 0, 1, 5)]); + check_spans(r#""ábc""#, &[(1, 0, 1, 5)]); + check_spans(r##"r#"abc"#"##, &[(1, 0, 1, 8)]); + check_spans(r##"r#"ábc"#"##, &[(1, 0, 1, 8)]); + check_spans("r#\"a\nc\"#", &[(1, 0, 2, 3)]); + check_spans("r#\"á\nc\"#", &[(1, 0, 2, 3)]); + check_spans("'a'", &[(1, 0, 1, 3)]); + check_spans("'á'", &[(1, 0, 1, 3)]); + check_spans("//! abc", &[(1, 0, 1, 7), (1, 0, 1, 7), (1, 0, 1, 7)]); + check_spans("//! ábc", &[(1, 0, 1, 7), (1, 0, 1, 7), (1, 0, 1, 7)]); + check_spans("//! abc\n", &[(1, 0, 1, 7), (1, 0, 1, 7), (1, 0, 1, 7)]); + check_spans("//! ábc\n", &[(1, 0, 1, 7), (1, 0, 1, 7), (1, 0, 1, 7)]); + check_spans("/*! abc */", &[(1, 0, 1, 10), (1, 0, 1, 10), (1, 0, 1, 10)]); + check_spans("/*! ábc */", &[(1, 0, 1, 10), (1, 0, 1, 10), (1, 0, 1, 10)]); + check_spans("/*! a\nc */", &[(1, 0, 2, 4), (1, 0, 2, 4), (1, 0, 2, 4)]); + check_spans("/*! á\nc */", &[(1, 0, 2, 4), (1, 0, 2, 4), (1, 0, 2, 4)]); + check_spans("abc", &[(1, 0, 1, 3)]); + check_spans("ábc", &[(1, 0, 1, 3)]); + check_spans("ábć", &[(1, 0, 1, 3)]); + check_spans("abc// foo", &[(1, 0, 1, 3)]); + check_spans("ábc// foo", &[(1, 0, 1, 3)]); + check_spans("ábć// foo", &[(1, 0, 1, 3)]); + check_spans("b\"a\\\n c\"", &[(1, 0, 2, 3)]); +} + +#[cfg(span_locations)] +fn check_spans(p: &str, mut lines: &[(usize, usize, usize, usize)]) { + let ts = p.parse::().unwrap(); + check_spans_internal(ts, &mut lines); + assert!(lines.is_empty(), "leftover ranges: {:?}", lines); +} + +#[cfg(span_locations)] +fn check_spans_internal(ts: TokenStream, lines: &mut &[(usize, usize, usize, usize)]) { + for i in ts { + if let Some((&(sline, scol, eline, ecol), rest)) = lines.split_first() { + *lines = rest; + + let start = i.span().start(); + assert_eq!(start.line, sline, "sline did not match for {}", i); + assert_eq!(start.column, scol, "scol did not match for {}", i); + + let end = i.span().end(); + assert_eq!(end.line, eline, "eline did not match for {}", i); + assert_eq!(end.column, ecol, "ecol did not match for {}", i); + + if let TokenTree::Group(g) = i { + check_spans_internal(g.stream().clone(), lines); + } + } + } +} + +#[test] +fn whitespace() { + // space, horizontal tab, vertical tab, form feed, carriage return, line + // feed, non-breaking space, left-to-right mark, right-to-left mark + let various_spaces = " \t\u{b}\u{c}\r\n\u{a0}\u{200e}\u{200f}"; + let tokens = various_spaces.parse::().unwrap(); + assert_eq!(tokens.into_iter().count(), 0); + + let lone_carriage_returns = " \r \r\r\n "; + lone_carriage_returns.parse::().unwrap(); +} + +#[test] +fn byte_order_mark() { + let string = "\u{feff}foo"; + let tokens = string.parse::().unwrap(); + match tokens.into_iter().next().unwrap() { + TokenTree::Ident(ident) => assert_eq!(ident, "foo"), + _ => unreachable!(), + } + + let string = "foo\u{feff}"; + string.parse::().unwrap_err(); +} + +#[cfg(span_locations)] +fn create_span() -> proc_macro2::Span { + let tts: TokenStream = "1".parse().unwrap(); + match tts.into_iter().next().unwrap() { + TokenTree::Literal(literal) => literal.span(), + _ => unreachable!(), + } +} + +#[cfg(span_locations)] +#[test] +fn test_invalidate_current_thread_spans() { + let actual = format!("{:#?}", create_span()); + assert_eq!(actual, "bytes(1..2)"); + let actual = format!("{:#?}", create_span()); + assert_eq!(actual, "bytes(3..4)"); + + proc_macro2::extra::invalidate_current_thread_spans(); + + let actual = format!("{:#?}", create_span()); + // Test that span offsets have been reset after the call + // to invalidate_current_thread_spans() + assert_eq!(actual, "bytes(1..2)"); +} + +#[cfg(span_locations)] +#[test] +#[should_panic(expected = "Invalid span with no related FileInfo!")] +fn test_use_span_after_invalidation() { + let span = create_span(); + + proc_macro2::extra::invalidate_current_thread_spans(); + + span.source_text(); +} diff --git a/third_party/crates/proc-macro2-1.0.107/tests/test_fmt.rs b/third_party/crates/proc-macro2-1.0.107/tests/test_fmt.rs new file mode 100644 index 0000000..5213b81 --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/tests/test_fmt.rs @@ -0,0 +1,26 @@ +use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream, TokenTree}; +use std::iter; + +#[test] +fn test_fmt_group() { + let ident = Ident::new("x", Span::call_site()); + let inner = TokenStream::from_iter(iter::once(TokenTree::Ident(ident))); + let parens_empty = Group::new(Delimiter::Parenthesis, TokenStream::new()); + let parens_nonempty = Group::new(Delimiter::Parenthesis, inner.clone()); + let brackets_empty = Group::new(Delimiter::Bracket, TokenStream::new()); + let brackets_nonempty = Group::new(Delimiter::Bracket, inner.clone()); + let braces_empty = Group::new(Delimiter::Brace, TokenStream::new()); + let braces_nonempty = Group::new(Delimiter::Brace, inner.clone()); + let none_empty = Group::new(Delimiter::None, TokenStream::new()); + let none_nonempty = Group::new(Delimiter::None, inner); + + // Matches libproc_macro. + assert_eq!("()", parens_empty.to_string()); + assert_eq!("(x)", parens_nonempty.to_string()); + assert_eq!("[]", brackets_empty.to_string()); + assert_eq!("[x]", brackets_nonempty.to_string()); + assert_eq!("{ }", braces_empty.to_string()); + assert_eq!("{ x }", braces_nonempty.to_string()); + assert_eq!("", none_empty.to_string()); + assert_eq!("x", none_nonempty.to_string()); +} diff --git a/third_party/crates/proc-macro2-1.0.107/tests/test_size.rs b/third_party/crates/proc-macro2-1.0.107/tests/test_size.rs new file mode 100644 index 0000000..3361847 --- /dev/null +++ b/third_party/crates/proc-macro2-1.0.107/tests/test_size.rs @@ -0,0 +1,79 @@ +#![allow(unused_attributes)] + +extern crate proc_macro; + +use std::mem; + +#[cfg_attr(not(target_pointer_width = "64"), ignore = "only applicable to 64-bit")] +#[cfg_attr(randomize_layout, ignore = "disabled due to randomized layout")] +#[test] +fn test_proc_macro_size() { + assert_eq!(mem::size_of::(), 4); + assert_eq!(mem::size_of::>(), 4); + assert_eq!(mem::size_of::(), 20); + assert_eq!(mem::size_of::(), 12); + assert_eq!(mem::size_of::(), 8); + assert_eq!(mem::size_of::(), 16); + assert_eq!(mem::size_of::(), 4); +} + +#[cfg_attr(not(target_pointer_width = "64"), ignore = "only applicable to 64-bit")] +#[cfg_attr(randomize_layout, ignore = "disabled due to randomized layout")] +#[cfg_attr(wrap_proc_macro, ignore = "wrapper mode")] +#[cfg_attr(span_locations, ignore = "span locations are on")] +#[test] +fn test_proc_macro2_fallback_size_without_locations() { + assert_eq!(mem::size_of::(), 0); + assert_eq!(mem::size_of::>(), 1); + assert_eq!(mem::size_of::(), 16); + assert_eq!(mem::size_of::(), 24); + assert_eq!(mem::size_of::(), 8); + assert_eq!(mem::size_of::(), 24); + assert_eq!(mem::size_of::(), 8); +} + +#[cfg_attr(not(target_pointer_width = "64"), ignore = "only applicable to 64-bit")] +#[cfg_attr(randomize_layout, ignore = "disabled due to randomized layout")] +#[cfg_attr(wrap_proc_macro, ignore = "wrapper mode")] +#[cfg_attr(not(span_locations), ignore = "span locations are off")] +#[test] +fn test_proc_macro2_fallback_size_with_locations() { + assert_eq!(mem::size_of::(), 8); + assert_eq!(mem::size_of::>(), 12); + assert_eq!(mem::size_of::(), 24); + assert_eq!(mem::size_of::(), 32); + assert_eq!(mem::size_of::(), 16); + assert_eq!(mem::size_of::(), 32); + assert_eq!(mem::size_of::(), 8); +} + +#[rustversion::attr(before(1.71), ignore = "requires Rust 1.71+")] +#[cfg_attr(not(target_pointer_width = "64"), ignore = "only applicable to 64-bit")] +#[cfg_attr(randomize_layout, ignore = "disabled due to randomized layout")] +#[cfg_attr(not(wrap_proc_macro), ignore = "fallback mode")] +#[cfg_attr(span_locations, ignore = "span locations are on")] +#[test] +fn test_proc_macro2_wrapper_size_without_locations() { + assert_eq!(mem::size_of::(), 4); + assert_eq!(mem::size_of::>(), 8); + assert_eq!(mem::size_of::(), 24); + assert_eq!(mem::size_of::(), 24); + assert_eq!(mem::size_of::(), 12); + assert_eq!(mem::size_of::(), 24); + assert_eq!(mem::size_of::(), 32); +} + +#[cfg_attr(not(target_pointer_width = "64"), ignore = "only applicable to 64-bit")] +#[cfg_attr(randomize_layout, ignore = "disabled due to randomized layout")] +#[cfg_attr(not(wrap_proc_macro), ignore = "fallback mode")] +#[cfg_attr(not(span_locations), ignore = "span locations are off")] +#[test] +fn test_proc_macro2_wrapper_size_with_locations() { + assert_eq!(mem::size_of::(), 12); + assert_eq!(mem::size_of::>(), 12); + assert_eq!(mem::size_of::(), 32); + assert_eq!(mem::size_of::(), 32); + assert_eq!(mem::size_of::(), 20); + assert_eq!(mem::size_of::(), 32); + assert_eq!(mem::size_of::(), 32); +} diff --git a/third_party/crates/quote-1.0.47/.cargo-checksum.json b/third_party/crates/quote-1.0.47/.cargo-checksum.json new file mode 100644 index 0000000..2afc2bb --- /dev/null +++ b/third_party/crates/quote-1.0.47/.cargo-checksum.json @@ -0,0 +1 @@ +{"$comment":"This file only protects against accidental modifications. It is not a security mechanism and does not protect against malicious changes.","files":{".cargo_vcs_info.json":"1452b78f41bb8c7dbf526da57f134ac6d75cf80b7cc539494bab5e133907ce0e",".github/FUNDING.yml":"b017158736b3c9751a2d21edfce7fe61c8954e2fced8da8dd3013c2f3e295bd9",".github/workflows/ci.yml":"fb61965972f379dbd9bd98ea5d45ffd67fd79b30e71ef667f69e8b65134923c2","Cargo.lock":"a8d837a5066c75ed2af8a982eb6f8ebdfb96f94ddb06978fec45827f4ea1348c","Cargo.toml":"13d8c50837f14aff48cd622349f98fb2c46350b7a0c08fd574cf7de4def27d06","Cargo.toml.orig":"acbbe8c10dc81f648339333c8fa3e0aa787ad5887b105d1947bc522553d87d73","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"9d6af721967088b8263c0544c0c3c459206998252dd5632a3bdf87cb27ec92be","build.rs":"cd6808c02e476b09a520105e2c6f6d325cccb1ecd542cbbcc836a0ae6f6fb0f1","rust-toolchain.toml":"6bbb61302978c736b2da03e4fb40e3beab908f85d533ab46fd541e637b5f3e0f","src/ext.rs":"dabcf1dbf9a81c2dccbfb85f81a08120f5a15be40616d51434ed4ebdfe0c7283","src/format.rs":"662db1f14106d79aacab400a3176a75989a4437ecaaa85ab88cd9a40b750cc5b","src/ident_fragment.rs":"eed1a7407182c00ddfdc98741eaa6e234a6d2c01755e95f943b27926b8c92243","src/lib.rs":"e01ca26adfe51a087813d1fc1154efd8a8c9cb5b5a81f314194b4904a4422c71","src/runtime.rs":"fdb7986b31141627408b51381607f66ef4b69dd81b080c2f6489da267e96b2ba","src/spanned.rs":"713678bf5cb3b4bf2f119dcf64d188a63dc59455a724c3d2567ceab83b734d73","src/to_tokens.rs":"1b07b676afce2f666bac6f454758d066758033fc85e9cd9d2d12d58ad2eb36e1","tests/compiletest.rs":"4e381aa8ca3eabb7ac14d1e0c3700b3223e47640547a6988cfa13ad68255f60f","tests/test.rs":"023d6b57ba5ba199a04d9757e3b1464c2bc09579b035ea82c047e08d89d19226","tests/ui/does-not-have-iter-interpolated-dup.rs":"ad13eea21d4cdd2ab6c082f633392e1ff20fb0d1af5f2177041e0bf7f30da695","tests/ui/does-not-have-iter-interpolated-dup.stderr":"c7bbbc8860b9ec0e87e725412a139841c3046aaf465f7190c94f935ab037a996","tests/ui/does-not-have-iter-interpolated.rs":"83a5b3f240651adcbe4b6e51076d76d653ad439b37442cf4054f1fd3c073f3b7","tests/ui/does-not-have-iter-interpolated.stderr":"6ca839345f8119f7eb3acd2fc6a37833dbcc861c02d8961727db01a29318fcc6","tests/ui/does-not-have-iter-separated.rs":"fe413c48331d5e3a7ae5fef6a5892a90c72f610d54595879eb49d0a94154ba3f","tests/ui/does-not-have-iter-separated.stderr":"ff2312aa4623e79eb7f5810cf0e6d992cd57779f0a01c5855a92a1f102086123","tests/ui/does-not-have-iter.rs":"09dc9499d861b63cebb0848b855b78e2dc9497bfde37ba6339f3625ae009a62f","tests/ui/does-not-have-iter.stderr":"21408398d12876b82416cfd57b7919ca4210f5fb8f79d7d921b2bfed5879ac4d","tests/ui/not-quotable.rs":"5759d0884943417609f28faadc70254a3e2fd3d9bd6ff7297a3fb70a77fafd8a","tests/ui/not-quotable.stderr":"a9748bc9a0a72a17f9c1f96e9b12be3686e9d7d51f120796516e26e5cebf62ad","tests/ui/not-repeatable.rs":"a4b115c04e4e41049a05f5b69450503fbffeba031218b4189cb931839f7f9a9c","tests/ui/not-repeatable.stderr":"72105d3dec4e8ed2a657db7d397e30d452c26c1488cb1e18e23c2d1d137a6f6d","tests/ui/wrong-type-span.rs":"6195e35ea844c0c52ba1cff5d790c3a371af6915d137d377834ad984229ef9ea","tests/ui/wrong-type-span.stderr":"cad072e40e0ecc04f375122ae41aede2f0da2a9244492b3fcf70249e59d1b128"},"package":"1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"} \ No newline at end of file diff --git a/third_party/crates/quote-1.0.47/.cargo_vcs_info.json b/third_party/crates/quote-1.0.47/.cargo_vcs_info.json new file mode 100644 index 0000000..3994db5 --- /dev/null +++ b/third_party/crates/quote-1.0.47/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "723dcb47d3f0ddc896e17287c8a8d3f2ea2317d5" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/third_party/crates/quote-1.0.47/.github/FUNDING.yml b/third_party/crates/quote-1.0.47/.github/FUNDING.yml new file mode 100644 index 0000000..7507077 --- /dev/null +++ b/third_party/crates/quote-1.0.47/.github/FUNDING.yml @@ -0,0 +1 @@ +github: dtolnay diff --git a/third_party/crates/quote-1.0.47/.github/workflows/ci.yml b/third_party/crates/quote-1.0.47/.github/workflows/ci.yml new file mode 100644 index 0000000..f3dbf99 --- /dev/null +++ b/third_party/crates/quote-1.0.47/.github/workflows/ci.yml @@ -0,0 +1,112 @@ +name: CI + +on: + push: + pull_request: + workflow_dispatch: + schedule: [cron: "40 1 * * *"] + +permissions: + contents: read + +env: + RUSTFLAGS: -Dwarnings + +jobs: + pre_ci: + uses: dtolnay/.github/.github/workflows/pre_ci.yml@master + + test: + name: Rust ${{matrix.rust}} + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + rust: [nightly, stable, beta, 1.85.0, 1.71.0] + timeout-minutes: 45 + steps: + - uses: actions/checkout@v7 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{matrix.rust}} + components: rust-src + - name: Enable type layout randomization + run: echo RUSTFLAGS=${RUSTFLAGS}\ -Zrandomize-layout >> $GITHUB_ENV + if: matrix.rust == 'nightly' + - run: cargo check + - run: cargo test + if: matrix.rust != '1.71.0' + - run: cargo run --manifest-path benches/Cargo.toml + - uses: actions/upload-artifact@v7 + if: matrix.rust == 'nightly' && always() + with: + name: Cargo.lock + path: Cargo.lock + continue-on-error: true + + minimal: + name: Minimal versions + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@v7 + - uses: dtolnay/rust-toolchain@nightly + - run: cargo generate-lockfile -Z minimal-versions + - run: cargo check --locked + + doc: + name: Documentation + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + timeout-minutes: 45 + env: + RUSTDOCFLAGS: -Dwarnings + steps: + - uses: actions/checkout@v7 + - uses: dtolnay/rust-toolchain@nightly + with: + components: rust-src + - uses: dtolnay/install@cargo-docs-rs + - run: cargo docs-rs + + clippy: + name: Clippy + runs-on: ubuntu-latest + if: github.event_name != 'pull_request' + timeout-minutes: 45 + steps: + - uses: actions/checkout@v7 + - uses: dtolnay/rust-toolchain@nightly + with: + components: clippy, rust-src + - run: cargo clippy --tests --workspace -- -Dclippy::all -Dclippy::pedantic + + miri: + name: Miri + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@v7 + - uses: dtolnay/rust-toolchain@miri + - run: cargo miri setup + - run: cargo miri test + 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@v7 + - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/install@cargo-outdated + - run: cargo outdated --workspace --exit-code 1 diff --git a/third_party/crates/quote-1.0.47/BUILD.bazel b/third_party/crates/quote-1.0.47/BUILD.bazel new file mode 100644 index 0000000..f0fe020 --- /dev/null +++ b/third_party/crates/quote-1.0.47/BUILD.bazel @@ -0,0 +1,186 @@ +############################################################################### +# @generated +# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To +# regenerate this file, run the following: +# +# bazel run @@//third_party:vendor_crates +############################################################################### + +load( + "@rules_rust//cargo:defs.bzl", + "cargo_build_script", + "cargo_toml_env_vars", +) +load("@rules_rust//rust:defs.bzl", "rust_library") + +package(default_visibility = ["//visibility:public"]) + +cargo_toml_env_vars( + name = "cargo_toml_env_vars", + src = "Cargo.toml", +) + +rust_library( + name = "quote", + srcs = glob( + include = ["**/*.rs"], + allow_empty = False, + ), + compile_data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + crate_features = [ + "proc-macro", + ], + crate_root = "src/lib.rs", + edition = "2021", + rustc_env_files = [ + ":cargo_toml_env_vars", + ], + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=quote", + "manual", + "noclippy", + "norustfmt", + ], + target_compatible_with = select({ + "@rules_rust//rust/platform:aarch64-apple-darwin": [], + "@rules_rust//rust/platform:aarch64-apple-ios": [], + "@rules_rust//rust/platform:aarch64-apple-ios-macabi": [], + "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], + "@rules_rust//rust/platform:aarch64-linux-android": [], + "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], + "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], + "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-none": [], + "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], + "@rules_rust//rust/platform:aarch64-unknown-uefi": [], + "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], + "@rules_rust//rust/platform:armv7-linux-androideabi": [], + "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:i686-apple-darwin": [], + "@rules_rust//rust/platform:i686-linux-android": [], + "@rules_rust//rust/platform:i686-pc-windows-msvc": [], + "@rules_rust//rust/platform:i686-unknown-freebsd": [], + "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], + "@rules_rust//rust/platform:loongarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:mips-unknown-linux-gnu": [], + "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv32imac-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], + "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-netbsd": [], + "@rules_rust//rust/platform:sparc64-unknown-openbsd": [], + "@rules_rust//rust/platform:thumbv6m-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabihf": [], + "@rules_rust//rust/platform:thumbv7m-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabihf": [], + "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], + "@rules_rust//rust/platform:wasm32-unknown-unknown": [], + "@rules_rust//rust/platform:wasm32-wasip1": [], + "@rules_rust//rust/platform:wasm32-wasip1-threads": [], + "@rules_rust//rust/platform:wasm32-wasip2": [], + "@rules_rust//rust/platform:x86_64-apple-darwin": [], + "@rules_rust//rust/platform:x86_64-apple-ios": [], + "@rules_rust//rust/platform:x86_64-apple-ios-macabi": [], + "@rules_rust//rust/platform:x86_64-linux-android": [], + "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], + "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], + "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], + "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-none": [], + "@rules_rust//rust/platform:x86_64-unknown-uefi": [], + "//conditions:default": ["@platforms//:incompatible"], + }), + version = "1.0.47", + deps = [ + ":build_script_build", + "//third_party/crates/proc-macro2-1.0.107:proc_macro2", + ], +) + +cargo_build_script( + name = "_bs", + srcs = glob( + include = ["**/*.rs"], + allow_empty = False, + ), + build_script_env_files = [ + ":cargo_toml_env_vars", + ], + compile_data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + "**/*.rs", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + crate_features = [ + "proc-macro", + ], + crate_name = "build_script_build", + crate_root = "build.rs", + data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + edition = "2021", + emit_warnings = False, + pkg_name = "quote", + rustc_env_files = [ + ":cargo_toml_env_vars", + ], + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=quote", + "manual", + "noclippy", + "norustfmt", + ], + version = "1.0.47", + visibility = ["//visibility:private"], +) + +alias( + name = "build_script_build", + actual = ":_bs", + tags = ["manual"], +) diff --git a/third_party/crates/quote-1.0.47/Cargo.lock b/third_party/crates/quote-1.0.47/Cargo.lock new file mode 100644 index 0000000..90c5341 --- /dev/null +++ b/third_party/crates/quote-1.0.47/Cargo.lock @@ -0,0 +1,256 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "dissimilar" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aeda16ab4059c5fd2a83f2b9c9e9c981327b18aa8e3b313f7e6563799d4f093e" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "quote" +version = "1.0.47" +dependencies = [ + "proc-macro2", + "rustversion", + "trybuild", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote 1.0.46", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + +[[package]] +name = "syn" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fac314a64dc9a36e61a9eb4261a5e9bbfbc922b27e518af97bc32b926cf967" +dependencies = [ + "proc-macro2", + "quote 1.0.46", + "unicode-ident", +] + +[[package]] +name = "target-triple" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3a6bfce3d99adfa72d24750a61f782f3036a81e7f86d8841ee1326deaebd171" + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "toml" +version = "1.1.3+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53c96ecdfa941c8fc4fcaed14f99ada8ebed502eef533015095a07e3301d4c3c" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" + +[[package]] +name = "trybuild" +version = "1.0.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06649c6f63d86604ba0c8950d5a1829fc9a17afd70fc6629f481d75b6a624c78" +dependencies = [ + "dissimilar", + "glob", + "serde", + "serde_derive", + "serde_json", + "target-triple", + "termcolor", + "toml", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "winnow" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/third_party/crates/quote-1.0.47/Cargo.toml b/third_party/crates/quote-1.0.47/Cargo.toml new file mode 100644 index 0000000..bfedb01 --- /dev/null +++ b/third_party/crates/quote-1.0.47/Cargo.toml @@ -0,0 +1,70 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.71" +name = "quote" +version = "1.0.47" +authors = ["David Tolnay "] +build = "build.rs" +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Quasi-quoting macro quote!(...)" +documentation = "https://docs.rs/quote/" +readme = "README.md" +keywords = [ + "macros", + "syn", +] +categories = ["development-tools::procedural-macro-helpers"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/dtolnay/quote" + +[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", +] + +[features] +default = ["proc-macro"] +proc-macro = ["proc-macro2/proc-macro"] + +[lib] +name = "quote" +path = "src/lib.rs" + +[[test]] +name = "compiletest" +path = "tests/compiletest.rs" + +[[test]] +name = "test" +path = "tests/test.rs" + +[dependencies.proc-macro2] +version = "1.0.80" +default-features = false + +[dev-dependencies.rustversion] +version = "1.0" + +[dev-dependencies.trybuild] +version = "1.0.108" +features = ["diff"] diff --git a/third_party/crates/quote-1.0.47/Cargo.toml.orig b/third_party/crates/quote-1.0.47/Cargo.toml.orig new file mode 100644 index 0000000..584ff9f --- /dev/null +++ b/third_party/crates/quote-1.0.47/Cargo.toml.orig @@ -0,0 +1,39 @@ +[package] +name = "quote" +version = "1.0.47" +authors = ["David Tolnay "] +autobenches = false +categories = ["development-tools::procedural-macro-helpers"] +description = "Quasi-quoting macro quote!(...)" +documentation = "https://docs.rs/quote/" +edition = "2021" +keywords = ["macros", "syn"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/dtolnay/quote" +rust-version = "1.71" + +[dependencies] +proc-macro2 = { version = "1.0.80", default-features = false } + +[dev-dependencies] +rustversion = "1.0" +trybuild = { version = "1.0.108", features = ["diff"] } + +[features] +default = ["proc-macro"] +# Disabling the proc-macro feature removes the dynamic library dependency on +# libproc_macro in the rustc compiler. +proc-macro = ["proc-macro2/proc-macro"] + +[workspace] +members = ["benches"] + +[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", +] diff --git a/third_party/crates/quote-1.0.47/LICENSE-APACHE b/third_party/crates/quote-1.0.47/LICENSE-APACHE new file mode 100644 index 0000000..1b5ec8b --- /dev/null +++ b/third_party/crates/quote-1.0.47/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/third_party/crates/quote-1.0.47/LICENSE-MIT b/third_party/crates/quote-1.0.47/LICENSE-MIT new file mode 100644 index 0000000..31aa793 --- /dev/null +++ b/third_party/crates/quote-1.0.47/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/crates/quote-1.0.47/README.md b/third_party/crates/quote-1.0.47/README.md new file mode 100644 index 0000000..62585db --- /dev/null +++ b/third_party/crates/quote-1.0.47/README.md @@ -0,0 +1,270 @@ +Rust Quasi-Quoting +================== + +[github](https://github.com/dtolnay/quote) +[crates.io](https://crates.io/crates/quote) +[docs.rs](https://docs.rs/quote) +[build status](https://github.com/dtolnay/quote/actions?query=branch%3Amaster) + +This crate provides the [`quote!`] macro for turning Rust syntax tree data +structures into tokens of source code. + +[`quote!`]: https://docs.rs/quote/1.0/quote/macro.quote.html + +Procedural macros in Rust receive a stream of tokens as input, execute arbitrary +Rust code to determine how to manipulate those tokens, and produce a stream of +tokens to hand back to the compiler to compile into the caller's crate. +Quasi-quoting is a solution to one piece of that — producing tokens to +return to the compiler. + +The idea of quasi-quoting is that we write *code* that we treat as *data*. +Within the `quote!` macro, we can write what looks like code to our text editor +or IDE. We get all the benefits of the editor's brace matching, syntax +highlighting, indentation, and maybe autocompletion. But rather than compiling +that as code into the current crate, we can treat it as data, pass it around, +mutate it, and eventually hand it back to the compiler as tokens to compile into +the macro caller's crate. + +This crate is motivated by the procedural macro use case, but is a +general-purpose Rust quasi-quoting library and is not specific to procedural +macros. + +```toml +[dependencies] +quote = "1.0" +``` + +[*Release notes*](https://github.com/dtolnay/quote/releases) + +
+ +## Syntax + +The quote crate provides a [`quote!`] macro within which you can write Rust code +that gets packaged into a [`TokenStream`] and can be treated as data. You should +think of `TokenStream` as representing a fragment of Rust source code. + +[`TokenStream`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.TokenStream.html + +Within the `quote!` macro, interpolation is done with `#var`. Any type +implementing the [`quote::ToTokens`] trait can be interpolated. This includes +most Rust primitive types as well as most of the syntax tree types from [`syn`]. + +[`quote::ToTokens`]: https://docs.rs/quote/1.0/quote/trait.ToTokens.html +[`syn`]: https://github.com/dtolnay/syn + +```rust +let tokens = quote! { + struct SerializeWith #generics #where_clause { + value: &'a #field_ty, + phantom: core::marker::PhantomData<#item_ty>, + } + + impl #generics serde::Serialize for SerializeWith #generics #where_clause { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + #path(self.value, serializer) + } + } + + SerializeWith { + value: #value, + phantom: core::marker::PhantomData::<#item_ty>, + } +}; +``` + +
+ +## Repetition + +Repetition is done using `#(...)*` or `#(...),*` similar to `macro_rules!`. This +iterates through the elements of any variable interpolated within the repetition +and inserts a copy of the repetition body for each one. The variables in an +interpolation may be a `Vec`, slice, `BTreeSet`, or any `Iterator`. + +- `#(#var)*` — no separators +- `#(#var),*` — the character before the asterisk is used as a separator +- `#( struct #var; )*` — the repetition can contain other things +- `#( #k => println!("{}", #v), )*` — even multiple interpolations + +Note that there is a difference between `#(#var ,)*` and `#(#var),*`—the latter +does not produce a trailing comma. This matches the behavior of delimiters in +`macro_rules!`. + +
+ +## Returning tokens to the compiler + +The `quote!` macro evaluates to an expression of type +`proc_macro2::TokenStream`. Meanwhile Rust procedural macros are expected to +return the type `proc_macro::TokenStream`. + +The difference between the two types is that `proc_macro` types are entirely +specific to procedural macros and cannot ever exist in code outside of a +procedural macro, while `proc_macro2` types may exist anywhere including tests +and non-macro code like main.rs and build.rs. This is why even the procedural +macro ecosystem is largely built around `proc_macro2`, because that ensures the +libraries are unit testable and accessible in non-macro contexts. + +There is a [`From`]-conversion in both directions so returning the output of +`quote!` from a procedural macro usually looks like `tokens.into()` or +`proc_macro::TokenStream::from(tokens)`. + +[`From`]: https://doc.rust-lang.org/std/convert/trait.From.html + +
+ +## Examples + +### Combining quoted fragments + +Usually you don't end up constructing an entire final `TokenStream` in one +piece. Different parts may come from different helper functions. The tokens +produced by `quote!` themselves implement `ToTokens` and so can be interpolated +into later `quote!` invocations to build up a final result. + +```rust +let type_definition = quote! {...}; +let methods = quote! {...}; + +let tokens = quote! { + #type_definition + #methods +}; +``` + +### Constructing identifiers + +Suppose we have an identifier `ident` which came from somewhere in a macro +input and we need to modify it in some way for the macro output. Let's consider +prepending the identifier with an underscore. + +Simply interpolating the identifier next to an underscore will not have the +behavior of concatenating them. The underscore and the identifier will continue +to be two separate tokens as if you had written `_ x`. + +```rust +// incorrect +quote! { + let mut _#ident = 0; +} +``` + +The solution is to build a new identifier token with the correct value. As this +is such a common case, the `format_ident!` macro provides a convenient utility +for doing so correctly. + +```rust +let varname = format_ident!("_{}", ident); +quote! { + let mut #varname = 0; +} +``` + +Alternatively, the APIs provided by Syn and proc-macro2 can be used to directly +build the identifier. This is roughly equivalent to the above, but will not +handle `ident` being a raw identifier. + +```rust +let concatenated = format!("_{}", ident); +let varname = syn::Ident::new(&concatenated, ident.span()); +quote! { + let mut #varname = 0; +} +``` + +### Making method calls + +Let's say our macro requires some type specified in the macro input to have a +constructor called `new`. We have the type in a variable called `field_type` of +type `syn::Type` and want to invoke the constructor. + +```rust +// incorrect +quote! { + let value = #field_type::new(); +} +``` + +This works only sometimes. If `field_type` is `String`, the expanded code +contains `String::new()` which is fine. But if `field_type` is something like +`Vec` then the expanded code is `Vec::new()` which is invalid syntax. +Ordinarily in handwritten Rust we would write `Vec::::new()` but for macros +often the following is more convenient. + +```rust +quote! { + let value = <#field_type>::new(); +} +``` + +This expands to `>::new()` which behaves correctly. + +A similar pattern is appropriate for trait methods. + +```rust +quote! { + let value = <#field_type as core::default::Default>::default(); +} +``` + +
+ +## Hygiene + +Any interpolated tokens preserve the `Span` information provided by their +`ToTokens` implementation. Tokens that originate within a `quote!` invocation +are spanned with [`Span::call_site()`]. + +[`Span::call_site()`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.Span.html#method.call_site + +A different span can be provided explicitly through the [`quote_spanned!`] +macro. + +[`quote_spanned!`]: https://docs.rs/quote/1.0/quote/macro.quote_spanned.html + +
+ +## Non-macro code generators + +When using `quote` in a build.rs or main.rs and writing the output out to a +file, consider having the code generator pass the tokens through [prettyplease] +before writing. This way if an error occurs in the generated code it is +convenient for a human to read and debug. + +Be aware that no kind of hygiene or span information is retained when tokens are +written to a file; the conversion from tokens to source code is lossy. + +Example usage in build.rs: + +```rust +let output = quote! { ... }; +let syntax_tree = syn::parse2(output).unwrap(); +let formatted = prettyplease::unparse(&syntax_tree); + +let out_dir = env::var_os("OUT_DIR").unwrap(); +let dest_path = Path::new(&out_dir).join("out.rs"); +fs::write(dest_path, formatted).unwrap(); +``` + +[prettyplease]: https://github.com/dtolnay/prettyplease + +
+ +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + diff --git a/third_party/crates/quote-1.0.47/build.rs b/third_party/crates/quote-1.0.47/build.rs new file mode 100644 index 0000000..50f98cb --- /dev/null +++ b/third_party/crates/quote-1.0.47/build.rs @@ -0,0 +1,32 @@ +use std::env; +use std::process::Command; +use std::str; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + + let Some(minor) = rustc_minor_version() else { + return; + }; + + if minor >= 77 { + println!("cargo:rustc-check-cfg=cfg(no_diagnostic_namespace)"); + } + + // 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 = 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/third_party/crates/quote-1.0.47/rust-toolchain.toml b/third_party/crates/quote-1.0.47/rust-toolchain.toml new file mode 100644 index 0000000..20fe888 --- /dev/null +++ b/third_party/crates/quote-1.0.47/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +components = ["rust-src"] diff --git a/third_party/crates/quote-1.0.47/src/ext.rs b/third_party/crates/quote-1.0.47/src/ext.rs new file mode 100644 index 0000000..2553717 --- /dev/null +++ b/third_party/crates/quote-1.0.47/src/ext.rs @@ -0,0 +1,138 @@ +use super::ToTokens; +use core::iter; +use proc_macro2::{TokenStream, TokenTree}; + +/// TokenStream extension trait with methods for appending tokens. +/// +/// This trait is sealed and cannot be implemented outside of the `quote` crate. +pub trait TokenStreamExt: private::Sealed { + /// For use by `ToTokens` implementations. + /// + /// Appends the token specified to this list of tokens. + fn append(&mut self, token: U) + where + U: Into; + + /// For use by `ToTokens` implementations. + /// + /// ``` + /// # use quote::{quote, TokenStreamExt, ToTokens}; + /// # use proc_macro2::TokenStream; + /// # + /// struct X; + /// + /// impl ToTokens for X { + /// fn to_tokens(&self, tokens: &mut TokenStream) { + /// tokens.append_all(&[true, false]); + /// } + /// } + /// + /// let tokens = quote!(#X); + /// assert_eq!(tokens.to_string(), "true false"); + /// ``` + fn append_all(&mut self, iter: I) + where + I: IntoIterator, + I::Item: ToTokens; + + /// For use by `ToTokens` implementations. + /// + /// Appends all of the items in the iterator `I`, separated by the tokens + /// `U`. + fn append_separated(&mut self, iter: I, op: U) + where + I: IntoIterator, + I::Item: ToTokens, + U: ToTokens; + + /// For use by `ToTokens` implementations. + /// + /// Appends all tokens in the iterator `I`, appending `U` after each + /// element, including after the last element of the iterator. + fn append_terminated(&mut self, iter: I, term: U) + where + I: IntoIterator, + I::Item: ToTokens, + U: ToTokens; +} + +impl TokenStreamExt for TokenStream { + fn append(&mut self, token: U) + where + U: Into, + { + self.extend(iter::once(token.into())); + } + + fn append_all(&mut self, iter: I) + where + I: IntoIterator, + I::Item: ToTokens, + { + do_append_all(self, iter.into_iter()); + + fn do_append_all(stream: &mut TokenStream, iter: I) + where + I: Iterator, + I::Item: ToTokens, + { + for token in iter { + token.to_tokens(stream); + } + } + } + + fn append_separated(&mut self, iter: I, op: U) + where + I: IntoIterator, + I::Item: ToTokens, + U: ToTokens, + { + do_append_separated(self, iter.into_iter(), op); + + fn do_append_separated(stream: &mut TokenStream, iter: I, op: U) + where + I: Iterator, + I::Item: ToTokens, + U: ToTokens, + { + let mut first = true; + for token in iter { + if !first { + op.to_tokens(stream); + } + first = false; + token.to_tokens(stream); + } + } + } + + fn append_terminated(&mut self, iter: I, term: U) + where + I: IntoIterator, + I::Item: ToTokens, + U: ToTokens, + { + do_append_terminated(self, iter.into_iter(), term); + + fn do_append_terminated(stream: &mut TokenStream, iter: I, term: U) + where + I: Iterator, + I::Item: ToTokens, + U: ToTokens, + { + for token in iter { + token.to_tokens(stream); + term.to_tokens(stream); + } + } + } +} + +mod private { + use proc_macro2::TokenStream; + + pub trait Sealed {} + + impl Sealed for TokenStream {} +} diff --git a/third_party/crates/quote-1.0.47/src/format.rs b/third_party/crates/quote-1.0.47/src/format.rs new file mode 100644 index 0000000..894d146 --- /dev/null +++ b/third_party/crates/quote-1.0.47/src/format.rs @@ -0,0 +1,168 @@ +/// Formatting macro for constructing `Ident`s. +/// +///
+/// +/// # Syntax +/// +/// Syntax is copied from the [`format!`][alloc::format!] macro, supporting both +/// positional and named arguments. +/// +/// Only a limited set of formatting traits are supported. The current mapping +/// of format types to traits is: +/// +/// * `{}` ⇒ [`IdentFragment`] +/// * `{:o}` ⇒ [`Octal`](core::fmt::Octal) +/// * `{:x}` ⇒ [`LowerHex`](core::fmt::LowerHex) +/// * `{:X}` ⇒ [`UpperHex`](core::fmt::UpperHex) +/// * `{:b}` ⇒ [`Binary`](core::fmt::Binary) +/// +/// See [`core::fmt`] for more information. +/// +///
+/// +/// # IdentFragment +/// +/// Unlike `format!`, this macro uses the [`IdentFragment`] formatting trait by +/// default. This trait is like `Display`, with a few differences: +/// +/// * `IdentFragment` is only implemented for a limited set of types, such as +/// unsigned integers and strings. +/// * [`Ident`] arguments will have their `r#` prefixes stripped, if present. +/// +/// [`IdentFragment`]: crate::IdentFragment +/// [`Ident`]: proc_macro2::Ident +/// +///
+/// +/// # Hygiene +/// +/// The [`Span`] of the first `Ident` argument is used as the span of the final +/// identifier, falling back to [`Span::call_site`] when no identifiers are +/// provided. +/// +/// ``` +/// # use quote::format_ident; +/// # let ident = format_ident!("Ident"); +/// // If `ident` is an Ident, the span of `my_ident` will be inherited from it. +/// let my_ident = format_ident!("My{}{}", ident, "IsCool"); +/// assert_eq!(my_ident, "MyIdentIsCool"); +/// ``` +/// +/// Alternatively, the span can be overridden by passing the `span` named +/// argument. +/// +/// ``` +/// # use quote::format_ident; +/// # const IGNORE_TOKENS: &'static str = stringify! { +/// let my_span = /* ... */; +/// # }; +/// # let my_span = proc_macro2::Span::call_site(); +/// format_ident!("MyIdent", span = my_span); +/// ``` +/// +/// [`Span`]: proc_macro2::Span +/// [`Span::call_site`]: proc_macro2::Span::call_site +/// +///


+/// +/// # Panics +/// +/// This method will panic if the resulting formatted string is not a valid +/// identifier. +/// +///
+/// +/// # Examples +/// +/// Composing raw and non-raw identifiers: +/// ``` +/// # use quote::format_ident; +/// let my_ident = format_ident!("My{}", "Ident"); +/// assert_eq!(my_ident, "MyIdent"); +/// +/// let raw = format_ident!("r#Raw"); +/// assert_eq!(raw, "r#Raw"); +/// +/// let my_ident_raw = format_ident!("{}Is{}", my_ident, raw); +/// assert_eq!(my_ident_raw, "MyIdentIsRaw"); +/// ``` +/// +/// Integer formatting options: +/// ``` +/// # use quote::format_ident; +/// let num: u32 = 10; +/// +/// let decimal = format_ident!("Id_{}", num); +/// assert_eq!(decimal, "Id_10"); +/// +/// let octal = format_ident!("Id_{:o}", num); +/// assert_eq!(octal, "Id_12"); +/// +/// let binary = format_ident!("Id_{:b}", num); +/// assert_eq!(binary, "Id_1010"); +/// +/// let lower_hex = format_ident!("Id_{:x}", num); +/// assert_eq!(lower_hex, "Id_a"); +/// +/// let upper_hex = format_ident!("Id_{:X}", num); +/// assert_eq!(upper_hex, "Id_A"); +/// ``` +#[macro_export] +macro_rules! format_ident { + ($fmt:expr) => { + $crate::format_ident_impl!([ + $crate::__private::Option::None, + $fmt + ]) + }; + + ($fmt:expr, $($rest:tt)*) => { + $crate::format_ident_impl!([ + $crate::__private::Option::None, + $fmt + ] $($rest)*) + }; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! format_ident_impl { + // Final state + ([$span:expr, $($fmt:tt)*]) => { + $crate::__private::mk_ident( + &$crate::__private::format!($($fmt)*), + $span, + ) + }; + + // Span argument + ([$old:expr, $($fmt:tt)*] span = $span:expr) => { + $crate::format_ident_impl!([$old, $($fmt)*] span = $span,) + }; + ([$old:expr, $($fmt:tt)*] span = $span:expr, $($rest:tt)*) => { + $crate::format_ident_impl!([ + $crate::__private::Option::Some::<$crate::__private::Span>($span), + $($fmt)* + ] $($rest)*) + }; + + // Named argument + ([$span:expr, $($fmt:tt)*] $name:ident = $arg:expr) => { + $crate::format_ident_impl!([$span, $($fmt)*] $name = $arg,) + }; + ([$span:expr, $($fmt:tt)*] $name:ident = $arg:expr, $($rest:tt)*) => { + match $crate::__private::IdentFragmentAdapter(&$arg) { + arg => $crate::format_ident_impl!([$span.or(arg.span()), $($fmt)*, $name = arg] $($rest)*), + } + }; + + // Positional argument + ([$span:expr, $($fmt:tt)*] $arg:expr) => { + $crate::format_ident_impl!([$span, $($fmt)*] $arg,) + }; + ([$span:expr, $($fmt:tt)*] $arg:expr, $($rest:tt)*) => { + match $crate::__private::IdentFragmentAdapter(&$arg) { + arg => $crate::format_ident_impl!([$span.or(arg.span()), $($fmt)*, arg] $($rest)*), + } + }; +} diff --git a/third_party/crates/quote-1.0.47/src/ident_fragment.rs b/third_party/crates/quote-1.0.47/src/ident_fragment.rs new file mode 100644 index 0000000..646c9c7 --- /dev/null +++ b/third_party/crates/quote-1.0.47/src/ident_fragment.rs @@ -0,0 +1,89 @@ +use alloc::borrow::{Cow, ToOwned}; +use alloc::string::{String, ToString}; +use core::fmt; +use proc_macro2::{Ident, Span}; + +/// Specialized formatting trait used by `format_ident!`. +/// +/// [`Ident`] arguments formatted using this trait will have their `r#` prefix +/// stripped, if present. +/// +/// See [`format_ident!`] for more information. +/// +/// [`format_ident!`]: crate::format_ident +pub trait IdentFragment { + /// Format this value as an identifier fragment. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result; + + /// Span associated with this `IdentFragment`. + /// + /// If non-`None`, may be inherited by formatted identifiers. + fn span(&self) -> Option { + None + } +} + +impl IdentFragment for &T { + fn span(&self) -> Option { + ::span(*self) + } + + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + IdentFragment::fmt(*self, f) + } +} + +impl IdentFragment for &mut T { + fn span(&self) -> Option { + ::span(*self) + } + + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + IdentFragment::fmt(*self, f) + } +} + +impl IdentFragment for Ident { + fn span(&self) -> Option { + Some(self.span()) + } + + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let id = self.to_string(); + if let Some(id) = id.strip_prefix("r#") { + fmt::Display::fmt(id, f) + } else { + fmt::Display::fmt(&id[..], f) + } + } +} + +impl IdentFragment for Cow<'_, T> +where + T: IdentFragment + ToOwned + ?Sized, +{ + fn span(&self) -> Option { + T::span(self) + } + + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + T::fmt(self, f) + } +} + +// Limited set of types which this is implemented for, as we want to avoid types +// which will often include non-identifier characters in their `Display` impl. +macro_rules! ident_fragment_display { + ($($T:ty),*) => { + $( + impl IdentFragment for $T { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, f) + } + } + )* + }; +} + +ident_fragment_display!(bool, str, String, char); +ident_fragment_display!(u8, u16, u32, u64, u128, usize); diff --git a/third_party/crates/quote-1.0.47/src/lib.rs b/third_party/crates/quote-1.0.47/src/lib.rs new file mode 100644 index 0000000..4bbe346 --- /dev/null +++ b/third_party/crates/quote-1.0.47/src/lib.rs @@ -0,0 +1,1471 @@ +//! [![github]](https://github.com/dtolnay/quote) [![crates-io]](https://crates.io/crates/quote) [![docs-rs]](https://docs.rs/quote) +//! +//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github +//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust +//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs +//! +//!
+//! +//! This crate provides the [`quote!`] macro for turning Rust syntax tree data +//! structures into tokens of source code. +//! +//! Procedural macros in Rust receive a stream of tokens as input, execute +//! arbitrary Rust code to determine how to manipulate those tokens, and produce +//! a stream of tokens to hand back to the compiler to compile into the caller's +//! crate. Quasi-quoting is a solution to one piece of that — producing +//! tokens to return to the compiler. +//! +//! The idea of quasi-quoting is that we write *code* that we treat as *data*. +//! Within the `quote!` macro, we can write what looks like code to our text +//! editor or IDE. We get all the benefits of the editor's brace matching, +//! syntax highlighting, indentation, and maybe autocompletion. But rather than +//! compiling that as code into the current crate, we can treat it as data, pass +//! it around, mutate it, and eventually hand it back to the compiler as tokens +//! to compile into the macro caller's crate. +//! +//! This crate is motivated by the procedural macro use case, but is a +//! general-purpose Rust quasi-quoting library and is not specific to procedural +//! macros. +//! +//! ```toml +//! [dependencies] +//! quote = "1.0" +//! ``` +//! +//!
+//! +//! # Example +//! +//! The following quasi-quoted block of code is something you might find in [a] +//! procedural macro having to do with data structure serialization. The `#var` +//! syntax performs interpolation of runtime variables into the quoted tokens. +//! Check out the documentation of the [`quote!`] macro for more detail about +//! the syntax. See also the [`quote_spanned!`] macro which is important for +//! implementing hygienic procedural macros. +//! +//! [a]: https://serde.rs/ +//! +//! ``` +//! # use quote::quote; +//! # +//! # let generics = ""; +//! # let where_clause = ""; +//! # let field_ty = ""; +//! # let item_ty = ""; +//! # let path = ""; +//! # let value = ""; +//! # +//! let tokens = quote! { +//! struct SerializeWith #generics #where_clause { +//! value: &'a #field_ty, +//! phantom: core::marker::PhantomData<#item_ty>, +//! } +//! +//! impl #generics serde::Serialize for SerializeWith #generics #where_clause { +//! fn serialize(&self, serializer: S) -> Result +//! where +//! S: serde::Serializer, +//! { +//! #path(self.value, serializer) +//! } +//! } +//! +//! SerializeWith { +//! value: #value, +//! phantom: core::marker::PhantomData::<#item_ty>, +//! } +//! }; +//! ``` +//! +//!
+//! +//! # Non-macro code generators +//! +//! When using `quote` in a build.rs or main.rs and writing the output out to a +//! file, consider having the code generator pass the tokens through +//! [prettyplease] before writing. This way if an error occurs in the generated +//! code it is convenient for a human to read and debug. +//! +//! [prettyplease]: https://github.com/dtolnay/prettyplease + +#![no_std] +#![doc(html_root_url = "https://docs.rs/quote/1.0.47")] +#![allow( + clippy::doc_markdown, + clippy::elidable_lifetime_names, + clippy::items_after_statements, + clippy::missing_errors_doc, + clippy::missing_panics_doc, + clippy::module_name_repetitions, + clippy::needless_lifetimes, + // false positive https://github.com/rust-lang/rust-clippy/issues/6983 + clippy::wrong_self_convention, +)] + +extern crate alloc; +extern crate std; + +#[cfg(feature = "proc-macro")] +extern crate proc_macro; + +mod ext; +mod format; +mod ident_fragment; +mod to_tokens; + +// Not public API. +#[doc(hidden)] +#[path = "runtime.rs"] +pub mod __private; + +pub use crate::ext::TokenStreamExt; +pub use crate::ident_fragment::IdentFragment; +pub use crate::to_tokens::ToTokens; + +// Not public API. +#[doc(hidden)] +pub mod spanned; + +macro_rules! __quote { + ($quote:item) => { + /// The whole point. + /// + /// Performs variable interpolation against the input and produces it as + /// [`proc_macro2::TokenStream`]. + /// + /// Note: for returning tokens to the compiler in a procedural macro, use + /// `.into()` on the result to convert to [`proc_macro::TokenStream`]. + /// + ///
+ /// + /// # Interpolation + /// + /// Variable interpolation is done with `#var` (similar to `$var` in + /// `macro_rules!` macros). This grabs the `var` variable that is currently in + /// scope and inserts it in that location in the output tokens. Any type + /// implementing the [`ToTokens`] trait can be interpolated. This includes most + /// Rust primitive types as well as most of the syntax tree types from the [Syn] + /// crate. + /// + /// [Syn]: https://github.com/dtolnay/syn + /// + /// Repetition is done using `#(...)*` or `#(...),*` again similar to + /// `macro_rules!`. This iterates through the elements of any variable + /// interpolated within the repetition and inserts a copy of the repetition body + /// for each one. The variables in an interpolation may be a `Vec`, slice, + /// `BTreeSet`, or any `Iterator`. + /// + /// - `#(#var)*` — no separators + /// - `#(#var),*` — the character before the asterisk is used as a separator + /// - `#( struct #var; )*` — the repetition can contain other tokens + /// - `#( #k => println!("{}", #v), )*` — even multiple interpolations + /// + ///
+ /// + /// # Hygiene + /// + /// Any interpolated tokens preserve the `Span` information provided by their + /// `ToTokens` implementation. Tokens that originate within the `quote!` + /// invocation are spanned with [`Span::call_site()`]. + /// + /// [`Span::call_site()`]: proc_macro2::Span::call_site + /// + /// A different span can be provided through the [`quote_spanned!`] macro. + /// + ///
+ /// + /// # Return type + /// + /// The macro evaluates to an expression of type `proc_macro2::TokenStream`. + /// Meanwhile Rust procedural macros are expected to return the type + /// `proc_macro::TokenStream`. + /// + /// The difference between the two types is that `proc_macro` types are entirely + /// specific to procedural macros and cannot ever exist in code outside of a + /// procedural macro, while `proc_macro2` types may exist anywhere including + /// tests and non-macro code like main.rs and build.rs. This is why even the + /// procedural macro ecosystem is largely built around `proc_macro2`, because + /// that ensures the libraries are unit testable and accessible in non-macro + /// contexts. + /// + /// There is a [`From`]-conversion in both directions so returning the output of + /// `quote!` from a procedural macro usually looks like `tokens.into()` or + /// `proc_macro::TokenStream::from(tokens)`. + /// + ///
+ /// + /// # Examples + /// + /// ### Procedural macro + /// + /// The structure of a basic procedural macro is as follows. Refer to the [Syn] + /// crate for further useful guidance on using `quote!` as part of a procedural + /// macro. + /// + /// [Syn]: https://github.com/dtolnay/syn + /// + /// ``` + /// # #[cfg(any())] + /// extern crate proc_macro; + /// # extern crate proc_macro2; + /// + /// # #[cfg(any())] + /// use proc_macro::TokenStream; + /// # use proc_macro2::TokenStream; + /// use quote::quote; + /// + /// # const IGNORE_TOKENS: &'static str = stringify! { + /// #[proc_macro_derive(HeapSize)] + /// # }; + /// pub fn derive_heap_size(input: TokenStream) -> TokenStream { + /// // Parse the input and figure out what implementation to generate... + /// # const IGNORE_TOKENS: &'static str = stringify! { + /// let name = /* ... */; + /// let expr = /* ... */; + /// # }; + /// # + /// # let name = 0; + /// # let expr = 0; + /// + /// let expanded = quote! { + /// // The generated impl. + /// impl heapsize::HeapSize for #name { + /// fn heap_size_of_children(&self) -> usize { + /// #expr + /// } + /// } + /// }; + /// + /// // Hand the output tokens back to the compiler. + /// TokenStream::from(expanded) + /// } + /// ``` + /// + ///


+ /// + /// ### Combining quoted fragments + /// + /// Usually you don't end up constructing an entire final `TokenStream` in one + /// piece. Different parts may come from different helper functions. The tokens + /// produced by `quote!` themselves implement `ToTokens` and so can be + /// interpolated into later `quote!` invocations to build up a final result. + /// + /// ``` + /// # use quote::quote; + /// # + /// let type_definition = quote! {...}; + /// let methods = quote! {...}; + /// + /// let tokens = quote! { + /// #type_definition + /// #methods + /// }; + /// ``` + /// + ///


+ /// + /// ### Constructing identifiers + /// + /// Suppose we have an identifier `ident` which came from somewhere in a macro + /// input and we need to modify it in some way for the macro output. Let's + /// consider prepending the identifier with an underscore. + /// + /// Simply interpolating the identifier next to an underscore will not have the + /// behavior of concatenating them. The underscore and the identifier will + /// continue to be two separate tokens as if you had written `_ x`. + /// + /// ```edition2018 + /// # use proc_macro2::{self as syn, Span}; + /// # use quote::quote; + /// # + /// # let ident = syn::Ident::new("i", Span::call_site()); + /// # + /// // incorrect + /// quote! { + /// let mut _#ident = 0; + /// } + /// # ; + /// ``` + /// + /// The solution is to build a new identifier token with the correct value. As + /// this is such a common case, the [`format_ident!`] macro provides a + /// convenient utility for doing so correctly. + /// + /// ``` + /// # use proc_macro2::{Ident, Span}; + /// # use quote::{format_ident, quote}; + /// # + /// # let ident = Ident::new("i", Span::call_site()); + /// # + /// let varname = format_ident!("_{}", ident); + /// quote! { + /// let mut #varname = 0; + /// } + /// # ; + /// ``` + /// + /// Alternatively, the APIs provided by Syn and proc-macro2 can be used to + /// directly build the identifier. This is roughly equivalent to the above, but + /// will not handle `ident` being a raw identifier. + /// + /// ``` + /// # use proc_macro2::{self as syn, Span}; + /// # use quote::quote; + /// # + /// # let ident = syn::Ident::new("i", Span::call_site()); + /// # + /// let concatenated = format!("_{}", ident); + /// let varname = syn::Ident::new(&concatenated, ident.span()); + /// quote! { + /// let mut #varname = 0; + /// } + /// # ; + /// ``` + /// + ///


+ /// + /// ### Making method calls + /// + /// Let's say our macro requires some type specified in the macro input to have + /// a constructor called `new`. We have the type in a variable called + /// `field_type` of type `syn::Type` and want to invoke the constructor. + /// + /// ``` + /// # use quote::quote; + /// # + /// # let field_type = quote!(...); + /// # + /// // incorrect + /// quote! { + /// let value = #field_type::new(); + /// } + /// # ; + /// ``` + /// + /// This works only sometimes. If `field_type` is `String`, the expanded code + /// contains `String::new()` which is fine. But if `field_type` is something + /// like `Vec` then the expanded code is `Vec::new()` which is invalid + /// syntax. Ordinarily in handwritten Rust we would write `Vec::::new()` + /// but for macros often the following is more convenient. + /// + /// ``` + /// # use quote::quote; + /// # + /// # let field_type = quote!(...); + /// # + /// quote! { + /// let value = <#field_type>::new(); + /// } + /// # ; + /// ``` + /// + /// This expands to `>::new()` which behaves correctly. + /// + /// A similar pattern is appropriate for trait methods. + /// + /// ``` + /// # use quote::quote; + /// # + /// # let field_type = quote!(...); + /// # + /// quote! { + /// let value = <#field_type as core::default::Default>::default(); + /// } + /// # ; + /// ``` + /// + ///


+ /// + /// ### Interpolating text inside of doc comments + /// + /// Neither doc comments nor string literals get interpolation behavior in + /// quote: + /// + /// ```compile_fail + /// quote! { + /// /// try to interpolate: #ident + /// /// + /// /// ... + /// } + /// ``` + /// + /// ```compile_fail + /// quote! { + /// #[doc = "try to interpolate: #ident"] + /// } + /// ``` + /// + /// Instead the best way to build doc comments that involve variables is by + /// formatting the doc string literal outside of quote. + /// + /// ```rust + /// # use proc_macro2::{Ident, Span}; + /// # use quote::quote; + /// # + /// # const IGNORE: &str = stringify! { + /// let msg = format!(...); + /// # }; + /// # + /// # let ident = Ident::new("var", Span::call_site()); + /// # let msg = format!("try to interpolate: {}", ident); + /// quote! { + /// #[doc = #msg] + /// /// + /// /// ... + /// } + /// # ; + /// ``` + /// + ///


+ /// + /// ### Indexing into a tuple struct + /// + /// When interpolating indices of a tuple or tuple struct, we need them not to + /// appears suffixed as integer literals by interpolating them as [`syn::Index`] + /// instead. + /// + /// [`syn::Index`]: https://docs.rs/syn/3/syn/struct.Index.html + /// + /// ```compile_fail + /// let i = 0usize..self.fields.len(); + /// + /// // expands to 0 + self.0usize.heap_size() + self.1usize.heap_size() + ... + /// // which is not valid syntax + /// quote! { + /// 0 #( + self.#i.heap_size() )* + /// } + /// ``` + /// + /// ``` + /// # use proc_macro2::{Ident, TokenStream}; + /// # use quote::quote; + /// # + /// # mod syn { + /// # use proc_macro2::{Literal, TokenStream}; + /// # use quote::{ToTokens, TokenStreamExt}; + /// # + /// # pub struct Index(usize); + /// # + /// # impl From for Index { + /// # fn from(i: usize) -> Self { + /// # Index(i) + /// # } + /// # } + /// # + /// # impl ToTokens for Index { + /// # fn to_tokens(&self, tokens: &mut TokenStream) { + /// # tokens.append(Literal::usize_unsuffixed(self.0)); + /// # } + /// # } + /// # } + /// # + /// # struct Struct { + /// # fields: Vec, + /// # } + /// # + /// # impl Struct { + /// # fn example(&self) -> TokenStream { + /// let i = (0..self.fields.len()).map(syn::Index::from); + /// + /// // expands to 0 + self.0.heap_size() + self.1.heap_size() + ... + /// quote! { + /// 0 #( + self.#i.heap_size() )* + /// } + /// # } + /// # } + /// ``` + $quote + }; +} + +#[cfg(doc)] +__quote![ + #[macro_export] + macro_rules! quote { + ($($tt:tt)*) => { + ... + }; + } +]; + +#[cfg(not(doc))] +__quote![ + #[macro_export] + macro_rules! quote { + () => { + $crate::__private::TokenStream::new() + }; + + // Special case rule for a single tt, for performance. + ($tt:tt) => {{ + let mut _s = $crate::__private::TokenStream::new(); + $crate::quote_token!{$tt _s} + _s + }}; + + // Special case rules for two tts, for performance. + (# $var:ident) => {{ + let mut _s = $crate::__private::TokenStream::new(); + $crate::ToTokens::to_tokens(&$var, &mut _s); + _s + }}; + ($tt1:tt $tt2:tt) => {{ + let mut _s = $crate::__private::TokenStream::new(); + $crate::quote_token!{$tt1 _s} + $crate::quote_token!{$tt2 _s} + _s + }}; + + // Rule for any other number of tokens. + ($($tt:tt)*) => {{ + let mut _s = $crate::__private::TokenStream::new(); + $crate::quote_each_token!{_s $($tt)*} + _s + }}; + } +]; + +/// Same as `quote!`, but applies a given span to all tokens originating within +/// the macro invocation. +/// +///
+/// +/// # Syntax +/// +/// A span expression of type [`Span`], followed by `=>`, followed by the tokens +/// to quote. The span expression should be brief — use a variable for +/// anything more than a few characters. There should be no space before the +/// `=>` token. +/// +/// [`Span`]: proc_macro2::Span +/// +/// ``` +/// # use proc_macro2::Span; +/// # use quote::quote_spanned; +/// # +/// # const IGNORE_TOKENS: &'static str = stringify! { +/// let span = /* ... */; +/// # }; +/// # let span = Span::call_site(); +/// # let init = 0; +/// +/// // On one line, use parentheses. +/// let tokens = quote_spanned!(span=> Box::into_raw(Box::new(#init))); +/// +/// // On multiple lines, place the span at the top and use braces. +/// let tokens = quote_spanned! {span=> +/// Box::into_raw(Box::new(#init)) +/// }; +/// ``` +/// +/// The lack of space before the `=>` should look jarring to Rust programmers +/// and this is intentional. The formatting is designed to be visibly +/// off-balance and draw the eye a particular way, due to the span expression +/// being evaluated in the context of the procedural macro and the remaining +/// tokens being evaluated in the generated code. +/// +///
+/// +/// # Hygiene +/// +/// Any interpolated tokens preserve the `Span` information provided by their +/// `ToTokens` implementation. Tokens that originate within the `quote_spanned!` +/// invocation are spanned with the given span argument. +/// +///
+/// +/// # Example +/// +/// The following procedural macro code uses `quote_spanned!` to assert that a +/// particular Rust type implements the [`Sync`] trait so that references can be +/// safely shared between threads. +/// +/// ``` +/// # use quote::{quote_spanned, TokenStreamExt, ToTokens}; +/// # use proc_macro2::{Span, TokenStream}; +/// # +/// # struct Type; +/// # +/// # impl Type { +/// # fn span(&self) -> Span { +/// # Span::call_site() +/// # } +/// # } +/// # +/// # impl ToTokens for Type { +/// # fn to_tokens(&self, _tokens: &mut TokenStream) {} +/// # } +/// # +/// # let ty = Type; +/// # let call_site = Span::call_site(); +/// # +/// let ty_span = ty.span(); +/// let assert_sync = quote_spanned! {ty_span=> +/// struct _AssertSync where #ty: Sync; +/// }; +/// ``` +/// +/// If the assertion fails, the user will see an error like the following. The +/// input span of their type is highlighted in the error. +/// +/// ```text +/// error[E0277]: the trait bound `*const (): std::marker::Sync` is not satisfied +/// --> src/main.rs:10:21 +/// | +/// 10 | static ref PTR: *const () = &(); +/// | ^^^^^^^^^ `*const ()` cannot be shared between threads safely +/// ``` +/// +/// In this example it is important for the where-clause to be spanned with the +/// line/column information of the user's input type so that error messages are +/// placed appropriately by the compiler. +#[macro_export] +macro_rules! quote_spanned { + ($span:expr=> $($tt:tt)*) => {{ + let _span: $crate::__private::Span = $crate::__private::get_span($span).__into_span(); + $crate::quote_spanned_with_expanded_span!{_span $($tt)*} + }}; +} + +// We want to ensure that `get_span` only gets called for the actual user +// invocation and not for recursive calls from groups, which will call this +// inner macro instead. +#[macro_export] +#[doc(hidden)] +macro_rules! quote_spanned_with_expanded_span { + ($span:ident) => { + $crate::__private::TokenStream::new() + }; + + // Special case rule for a single tt, for performance. + ($span:ident $tt:tt) => { + let mut _s = $crate::__private::TokenStream::new(); + $crate::quote_token_spanned!{$tt _s $span} + _s + }; + + // Special case rules for two tts, for performance. + ($span:ident # $var:ident) => { + let mut _s = $crate::__private::TokenStream::new(); + $crate::ToTokens::to_tokens(&$var, &mut _s); + _s + }; + ($span:ident $tt1:tt $tt2:tt) => { + let mut _s = $crate::__private::TokenStream::new(); + $crate::quote_token_spanned!{$tt1 _s $span} + $crate::quote_token_spanned!{$tt2 _s $span} + _s + }; + + // Rule for any other number of tokens. + ($span:ident $($tt:tt)*) => { + let mut _s = $crate::__private::TokenStream::new(); + $crate::quote_each_token_spanned!{_s $span $($tt)*} + _s + }; +} + +// Extract the names of all #metavariables and pass them to the $call macro. +// +// in: pounded_var_names!(then!(...) a #b c #( #d )* #e) +// out: then!(... b); +// then!(... d); +// then!(... e); +#[macro_export] +#[doc(hidden)] +macro_rules! pounded_var_names { + ($call:ident! $extra:tt $($tts:tt)*) => { + $crate::pounded_var_names_with_context!{$call! $extra + (@ $($tts)*) + ($($tts)* @) + } + }; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! pounded_var_names_with_context { + ($call:ident! $extra:tt ($($b1:tt)*) ($($curr:tt)*)) => { + $( + $crate::pounded_var_with_context!{$call! $extra $b1 $curr} + )* + }; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! pounded_var_with_context { + ($call:ident! $extra:tt $b1:tt ( $($inner:tt)* )) => { + $crate::pounded_var_names!{$call! $extra $($inner)*} + }; + + ($call:ident! $extra:tt $b1:tt [ $($inner:tt)* ]) => { + $crate::pounded_var_names!{$call! $extra $($inner)*} + }; + + ($call:ident! $extra:tt $b1:tt { $($inner:tt)* }) => { + $crate::pounded_var_names!{$call! $extra $($inner)*} + }; + + ($call:ident!($($extra:tt)*) # $var:ident) => { + $crate::$call!($($extra)* $var); + }; + + ($call:ident! $extra:tt $b1:tt $curr:tt) => {}; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! quote_bind_into_iter { + ($has_iter:ident $var:ident) => { + // `mut` may be unused if $var occurs multiple times in the list. + #[allow(unused_mut)] + let (mut $var, i) = $var.quote_into_iter(); + let $has_iter = $has_iter | i; + }; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! quote_bind_next_or_break { + ($var:ident) => { + let $var = match $var.next() { + Some(_x) => $crate::__private::RepInterp(_x), + None => break, + }; + }; +} + +// The obvious way to write this macro is as a tt muncher. This implementation +// does something more complex for two reasons. +// +// - With a tt muncher it's easy to hit Rust's built-in recursion_limit, which +// this implementation avoids because it isn't tail recursive. +// +// - Compile times for a tt muncher are quadratic relative to the length of +// the input. This implementation is linear, so it will be faster +// (potentially much faster) for big inputs. However, the constant factors +// of this implementation are higher than that of a tt muncher, so it is +// somewhat slower than a tt muncher if there are many invocations with +// short inputs. +// +// An invocation like this: +// +// quote_each_token!(_s a b c d e f g h i j); +// +// expands to this: +// +// quote_tokens_with_context!(_s +// (@ @ @ @ @ @ a b c d e f g h i j) +// (@ @ @ @ @ a b c d e f g h i j @) +// (@ @ @ @ a b c d e f g h i j @ @) +// (@ @ @ (a) (b) (c) (d) (e) (f) (g) (h) (i) (j) @ @ @) +// (@ @ a b c d e f g h i j @ @ @ @) +// (@ a b c d e f g h i j @ @ @ @ @) +// (a b c d e f g h i j @ @ @ @ @ @) +// ); +// +// which gets transposed and expanded to this: +// +// quote_token_with_context!(_s @ @ @ @ @ @ a); +// quote_token_with_context!(_s @ @ @ @ @ a b); +// quote_token_with_context!(_s @ @ @ @ a b c); +// quote_token_with_context!(_s @ @ @ (a) b c d); +// quote_token_with_context!(_s @ @ a (b) c d e); +// quote_token_with_context!(_s @ a b (c) d e f); +// quote_token_with_context!(_s a b c (d) e f g); +// quote_token_with_context!(_s b c d (e) f g h); +// quote_token_with_context!(_s c d e (f) g h i); +// quote_token_with_context!(_s d e f (g) h i j); +// quote_token_with_context!(_s e f g (h) i j @); +// quote_token_with_context!(_s f g h (i) j @ @); +// quote_token_with_context!(_s g h i (j) @ @ @); +// quote_token_with_context!(_s h i j @ @ @ @); +// quote_token_with_context!(_s i j @ @ @ @ @); +// quote_token_with_context!(_s j @ @ @ @ @ @); +// +// Without having used muncher-style recursion, we get one invocation of +// quote_token_with_context for each original tt, with three tts of context on +// either side. This is enough for the longest possible interpolation form (a +// repetition with separator, as in `# (#var) , *`) to be fully represented with +// the first or last tt in the middle. +// +// The middle tt (surrounded by parentheses) is the tt being processed. +// +// - When it is a `#`, quote_token_with_context can do an interpolation. The +// interpolation kind will depend on the three subsequent tts. +// +// - When it is within a later part of an interpolation, it can be ignored +// because the interpolation has already been done. +// +// - When it is not part of an interpolation it can be pushed as a single +// token into the output. +// +// - When the middle token is an unparenthesized `@`, that call is one of the +// first 3 or last 3 calls of quote_token_with_context and does not +// correspond to one of the original input tokens, so turns into nothing. +#[macro_export] +#[doc(hidden)] +macro_rules! quote_each_token { + ($tokens:ident $($tts:tt)*) => { + $crate::quote_tokens_with_context!{$tokens + (@ @ @ @ @ @ $($tts)*) + (@ @ @ @ @ $($tts)* @) + (@ @ @ @ $($tts)* @ @) + (@ @ @ $(($tts))* @ @ @) + (@ @ $($tts)* @ @ @ @) + (@ $($tts)* @ @ @ @ @) + ($($tts)* @ @ @ @ @ @) + } + }; +} + +// See the explanation on quote_each_token. +#[macro_export] +#[doc(hidden)] +macro_rules! quote_each_token_spanned { + ($tokens:ident $span:ident $($tts:tt)*) => { + $crate::quote_tokens_with_context_spanned!{$tokens $span + (@ @ @ @ @ @ $($tts)*) + (@ @ @ @ @ $($tts)* @) + (@ @ @ @ $($tts)* @ @) + (@ @ @ $(($tts))* @ @ @) + (@ @ $($tts)* @ @ @ @) + (@ $($tts)* @ @ @ @ @) + ($($tts)* @ @ @ @ @ @) + } + }; +} + +// See the explanation on quote_each_token. +#[macro_export] +#[doc(hidden)] +macro_rules! quote_tokens_with_context { + ($tokens:ident + ($($b3:tt)*) ($($b2:tt)*) ($($b1:tt)*) + ($($curr:tt)*) + ($($a1:tt)*) ($($a2:tt)*) ($($a3:tt)*) + ) => { + $( + $crate::quote_token_with_context!{$tokens $b3 $b2 $b1 $curr $a1 $a2 $a3} + )* + }; +} + +// See the explanation on quote_each_token. +#[macro_export] +#[doc(hidden)] +macro_rules! quote_tokens_with_context_spanned { + ($tokens:ident $span:ident + ($($b3:tt)*) ($($b2:tt)*) ($($b1:tt)*) + ($($curr:tt)*) + ($($a1:tt)*) ($($a2:tt)*) ($($a3:tt)*) + ) => { + $( + $crate::quote_token_with_context_spanned!{$tokens $span $b3 $b2 $b1 $curr $a1 $a2 $a3} + )* + }; +} + +// See the explanation on quote_each_token. +#[macro_export] +#[doc(hidden)] +macro_rules! quote_token_with_context { + // Unparenthesized `@` indicates this call does not correspond to one of the + // original input tokens. Ignore it. + ($tokens:ident $b3:tt $b2:tt $b1:tt @ $a1:tt $a2:tt $a3:tt) => {}; + + // A repetition with no separator. + ($tokens:ident $b3:tt $b2:tt $b1:tt (#) ( $($inner:tt)* ) * $a3:tt) => {{ + use $crate::__private::ext::*; + let has_iter = $crate::__private::HasIterator::; + $crate::pounded_var_names!{quote_bind_into_iter!(has_iter) () $($inner)*} + <_ as $crate::__private::CheckHasIterator>::check(has_iter); + // This is `while true` instead of `loop` because if there are no + // iterators used inside of this repetition then the body would not + // contain any `break`, so the compiler would emit unreachable code + // warnings on anything below the loop. We use has_iter to detect and + // fail to compile when there are no iterators, so here we just work + // around the unneeded extra warning. + while true { + $crate::pounded_var_names!{quote_bind_next_or_break!() () $($inner)*} + $crate::quote_each_token!{$tokens $($inner)*} + } + }}; + // ... and one step later. + ($tokens:ident $b3:tt $b2:tt # (( $($inner:tt)* )) * $a2:tt $a3:tt) => {}; + // ... and one step later. + ($tokens:ident $b3:tt # ( $($inner:tt)* ) (*) $a1:tt $a2:tt $a3:tt) => {}; + + // A repetition with separator. + ($tokens:ident $b3:tt $b2:tt $b1:tt (#) ( $($inner:tt)* ) $sep:tt *) => {{ + use $crate::__private::ext::*; + let mut _first = true; + let has_iter = $crate::__private::HasIterator::; + $crate::pounded_var_names!{quote_bind_into_iter!(has_iter) () $($inner)*} + <_ as $crate::__private::CheckHasIterator>::check(has_iter); + while true { + $crate::pounded_var_names!{quote_bind_next_or_break!() () $($inner)*} + if !_first { + $crate::quote_token!{$sep $tokens} + } + _first = false; + $crate::quote_each_token!{$tokens $($inner)*} + } + }}; + // ... and one step later. + ($tokens:ident $b3:tt $b2:tt # (( $($inner:tt)* )) $sep:tt * $a3:tt) => {}; + // ... and one step later. + ($tokens:ident $b3:tt # ( $($inner:tt)* ) ($sep:tt) * $a2:tt $a3:tt) => {}; + // (A special case for `#(var)**`, where the first `*` is treated as the + // repetition symbol and the second `*` is treated as an ordinary token.) + ($tokens:ident # ( $($inner:tt)* ) * (*) $a1:tt $a2:tt $a3:tt) => { + // https://github.com/dtolnay/quote/issues/130 + $crate::quote_token!{* $tokens} + }; + // ... and one step later. + ($tokens:ident # ( $($inner:tt)* ) $sep:tt (*) $a1:tt $a2:tt $a3:tt) => {}; + + // A non-repetition interpolation. + ($tokens:ident $b3:tt $b2:tt $b1:tt (#) $var:ident $a2:tt $a3:tt) => { + $crate::ToTokens::to_tokens(&$var, &mut $tokens); + }; + // ... and one step later. + ($tokens:ident $b3:tt $b2:tt # ($var:ident) $a1:tt $a2:tt $a3:tt) => {}; + + // An ordinary token, not part of any interpolation. + ($tokens:ident $b3:tt $b2:tt $b1:tt ($curr:tt) $a1:tt $a2:tt $a3:tt) => { + $crate::quote_token!{$curr $tokens} + }; +} + +// See the explanation on quote_each_token, and on the individual rules of +// quote_token_with_context. +#[macro_export] +#[doc(hidden)] +macro_rules! quote_token_with_context_spanned { + ($tokens:ident $span:ident $b3:tt $b2:tt $b1:tt @ $a1:tt $a2:tt $a3:tt) => {}; + + ($tokens:ident $span:ident $b3:tt $b2:tt $b1:tt (#) ( $($inner:tt)* ) * $a3:tt) => {{ + use $crate::__private::ext::*; + let has_iter = $crate::__private::HasIterator::; + $crate::pounded_var_names!{quote_bind_into_iter!(has_iter) () $($inner)*} + <_ as $crate::__private::CheckHasIterator>::check(has_iter); + while true { + $crate::pounded_var_names!{quote_bind_next_or_break!() () $($inner)*} + $crate::quote_each_token_spanned!{$tokens $span $($inner)*} + } + }}; + ($tokens:ident $span:ident $b3:tt $b2:tt # (( $($inner:tt)* )) * $a2:tt $a3:tt) => {}; + ($tokens:ident $span:ident $b3:tt # ( $($inner:tt)* ) (*) $a1:tt $a2:tt $a3:tt) => {}; + + ($tokens:ident $span:ident $b3:tt $b2:tt $b1:tt (#) ( $($inner:tt)* ) $sep:tt *) => {{ + use $crate::__private::ext::*; + let mut _first = true; + let has_iter = $crate::__private::HasIterator::; + $crate::pounded_var_names!{quote_bind_into_iter!(has_iter) () $($inner)*} + <_ as $crate::__private::CheckHasIterator>::check(has_iter); + while true { + $crate::pounded_var_names!{quote_bind_next_or_break!() () $($inner)*} + if !_first { + $crate::quote_token_spanned!{$sep $tokens $span} + } + _first = false; + $crate::quote_each_token_spanned!{$tokens $span $($inner)*} + } + }}; + ($tokens:ident $span:ident $b3:tt $b2:tt # (( $($inner:tt)* )) $sep:tt * $a3:tt) => {}; + ($tokens:ident $span:ident $b3:tt # ( $($inner:tt)* ) ($sep:tt) * $a2:tt $a3:tt) => {}; + ($tokens:ident $span:ident # ( $($inner:tt)* ) * (*) $a1:tt $a2:tt $a3:tt) => { + // https://github.com/dtolnay/quote/issues/130 + $crate::quote_token_spanned!{* $tokens $span} + }; + ($tokens:ident $span:ident # ( $($inner:tt)* ) $sep:tt (*) $a1:tt $a2:tt $a3:tt) => {}; + + ($tokens:ident $span:ident $b3:tt $b2:tt $b1:tt (#) $var:ident $a2:tt $a3:tt) => { + $crate::ToTokens::to_tokens(&$var, &mut $tokens); + }; + ($tokens:ident $span:ident $b3:tt $b2:tt # ($var:ident) $a1:tt $a2:tt $a3:tt) => {}; + + ($tokens:ident $span:ident $b3:tt $b2:tt $b1:tt ($curr:tt) $a1:tt $a2:tt $a3:tt) => { + $crate::quote_token_spanned!{$curr $tokens $span} + }; +} + +// These rules are ordered by approximate token frequency, at least for the +// first 10 or so, to improve compile times. Having `ident` first is by far the +// most important because it's typically 2-3x more common than the next most +// common token. +// +// Separately, we put the token being matched in the very front so that failing +// rules may fail to match as quickly as possible. +#[macro_export] +#[doc(hidden)] +macro_rules! quote_token { + ($ident:ident $tokens:ident) => { + $crate::__private::push_ident( + &mut $tokens, + $crate::__private::stringify!($ident), + ); + }; + + (:: $tokens:ident) => { + $crate::__private::push_colon2(&mut $tokens); + }; + + (( $($inner:tt)* ) $tokens:ident) => { + $crate::__private::push_group( + &mut $tokens, + $crate::__private::Delimiter::Parenthesis, + $crate::quote!($($inner)*), + ); + }; + + ([ $($inner:tt)* ] $tokens:ident) => { + $crate::__private::push_group( + &mut $tokens, + $crate::__private::Delimiter::Bracket, + $crate::quote!($($inner)*), + ); + }; + + ({ $($inner:tt)* } $tokens:ident) => { + $crate::__private::push_group( + &mut $tokens, + $crate::__private::Delimiter::Brace, + $crate::quote!($($inner)*), + ); + }; + + (# $tokens:ident) => { + $crate::__private::push_pound(&mut $tokens); + }; + + (, $tokens:ident) => { + $crate::__private::push_comma(&mut $tokens); + }; + + (. $tokens:ident) => { + $crate::__private::push_dot(&mut $tokens); + }; + + (; $tokens:ident) => { + $crate::__private::push_semi(&mut $tokens); + }; + + (: $tokens:ident) => { + $crate::__private::push_colon(&mut $tokens); + }; + + (+ $tokens:ident) => { + $crate::__private::push_add(&mut $tokens); + }; + + (+= $tokens:ident) => { + $crate::__private::push_add_eq(&mut $tokens); + }; + + (& $tokens:ident) => { + $crate::__private::push_and(&mut $tokens); + }; + + (&& $tokens:ident) => { + $crate::__private::push_and_and(&mut $tokens); + }; + + (&= $tokens:ident) => { + $crate::__private::push_and_eq(&mut $tokens); + }; + + (@ $tokens:ident) => { + $crate::__private::push_at(&mut $tokens); + }; + + (! $tokens:ident) => { + $crate::__private::push_bang(&mut $tokens); + }; + + (^ $tokens:ident) => { + $crate::__private::push_caret(&mut $tokens); + }; + + (^= $tokens:ident) => { + $crate::__private::push_caret_eq(&mut $tokens); + }; + + (/ $tokens:ident) => { + $crate::__private::push_div(&mut $tokens); + }; + + (/= $tokens:ident) => { + $crate::__private::push_div_eq(&mut $tokens); + }; + + (.. $tokens:ident) => { + $crate::__private::push_dot2(&mut $tokens); + }; + + (... $tokens:ident) => { + $crate::__private::push_dot3(&mut $tokens); + }; + + (..= $tokens:ident) => { + $crate::__private::push_dot_dot_eq(&mut $tokens); + }; + + (= $tokens:ident) => { + $crate::__private::push_eq(&mut $tokens); + }; + + (== $tokens:ident) => { + $crate::__private::push_eq_eq(&mut $tokens); + }; + + (>= $tokens:ident) => { + $crate::__private::push_ge(&mut $tokens); + }; + + (> $tokens:ident) => { + $crate::__private::push_gt(&mut $tokens); + }; + + (<= $tokens:ident) => { + $crate::__private::push_le(&mut $tokens); + }; + + (< $tokens:ident) => { + $crate::__private::push_lt(&mut $tokens); + }; + + (*= $tokens:ident) => { + $crate::__private::push_mul_eq(&mut $tokens); + }; + + (!= $tokens:ident) => { + $crate::__private::push_ne(&mut $tokens); + }; + + (| $tokens:ident) => { + $crate::__private::push_or(&mut $tokens); + }; + + (|= $tokens:ident) => { + $crate::__private::push_or_eq(&mut $tokens); + }; + + (|| $tokens:ident) => { + $crate::__private::push_or_or(&mut $tokens); + }; + + (? $tokens:ident) => { + $crate::__private::push_question(&mut $tokens); + }; + + (-> $tokens:ident) => { + $crate::__private::push_rarrow(&mut $tokens); + }; + + (<- $tokens:ident) => { + $crate::__private::push_larrow(&mut $tokens); + }; + + (% $tokens:ident) => { + $crate::__private::push_rem(&mut $tokens); + }; + + (%= $tokens:ident) => { + $crate::__private::push_rem_eq(&mut $tokens); + }; + + (=> $tokens:ident) => { + $crate::__private::push_fat_arrow(&mut $tokens); + }; + + (<< $tokens:ident) => { + $crate::__private::push_shl(&mut $tokens); + }; + + (<<= $tokens:ident) => { + $crate::__private::push_shl_eq(&mut $tokens); + }; + + (>> $tokens:ident) => { + $crate::__private::push_shr(&mut $tokens); + }; + + (>>= $tokens:ident) => { + $crate::__private::push_shr_eq(&mut $tokens); + }; + + (* $tokens:ident) => { + $crate::__private::push_star(&mut $tokens); + }; + + (- $tokens:ident) => { + $crate::__private::push_sub(&mut $tokens); + }; + + (-= $tokens:ident) => { + $crate::__private::push_sub_eq(&mut $tokens); + }; + + ($lifetime:lifetime $tokens:ident) => { + $crate::__private::push_lifetime( + &mut $tokens, + $crate::__private::stringify!($lifetime), + ); + }; + + (_ $tokens:ident) => { + $crate::__private::push_underscore(&mut $tokens); + }; + + ($other:tt $tokens:ident) => { + $crate::__private::parse( + &mut $tokens, + $crate::__private::stringify!($other), + ); + }; +} + +// See the comment above `quote_token!` about the rule ordering. +#[macro_export] +#[doc(hidden)] +macro_rules! quote_token_spanned { + ($ident:ident $tokens:ident $span:ident) => { + $crate::__private::push_ident_spanned( + &mut $tokens, + $span, + $crate::__private::stringify!($ident), + ); + }; + + (:: $tokens:ident $span:ident) => { + $crate::__private::push_colon2_spanned(&mut $tokens, $span); + }; + + (( $($inner:tt)* ) $tokens:ident $span:ident) => { + $crate::__private::push_group_spanned( + &mut $tokens, + $span, + $crate::__private::Delimiter::Parenthesis, + { + $crate::quote_spanned_with_expanded_span!{$span $($inner)*} + }, + ); + }; + + ([ $($inner:tt)* ] $tokens:ident $span:ident) => { + $crate::__private::push_group_spanned( + &mut $tokens, + $span, + $crate::__private::Delimiter::Bracket, + { + $crate::quote_spanned_with_expanded_span!{$span $($inner)*} + }, + ); + }; + + ({ $($inner:tt)* } $tokens:ident $span:ident) => { + $crate::__private::push_group_spanned( + &mut $tokens, + $span, + $crate::__private::Delimiter::Brace, + { + $crate::quote_spanned_with_expanded_span!{$span $($inner)*} + }, + ); + }; + + (# $tokens:ident $span:ident) => { + $crate::__private::push_pound_spanned(&mut $tokens, $span); + }; + + (, $tokens:ident $span:ident) => { + $crate::__private::push_comma_spanned(&mut $tokens, $span); + }; + + (. $tokens:ident $span:ident) => { + $crate::__private::push_dot_spanned(&mut $tokens, $span); + }; + + (; $tokens:ident $span:ident) => { + $crate::__private::push_semi_spanned(&mut $tokens, $span); + }; + + (: $tokens:ident $span:ident) => { + $crate::__private::push_colon_spanned(&mut $tokens, $span); + }; + + (+ $tokens:ident $span:ident) => { + $crate::__private::push_add_spanned(&mut $tokens, $span); + }; + + (+= $tokens:ident $span:ident) => { + $crate::__private::push_add_eq_spanned(&mut $tokens, $span); + }; + + (& $tokens:ident $span:ident) => { + $crate::__private::push_and_spanned(&mut $tokens, $span); + }; + + (&& $tokens:ident $span:ident) => { + $crate::__private::push_and_and_spanned(&mut $tokens, $span); + }; + + (&= $tokens:ident $span:ident) => { + $crate::__private::push_and_eq_spanned(&mut $tokens, $span); + }; + + (@ $tokens:ident $span:ident) => { + $crate::__private::push_at_spanned(&mut $tokens, $span); + }; + + (! $tokens:ident $span:ident) => { + $crate::__private::push_bang_spanned(&mut $tokens, $span); + }; + + (^ $tokens:ident $span:ident) => { + $crate::__private::push_caret_spanned(&mut $tokens, $span); + }; + + (^= $tokens:ident $span:ident) => { + $crate::__private::push_caret_eq_spanned(&mut $tokens, $span); + }; + + (/ $tokens:ident $span:ident) => { + $crate::__private::push_div_spanned(&mut $tokens, $span); + }; + + (/= $tokens:ident $span:ident) => { + $crate::__private::push_div_eq_spanned(&mut $tokens, $span); + }; + + (.. $tokens:ident $span:ident) => { + $crate::__private::push_dot2_spanned(&mut $tokens, $span); + }; + + (... $tokens:ident $span:ident) => { + $crate::__private::push_dot3_spanned(&mut $tokens, $span); + }; + + (..= $tokens:ident $span:ident) => { + $crate::__private::push_dot_dot_eq_spanned(&mut $tokens, $span); + }; + + (= $tokens:ident $span:ident) => { + $crate::__private::push_eq_spanned(&mut $tokens, $span); + }; + + (== $tokens:ident $span:ident) => { + $crate::__private::push_eq_eq_spanned(&mut $tokens, $span); + }; + + (>= $tokens:ident $span:ident) => { + $crate::__private::push_ge_spanned(&mut $tokens, $span); + }; + + (> $tokens:ident $span:ident) => { + $crate::__private::push_gt_spanned(&mut $tokens, $span); + }; + + (<= $tokens:ident $span:ident) => { + $crate::__private::push_le_spanned(&mut $tokens, $span); + }; + + (< $tokens:ident $span:ident) => { + $crate::__private::push_lt_spanned(&mut $tokens, $span); + }; + + (*= $tokens:ident $span:ident) => { + $crate::__private::push_mul_eq_spanned(&mut $tokens, $span); + }; + + (!= $tokens:ident $span:ident) => { + $crate::__private::push_ne_spanned(&mut $tokens, $span); + }; + + (| $tokens:ident $span:ident) => { + $crate::__private::push_or_spanned(&mut $tokens, $span); + }; + + (|= $tokens:ident $span:ident) => { + $crate::__private::push_or_eq_spanned(&mut $tokens, $span); + }; + + (|| $tokens:ident $span:ident) => { + $crate::__private::push_or_or_spanned(&mut $tokens, $span); + }; + + (? $tokens:ident $span:ident) => { + $crate::__private::push_question_spanned(&mut $tokens, $span); + }; + + (-> $tokens:ident $span:ident) => { + $crate::__private::push_rarrow_spanned(&mut $tokens, $span); + }; + + (<- $tokens:ident $span:ident) => { + $crate::__private::push_larrow_spanned(&mut $tokens, $span); + }; + + (% $tokens:ident $span:ident) => { + $crate::__private::push_rem_spanned(&mut $tokens, $span); + }; + + (%= $tokens:ident $span:ident) => { + $crate::__private::push_rem_eq_spanned(&mut $tokens, $span); + }; + + (=> $tokens:ident $span:ident) => { + $crate::__private::push_fat_arrow_spanned(&mut $tokens, $span); + }; + + (<< $tokens:ident $span:ident) => { + $crate::__private::push_shl_spanned(&mut $tokens, $span); + }; + + (<<= $tokens:ident $span:ident) => { + $crate::__private::push_shl_eq_spanned(&mut $tokens, $span); + }; + + (>> $tokens:ident $span:ident) => { + $crate::__private::push_shr_spanned(&mut $tokens, $span); + }; + + (>>= $tokens:ident $span:ident) => { + $crate::__private::push_shr_eq_spanned(&mut $tokens, $span); + }; + + (* $tokens:ident $span:ident) => { + $crate::__private::push_star_spanned(&mut $tokens, $span); + }; + + (- $tokens:ident $span:ident) => { + $crate::__private::push_sub_spanned(&mut $tokens, $span); + }; + + (-= $tokens:ident $span:ident) => { + $crate::__private::push_sub_eq_spanned(&mut $tokens, $span); + }; + + ($lifetime:lifetime $tokens:ident $span:ident) => { + $crate::__private::push_lifetime_spanned( + &mut $tokens, + $span, + $crate::__private::stringify!($lifetime), + ); + }; + + (_ $tokens:ident $span:ident) => { + $crate::__private::push_underscore_spanned(&mut $tokens, $span); + }; + + ($other:tt $tokens:ident $span:ident) => { + $crate::__private::parse_spanned( + &mut $tokens, + $span, + $crate::__private::stringify!($other), + ); + }; +} diff --git a/third_party/crates/quote-1.0.47/src/runtime.rs b/third_party/crates/quote-1.0.47/src/runtime.rs new file mode 100644 index 0000000..46bba33 --- /dev/null +++ b/third_party/crates/quote-1.0.47/src/runtime.rs @@ -0,0 +1,506 @@ +use self::get_span::{GetSpan, GetSpanBase, GetSpanInner}; +use crate::{IdentFragment, ToTokens, TokenStreamExt}; +use core::fmt; +use core::iter; +use core::ops::BitOr; +use proc_macro2::{Group, Ident, Punct, Spacing, TokenTree}; + +#[doc(hidden)] +pub use alloc::format; +#[doc(hidden)] +pub use core::option::Option; +#[doc(hidden)] +pub use core::stringify; + +#[doc(hidden)] +pub type Delimiter = proc_macro2::Delimiter; +#[doc(hidden)] +pub type Span = proc_macro2::Span; +#[doc(hidden)] +pub type TokenStream = proc_macro2::TokenStream; + +#[doc(hidden)] +pub struct HasIterator; + +impl BitOr> for HasIterator { + type Output = HasIterator; + fn bitor(self, _rhs: HasIterator) -> HasIterator { + HasIterator:: + } +} + +impl BitOr> for HasIterator { + type Output = HasIterator; + fn bitor(self, _rhs: HasIterator) -> HasIterator { + HasIterator:: + } +} + +impl BitOr> for HasIterator { + type Output = HasIterator; + fn bitor(self, _rhs: HasIterator) -> HasIterator { + HasIterator:: + } +} + +impl BitOr> for HasIterator { + type Output = HasIterator; + fn bitor(self, _rhs: HasIterator) -> HasIterator { + HasIterator:: + } +} + +#[doc(hidden)] +#[cfg_attr( + not(no_diagnostic_namespace), + diagnostic::on_unimplemented( + message = "repetition contains no interpolated value that is an iterator", + label = "none of the values interpolated inside this repetition are iterable" + ) +)] +pub trait CheckHasIterator: Sized { + fn check(self) {} +} + +impl CheckHasIterator for HasIterator {} + +/// Extension traits used by the implementation of `quote!`. These are defined +/// in separate traits, rather than as a single trait due to ambiguity issues. +/// +/// These traits expose a `quote_into_iter` method which should allow calling +/// whichever impl happens to be applicable. Calling that method repeatedly on +/// the returned value should be idempotent. +#[doc(hidden)] +pub mod ext { + use super::{HasIterator, RepInterp}; + use crate::ToTokens; + use alloc::collections::btree_set::{self, BTreeSet}; + use alloc::vec::Vec; + use core::slice; + + /// Extension trait providing the `quote_into_iter` method on iterators. + #[doc(hidden)] + pub trait RepIteratorExt: Iterator + Sized { + fn quote_into_iter(self) -> (Self, HasIterator) { + (self, HasIterator::) + } + } + + impl RepIteratorExt for T {} + + /// Extension trait providing the `quote_into_iter` method for + /// non-iterable types. These types interpolate the same value in each + /// iteration of the repetition. + #[doc(hidden)] + pub trait RepToTokensExt { + /// Pretend to be an iterator for the purposes of `quote_into_iter`. + /// This allows repeated calls to `quote_into_iter` to continue + /// correctly returning HasIterator. + fn next(&self) -> Option<&Self> { + Some(self) + } + + fn quote_into_iter(&self) -> (&Self, HasIterator) { + (self, HasIterator::) + } + } + + impl RepToTokensExt for T {} + + /// Extension trait providing the `quote_into_iter` method for types that + /// can be referenced as an iterator. + #[doc(hidden)] + pub trait RepAsIteratorExt<'q> { + type Iter: Iterator; + + fn quote_into_iter(&'q self) -> (Self::Iter, HasIterator); + } + + impl<'q, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &T { + type Iter = T::Iter; + + fn quote_into_iter(&'q self) -> (Self::Iter, HasIterator) { + ::quote_into_iter(*self) + } + } + + impl<'q, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &mut T { + type Iter = T::Iter; + + fn quote_into_iter(&'q self) -> (Self::Iter, HasIterator) { + ::quote_into_iter(*self) + } + } + + impl<'q, T: 'q> RepAsIteratorExt<'q> for [T] { + type Iter = slice::Iter<'q, T>; + + fn quote_into_iter(&'q self) -> (Self::Iter, HasIterator) { + (self.iter(), HasIterator::) + } + } + + impl<'q, T: 'q, const N: usize> RepAsIteratorExt<'q> for [T; N] { + type Iter = slice::Iter<'q, T>; + + fn quote_into_iter(&'q self) -> (Self::Iter, HasIterator) { + (self.iter(), HasIterator::) + } + } + + impl<'q, T: 'q> RepAsIteratorExt<'q> for Vec { + type Iter = slice::Iter<'q, T>; + + fn quote_into_iter(&'q self) -> (Self::Iter, HasIterator) { + (self.iter(), HasIterator::) + } + } + + impl<'q, T: 'q> RepAsIteratorExt<'q> for BTreeSet { + type Iter = btree_set::Iter<'q, T>; + + fn quote_into_iter(&'q self) -> (Self::Iter, HasIterator) { + (self.iter(), HasIterator::) + } + } + + impl<'q, T: RepAsIteratorExt<'q>> RepAsIteratorExt<'q> for RepInterp { + type Iter = T::Iter; + + fn quote_into_iter(&'q self) -> (Self::Iter, HasIterator) { + self.0.quote_into_iter() + } + } +} + +// Helper type used within interpolations to allow for repeated binding names. +// Implements the relevant traits, and exports a dummy `next()` method. +#[derive(Copy, Clone)] +#[doc(hidden)] +pub struct RepInterp(pub T); + +impl RepInterp { + // This method is intended to look like `Iterator::next`, and is called when + // a name is bound multiple times, as the previous binding will shadow the + // original `Iterator` object. This allows us to avoid advancing the + // iterator multiple times per iteration. + pub fn next(self) -> Option { + Some(self.0) + } +} + +impl Iterator for RepInterp { + type Item = T::Item; + + fn next(&mut self) -> Option { + self.0.next() + } +} + +impl ToTokens for RepInterp { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.0.to_tokens(tokens); + } +} + +#[doc(hidden)] +#[inline] +pub fn get_span(span: T) -> GetSpan { + GetSpan(GetSpanInner(GetSpanBase(span))) +} + +mod get_span { + use core::ops::Deref; + use proc_macro2::extra::DelimSpan; + use proc_macro2::Span; + + pub struct GetSpan(pub(crate) GetSpanInner); + + pub struct GetSpanInner(pub(crate) GetSpanBase); + + pub struct GetSpanBase(pub(crate) T); + + impl GetSpan { + #[inline] + pub fn __into_span(self) -> Span { + ((self.0).0).0 + } + } + + impl GetSpanInner { + #[inline] + pub fn __into_span(&self) -> Span { + (self.0).0.join() + } + } + + impl GetSpanBase { + #[allow(clippy::unused_self)] + pub fn __into_span(&self) -> T { + unreachable!() + } + } + + impl Deref for GetSpan { + type Target = GetSpanInner; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl Deref for GetSpanInner { + type Target = GetSpanBase; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } + } +} + +#[doc(hidden)] +pub fn push_group(tokens: &mut TokenStream, delimiter: Delimiter, inner: TokenStream) { + tokens.append(Group::new(delimiter, inner)); +} + +#[doc(hidden)] +pub fn push_group_spanned( + tokens: &mut TokenStream, + span: Span, + delimiter: Delimiter, + inner: TokenStream, +) { + let mut g = Group::new(delimiter, inner); + g.set_span(span); + tokens.append(g); +} + +#[doc(hidden)] +pub fn parse(tokens: &mut TokenStream, s: &str) { + let s: TokenStream = s.parse().expect("invalid token stream"); + tokens.extend(iter::once(s)); +} + +#[doc(hidden)] +pub fn parse_spanned(tokens: &mut TokenStream, span: Span, s: &str) { + let s: TokenStream = s.parse().expect("invalid token stream"); + for token in s { + tokens.append(respan_token_tree(token, span)); + } +} + +// Token tree with every span replaced by the given one. +fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree { + match &mut token { + TokenTree::Group(g) => { + let mut tokens = TokenStream::new(); + for token in g.stream() { + tokens.append(respan_token_tree(token, span)); + } + *g = Group::new(g.delimiter(), tokens); + g.set_span(span); + } + other => other.set_span(span), + } + token +} + +#[doc(hidden)] +pub fn push_ident(tokens: &mut TokenStream, s: &str) { + let span = Span::call_site(); + push_ident_spanned(tokens, span, s); +} + +#[doc(hidden)] +pub fn push_ident_spanned(tokens: &mut TokenStream, span: Span, s: &str) { + tokens.append(ident_maybe_raw(s, span)); +} + +#[doc(hidden)] +pub fn push_lifetime(tokens: &mut TokenStream, lifetime: &str) { + tokens.append(TokenTree::Punct(Punct::new('\'', Spacing::Joint))); + tokens.append(TokenTree::Ident(ident_maybe_raw( + &lifetime[1..], + Span::call_site(), + ))); +} + +#[doc(hidden)] +pub fn push_lifetime_spanned(tokens: &mut TokenStream, span: Span, lifetime: &str) { + tokens.append(TokenTree::Punct({ + let mut apostrophe = Punct::new('\'', Spacing::Joint); + apostrophe.set_span(span); + apostrophe + })); + tokens.append(TokenTree::Ident(ident_maybe_raw(&lifetime[1..], span))); +} + +macro_rules! push_punct { + ($name:ident $spanned:ident $char1:tt) => { + #[doc(hidden)] + pub fn $name(tokens: &mut TokenStream) { + tokens.append(Punct::new($char1, Spacing::Alone)); + } + #[doc(hidden)] + pub fn $spanned(tokens: &mut TokenStream, span: Span) { + let mut punct = Punct::new($char1, Spacing::Alone); + punct.set_span(span); + tokens.append(punct); + } + }; + ($name:ident $spanned:ident $char1:tt $char2:tt) => { + #[doc(hidden)] + pub fn $name(tokens: &mut TokenStream) { + tokens.append(Punct::new($char1, Spacing::Joint)); + tokens.append(Punct::new($char2, Spacing::Alone)); + } + #[doc(hidden)] + pub fn $spanned(tokens: &mut TokenStream, span: Span) { + let mut punct = Punct::new($char1, Spacing::Joint); + punct.set_span(span); + tokens.append(punct); + let mut punct = Punct::new($char2, Spacing::Alone); + punct.set_span(span); + tokens.append(punct); + } + }; + ($name:ident $spanned:ident $char1:tt $char2:tt $char3:tt) => { + #[doc(hidden)] + pub fn $name(tokens: &mut TokenStream) { + tokens.append(Punct::new($char1, Spacing::Joint)); + tokens.append(Punct::new($char2, Spacing::Joint)); + tokens.append(Punct::new($char3, Spacing::Alone)); + } + #[doc(hidden)] + pub fn $spanned(tokens: &mut TokenStream, span: Span) { + let mut punct = Punct::new($char1, Spacing::Joint); + punct.set_span(span); + tokens.append(punct); + let mut punct = Punct::new($char2, Spacing::Joint); + punct.set_span(span); + tokens.append(punct); + let mut punct = Punct::new($char3, Spacing::Alone); + punct.set_span(span); + tokens.append(punct); + } + }; +} + +push_punct!(push_add push_add_spanned '+'); +push_punct!(push_add_eq push_add_eq_spanned '+' '='); +push_punct!(push_and push_and_spanned '&'); +push_punct!(push_and_and push_and_and_spanned '&' '&'); +push_punct!(push_and_eq push_and_eq_spanned '&' '='); +push_punct!(push_at push_at_spanned '@'); +push_punct!(push_bang push_bang_spanned '!'); +push_punct!(push_caret push_caret_spanned '^'); +push_punct!(push_caret_eq push_caret_eq_spanned '^' '='); +push_punct!(push_colon push_colon_spanned ':'); +push_punct!(push_colon2 push_colon2_spanned ':' ':'); +push_punct!(push_comma push_comma_spanned ','); +push_punct!(push_div push_div_spanned '/'); +push_punct!(push_div_eq push_div_eq_spanned '/' '='); +push_punct!(push_dot push_dot_spanned '.'); +push_punct!(push_dot2 push_dot2_spanned '.' '.'); +push_punct!(push_dot3 push_dot3_spanned '.' '.' '.'); +push_punct!(push_dot_dot_eq push_dot_dot_eq_spanned '.' '.' '='); +push_punct!(push_eq push_eq_spanned '='); +push_punct!(push_eq_eq push_eq_eq_spanned '=' '='); +push_punct!(push_ge push_ge_spanned '>' '='); +push_punct!(push_gt push_gt_spanned '>'); +push_punct!(push_le push_le_spanned '<' '='); +push_punct!(push_lt push_lt_spanned '<'); +push_punct!(push_mul_eq push_mul_eq_spanned '*' '='); +push_punct!(push_ne push_ne_spanned '!' '='); +push_punct!(push_or push_or_spanned '|'); +push_punct!(push_or_eq push_or_eq_spanned '|' '='); +push_punct!(push_or_or push_or_or_spanned '|' '|'); +push_punct!(push_pound push_pound_spanned '#'); +push_punct!(push_question push_question_spanned '?'); +push_punct!(push_rarrow push_rarrow_spanned '-' '>'); +push_punct!(push_larrow push_larrow_spanned '<' '-'); +push_punct!(push_rem push_rem_spanned '%'); +push_punct!(push_rem_eq push_rem_eq_spanned '%' '='); +push_punct!(push_fat_arrow push_fat_arrow_spanned '=' '>'); +push_punct!(push_semi push_semi_spanned ';'); +push_punct!(push_shl push_shl_spanned '<' '<'); +push_punct!(push_shl_eq push_shl_eq_spanned '<' '<' '='); +push_punct!(push_shr push_shr_spanned '>' '>'); +push_punct!(push_shr_eq push_shr_eq_spanned '>' '>' '='); +push_punct!(push_star push_star_spanned '*'); +push_punct!(push_sub push_sub_spanned '-'); +push_punct!(push_sub_eq push_sub_eq_spanned '-' '='); + +#[doc(hidden)] +pub fn push_underscore(tokens: &mut TokenStream) { + push_underscore_spanned(tokens, Span::call_site()); +} + +#[doc(hidden)] +pub fn push_underscore_spanned(tokens: &mut TokenStream, span: Span) { + tokens.append(Ident::new("_", span)); +} + +// Helper method for constructing identifiers from the `format_ident!` macro, +// handling `r#` prefixes. +#[doc(hidden)] +pub fn mk_ident(id: &str, span: Option) -> Ident { + let span = span.unwrap_or_else(Span::call_site); + ident_maybe_raw(id, span) +} + +fn ident_maybe_raw(id: &str, span: Span) -> Ident { + if let Some(id) = id.strip_prefix("r#") { + Ident::new_raw(id, span) + } else { + Ident::new(id, span) + } +} + +// Adapts from `IdentFragment` to `fmt::Display` for use by the `format_ident!` +// macro, and exposes span information from these fragments. +// +// This struct also has forwarding implementations of the formatting traits +// `Octal`, `LowerHex`, `UpperHex`, and `Binary` to allow for their use within +// `format_ident!`. +#[derive(Copy, Clone)] +#[doc(hidden)] +pub struct IdentFragmentAdapter(pub T); + +impl IdentFragmentAdapter { + pub fn span(&self) -> Option { + self.0.span() + } +} + +impl fmt::Display for IdentFragmentAdapter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + IdentFragment::fmt(&self.0, f) + } +} + +impl fmt::Octal for IdentFragmentAdapter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Octal::fmt(&self.0, f) + } +} + +impl fmt::LowerHex for IdentFragmentAdapter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::LowerHex::fmt(&self.0, f) + } +} + +impl fmt::UpperHex for IdentFragmentAdapter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::UpperHex::fmt(&self.0, f) + } +} + +impl fmt::Binary for IdentFragmentAdapter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Binary::fmt(&self.0, f) + } +} diff --git a/third_party/crates/quote-1.0.47/src/spanned.rs b/third_party/crates/quote-1.0.47/src/spanned.rs new file mode 100644 index 0000000..6afc6b3 --- /dev/null +++ b/third_party/crates/quote-1.0.47/src/spanned.rs @@ -0,0 +1,49 @@ +use crate::ToTokens; +use proc_macro2::extra::DelimSpan; +use proc_macro2::{Span, TokenStream}; + +// Not public API other than via the syn crate. Use syn::spanned::Spanned. +pub trait Spanned: private::Sealed { + fn __span(&self) -> Span; +} + +impl Spanned for Span { + fn __span(&self) -> Span { + *self + } +} + +impl Spanned for DelimSpan { + fn __span(&self) -> Span { + self.join() + } +} + +impl Spanned for T { + fn __span(&self) -> Span { + join_spans(self.into_token_stream()) + } +} + +fn join_spans(tokens: TokenStream) -> Span { + let mut iter = tokens.into_iter().map(|tt| tt.span()); + + let Some(first) = iter.next() else { + return Span::call_site(); + }; + + iter.fold(None, |_prev, next| Some(next)) + .and_then(|last| first.join(last)) + .unwrap_or(first) +} + +mod private { + use crate::ToTokens; + use proc_macro2::extra::DelimSpan; + use proc_macro2::Span; + + pub trait Sealed {} + impl Sealed for Span {} + impl Sealed for DelimSpan {} + impl Sealed for T {} +} diff --git a/third_party/crates/quote-1.0.47/src/to_tokens.rs b/third_party/crates/quote-1.0.47/src/to_tokens.rs new file mode 100644 index 0000000..aff1a71 --- /dev/null +++ b/third_party/crates/quote-1.0.47/src/to_tokens.rs @@ -0,0 +1,281 @@ +use super::TokenStreamExt; +use alloc::borrow::{Cow, ToOwned}; +use alloc::boxed::Box; +use alloc::ffi::CString; +use alloc::rc::Rc; +use alloc::string::String; +use core::ffi::CStr; +use core::iter; +use proc_macro2::{Group, Ident, Literal, Punct, Span, TokenStream, TokenTree}; +use std::sync::Arc; + +/// Types that can be interpolated inside a `quote!` invocation. +pub trait ToTokens { + /// Write `self` to the given `TokenStream`. + /// + /// The token append methods provided by the [`TokenStreamExt`] extension + /// trait may be useful for implementing `ToTokens`. + /// + /// # Example + /// + /// Example implementation for a struct representing Rust paths like + /// `std::cmp::PartialEq`: + /// + /// ``` + /// use proc_macro2::{TokenTree, Spacing, Span, Punct, TokenStream}; + /// use quote::{TokenStreamExt, ToTokens}; + /// + /// pub struct Path { + /// pub global: bool, + /// pub segments: Vec, + /// } + /// + /// impl ToTokens for Path { + /// fn to_tokens(&self, tokens: &mut TokenStream) { + /// for (i, segment) in self.segments.iter().enumerate() { + /// if i > 0 || self.global { + /// // Double colon `::` + /// tokens.append(Punct::new(':', Spacing::Joint)); + /// tokens.append(Punct::new(':', Spacing::Alone)); + /// } + /// segment.to_tokens(tokens); + /// } + /// } + /// } + /// # + /// # pub struct PathSegment; + /// # + /// # impl ToTokens for PathSegment { + /// # fn to_tokens(&self, tokens: &mut TokenStream) { + /// # unimplemented!() + /// # } + /// # } + /// ``` + fn to_tokens(&self, tokens: &mut TokenStream); + + /// Convert `self` directly into a `TokenStream` object. + /// + /// This method is implicitly implemented using `to_tokens`, and acts as a + /// convenience method for consumers of the `ToTokens` trait. + fn to_token_stream(&self) -> TokenStream { + let mut tokens = TokenStream::new(); + self.to_tokens(&mut tokens); + tokens + } + + /// Convert `self` directly into a `TokenStream` object. + /// + /// This method is implicitly implemented using `to_tokens`, and acts as a + /// convenience method for consumers of the `ToTokens` trait. + fn into_token_stream(self) -> TokenStream + where + Self: Sized, + { + self.to_token_stream() + } +} + +impl ToTokens for &T { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens); + } +} + +impl ToTokens for &mut T { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens); + } +} + +impl<'a, T: ?Sized + ToOwned + ToTokens> ToTokens for Cow<'a, T> { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens); + } +} + +impl ToTokens for Box { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens); + } +} + +impl ToTokens for Rc { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens); + } +} + +impl ToTokens for Arc { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens); + } +} + +impl ToTokens for Option { + fn to_tokens(&self, tokens: &mut TokenStream) { + if let Some(t) = self { + t.to_tokens(tokens); + } + } +} + +impl ToTokens for str { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Literal::string(self)); + } +} + +impl ToTokens for String { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.as_str().to_tokens(tokens); + } +} + +impl ToTokens for i8 { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Literal::i8_suffixed(*self)); + } +} + +impl ToTokens for i16 { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Literal::i16_suffixed(*self)); + } +} + +impl ToTokens for i32 { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Literal::i32_suffixed(*self)); + } +} + +impl ToTokens for i64 { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Literal::i64_suffixed(*self)); + } +} + +impl ToTokens for i128 { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Literal::i128_suffixed(*self)); + } +} + +impl ToTokens for isize { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Literal::isize_suffixed(*self)); + } +} + +impl ToTokens for u8 { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Literal::u8_suffixed(*self)); + } +} + +impl ToTokens for u16 { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Literal::u16_suffixed(*self)); + } +} + +impl ToTokens for u32 { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Literal::u32_suffixed(*self)); + } +} + +impl ToTokens for u64 { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Literal::u64_suffixed(*self)); + } +} + +impl ToTokens for u128 { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Literal::u128_suffixed(*self)); + } +} + +impl ToTokens for usize { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Literal::usize_suffixed(*self)); + } +} + +impl ToTokens for f32 { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Literal::f32_suffixed(*self)); + } +} + +impl ToTokens for f64 { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Literal::f64_suffixed(*self)); + } +} + +impl ToTokens for char { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Literal::character(*self)); + } +} + +impl ToTokens for bool { + fn to_tokens(&self, tokens: &mut TokenStream) { + let word = if *self { "true" } else { "false" }; + tokens.append(Ident::new(word, Span::call_site())); + } +} + +impl ToTokens for CStr { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Literal::c_string(self)); + } +} + +impl ToTokens for CString { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Literal::c_string(self)); + } +} + +impl ToTokens for Group { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(self.clone()); + } +} + +impl ToTokens for Ident { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(self.clone()); + } +} + +impl ToTokens for Punct { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(self.clone()); + } +} + +impl ToTokens for Literal { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(self.clone()); + } +} + +impl ToTokens for TokenTree { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(self.clone()); + } +} + +impl ToTokens for TokenStream { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.extend(iter::once(self.clone())); + } + + fn into_token_stream(self) -> TokenStream { + self + } +} diff --git a/third_party/crates/quote-1.0.47/tests/compiletest.rs b/third_party/crates/quote-1.0.47/tests/compiletest.rs new file mode 100644 index 0000000..23a6a06 --- /dev/null +++ b/third_party/crates/quote-1.0.47/tests/compiletest.rs @@ -0,0 +1,7 @@ +#[rustversion::attr(not(nightly), ignore = "requires nightly")] +#[cfg_attr(miri, ignore = "incompatible with miri")] +#[test] +fn ui() { + let t = trybuild::TestCases::new(); + t.compile_fail("tests/ui/*.rs"); +} diff --git a/third_party/crates/quote-1.0.47/tests/test.rs b/third_party/crates/quote-1.0.47/tests/test.rs new file mode 100644 index 0000000..ecce963 --- /dev/null +++ b/third_party/crates/quote-1.0.47/tests/test.rs @@ -0,0 +1,575 @@ +#![allow( + clippy::disallowed_names, + clippy::let_underscore_untyped, + clippy::shadow_unrelated, + clippy::unseparated_literal_suffix, + clippy::used_underscore_binding +)] + +extern crate proc_macro; + +use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream}; +use quote::{format_ident, quote, quote_spanned, TokenStreamExt}; +use std::borrow::Cow; +use std::collections::BTreeSet; +use std::ffi::{CStr, CString}; + +struct X; + +impl quote::ToTokens for X { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Ident::new("X", Span::call_site())); + } +} + +#[test] +fn test_quote_impl() { + let tokens = quote! { + impl<'a, T: ToTokens> ToTokens for &'a T { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens) + } + } + }; + + let expected = concat!( + "impl < 'a , T : ToTokens > ToTokens for & 'a T { ", + "fn to_tokens (& self , tokens : & mut TokenStream) { ", + "(* * self) . to_tokens (tokens) ", + "} ", + "}" + ); + + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_quote_spanned_impl() { + let span = Span::call_site(); + let tokens = quote_spanned! {span=> + impl<'a, T: ToTokens> ToTokens for &'a T { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens) + } + } + }; + + let expected = concat!( + "impl < 'a , T : ToTokens > ToTokens for & 'a T { ", + "fn to_tokens (& self , tokens : & mut TokenStream) { ", + "(* * self) . to_tokens (tokens) ", + "} ", + "}" + ); + + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_substitution() { + let x = X; + let tokens = quote!(#x <#x> (#x) [#x] {#x}); + + let expected = "X < X > (X) [X] { X }"; + + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_iter() { + let primes = &[X, X, X, X]; + + assert_eq!("X X X X", quote!(#(#primes)*).to_string()); + + assert_eq!("X , X , X , X ,", quote!(#(#primes,)*).to_string()); + + assert_eq!("X , X , X , X", quote!(#(#primes),*).to_string()); +} + +#[test] +fn test_array() { + let array: [u8; 40] = [0; 40]; + let _ = quote!(#(#array #array)*); + + let ref_array: &[u8; 40] = &[0; 40]; + let _ = quote!(#(#ref_array #ref_array)*); + + let ref_slice: &[u8] = &[0; 40]; + let _ = quote!(#(#ref_slice #ref_slice)*); + + let array: [X; 2] = [X, X]; // !Copy + let _ = quote!(#(#array #array)*); + + let ref_array: &[X; 2] = &[X, X]; + let _ = quote!(#(#ref_array #ref_array)*); + + let ref_slice: &[X] = &[X, X]; + let _ = quote!(#(#ref_slice #ref_slice)*); + + let array_of_array: [[u8; 2]; 2] = [[0; 2]; 2]; + let _ = quote!(#(#(#array_of_array)*)*); +} + +#[test] +fn test_advanced() { + let generics = quote!( <'a, T> ); + + let where_clause = quote!( where T: Serialize ); + + let field_ty = quote!(String); + + let item_ty = quote!(Cow<'a, str>); + + let path = quote!(SomeTrait::serialize_with); + + let value = quote!(self.x); + + let tokens = quote! { + struct SerializeWith #generics #where_clause { + value: &'a #field_ty, + phantom: ::std::marker::PhantomData<#item_ty>, + } + + impl #generics ::serde::Serialize for SerializeWith #generics #where_clause { + fn serialize(&self, s: &mut S) -> Result<(), S::Error> + where S: ::serde::Serializer + { + #path(self.value, s) + } + } + + SerializeWith { + value: #value, + phantom: ::std::marker::PhantomData::<#item_ty>, + } + }; + + let expected = concat!( + "struct SerializeWith < 'a , T > where T : Serialize { ", + "value : & 'a String , ", + "phantom : :: std :: marker :: PhantomData < Cow < 'a , str > > , ", + "} ", + "impl < 'a , T > :: serde :: Serialize for SerializeWith < 'a , T > where T : Serialize { ", + "fn serialize < S > (& self , s : & mut S) -> Result < () , S :: Error > ", + "where S : :: serde :: Serializer ", + "{ ", + "SomeTrait :: serialize_with (self . value , s) ", + "} ", + "} ", + "SerializeWith { ", + "value : self . x , ", + "phantom : :: std :: marker :: PhantomData :: < Cow < 'a , str > > , ", + "}" + ); + + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_integer() { + let ii8 = -1i8; + let ii16 = -1i16; + let ii32 = -1i32; + let ii64 = -1i64; + let ii128 = -1i128; + let iisize = -1isize; + let uu8 = 1u8; + let uu16 = 1u16; + let uu32 = 1u32; + let uu64 = 1u64; + let uu128 = 1u128; + let uusize = 1usize; + + let tokens = quote! { + 1 1i32 1u256 + #ii8 #ii16 #ii32 #ii64 #ii128 #iisize + #uu8 #uu16 #uu32 #uu64 #uu128 #uusize + }; + let expected = + "1 1i32 1u256 - 1i8 - 1i16 - 1i32 - 1i64 - 1i128 - 1isize 1u8 1u16 1u32 1u64 1u128 1usize"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_floating() { + let e32 = 2.345f32; + + let e64 = 2.345f64; + + let tokens = quote! { + #e32 + #e64 + }; + let expected = "2.345f32 2.345f64"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_char() { + let zero = '\u{1}'; + let pound = '#'; + let quote = '"'; + let apost = '\''; + let newline = '\n'; + let heart = '\u{2764}'; + + let tokens = quote! { + #zero #pound #quote #apost #newline #heart + }; + let expected = "'\\u{1}' '#' '\"' '\\'' '\\n' '\u{2764}'"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_str() { + let s = "\u{1} a 'b \" c"; + let tokens = quote!(#s); + let expected = "\"\\u{1} a 'b \\\" c\""; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_string() { + let s = "\u{1} a 'b \" c".to_string(); + let tokens = quote!(#s); + let expected = "\"\\u{1} a 'b \\\" c\""; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_c_str() { + let s = CStr::from_bytes_with_nul(b"\x01 a 'b \" c\0").unwrap(); + let tokens = quote!(#s); + let expected = "c\"\\u{1} a 'b \\\" c\""; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_c_string() { + let s = CString::new(&b"\x01 a 'b \" c"[..]).unwrap(); + let tokens = quote!(#s); + let expected = "c\"\\u{1} a 'b \\\" c\""; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_interpolated_literal() { + macro_rules! m { + ($literal:literal) => { + quote!($literal) + }; + } + + let tokens = m!(1); + let expected = "1"; + assert_eq!(expected, tokens.to_string()); + + let tokens = m!(-1); + let expected = "- 1"; + assert_eq!(expected, tokens.to_string()); + + let tokens = m!(true); + let expected = "true"; + assert_eq!(expected, tokens.to_string()); + + let tokens = m!(-true); + let expected = "- true"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_ident() { + let foo = Ident::new("Foo", Span::call_site()); + let bar = Ident::new(&format!("Bar{}", 7), Span::call_site()); + let tokens = quote!(struct #foo; enum #bar {}); + let expected = "struct Foo ; enum Bar7 { }"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_underscore() { + let tokens = quote!(let _;); + let expected = "let _ ;"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_duplicate() { + let ch = 'x'; + + let tokens = quote!(#ch #ch); + + let expected = "'x' 'x'"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_fancy_repetition() { + let foo = vec!["a", "b"]; + let bar = vec![true, false]; + + let tokens = quote! { + #(#foo: #bar),* + }; + + let expected = r#""a" : true , "b" : false"#; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_nested_fancy_repetition() { + let nested = vec![vec!['a', 'b', 'c'], vec!['x', 'y', 'z']]; + + let tokens = quote! { + #( + #(#nested)* + ),* + }; + + let expected = "'a' 'b' 'c' , 'x' 'y' 'z'"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_duplicate_name_repetition() { + let foo = &["a", "b"]; + + let tokens = quote! { + #(#foo: #foo),* + #(#foo: #foo),* + }; + + let expected = r#""a" : "a" , "b" : "b" "a" : "a" , "b" : "b""#; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_duplicate_name_repetition_no_copy() { + let foo = vec!["a".to_owned(), "b".to_owned()]; + + let tokens = quote! { + #(#foo: #foo),* + }; + + let expected = r#""a" : "a" , "b" : "b""#; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_btreeset_repetition() { + let mut set = BTreeSet::new(); + set.insert("a".to_owned()); + set.insert("b".to_owned()); + + let tokens = quote! { + #(#set: #set),* + }; + + let expected = r#""a" : "a" , "b" : "b""#; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_variable_name_conflict() { + // The implementation of `#(...),*` uses the variable `_i` but it should be + // fine, if a little confusing when debugging. + let _i = vec!['a', 'b']; + let tokens = quote! { #(#_i),* }; + let expected = "'a' , 'b'"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_nonrep_in_repetition() { + let rep = vec!["a", "b"]; + let nonrep = "c"; + + let tokens = quote! { + #(#rep #rep : #nonrep #nonrep),* + }; + + let expected = r#""a" "a" : "c" "c" , "b" "b" : "c" "c""#; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_empty_quote() { + let tokens = quote!(); + assert_eq!("", tokens.to_string()); +} + +#[test] +fn test_box_str() { + let b = "str".to_owned().into_boxed_str(); + let tokens = quote! { #b }; + assert_eq!("\"str\"", tokens.to_string()); +} + +#[test] +fn test_cow() { + let owned: Cow = Cow::Owned(Ident::new("owned", Span::call_site())); + + let ident = Ident::new("borrowed", Span::call_site()); + let borrowed = Cow::Borrowed(&ident); + + let tokens = quote! { #owned #borrowed }; + assert_eq!("owned borrowed", tokens.to_string()); +} + +#[test] +fn test_closure() { + fn field_i(i: usize) -> Ident { + format_ident!("__field{}", i) + } + + let fields = (0usize..3) + .map(field_i as fn(_) -> _) + .map(|var| quote! { #var }); + + let tokens = quote! { #(#fields)* }; + assert_eq!("__field0 __field1 __field2", tokens.to_string()); +} + +#[test] +fn test_append_tokens() { + let mut a = quote!(a); + let b = quote!(b); + a.append_all(b); + assert_eq!("a b", a.to_string()); +} + +#[test] +fn test_format_ident() { + let id0 = format_ident!("Aa"); + let id1 = format_ident!("Hello{x}", x = id0); + let id2 = format_ident!("Hello{x}", x = 5usize); + let id3 = format_ident!("Hello{}_{x}", id0, x = 10usize); + let id4 = format_ident!("Aa", span = Span::call_site()); + let id5 = format_ident!("Hello{}", Cow::Borrowed("World")); + + assert_eq!(id0, "Aa"); + assert_eq!(id1, "HelloAa"); + assert_eq!(id2, "Hello5"); + assert_eq!(id3, "HelloAa_10"); + assert_eq!(id4, "Aa"); + assert_eq!(id5, "HelloWorld"); +} + +#[test] +fn test_format_ident_strip_raw() { + let id = format_ident!("r#struct"); + let my_id = format_ident!("MyId{}", id); + let raw_my_id = format_ident!("r#MyId{}", id); + + assert_eq!(id, "r#struct"); + assert_eq!(my_id, "MyIdstruct"); + assert_eq!(raw_my_id, "r#MyIdstruct"); +} + +#[test] +fn test_outer_line_comment() { + let tokens = quote! { + /// doc + }; + let expected = "# [doc = r\" doc\"]"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_inner_line_comment() { + let tokens = quote! { + //! doc + }; + let expected = "# ! [doc = r\" doc\"]"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_outer_block_comment() { + let tokens = quote! { + /** doc */ + }; + let expected = "# [doc = r\" doc \"]"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_inner_block_comment() { + let tokens = quote! { + /*! doc */ + }; + let expected = "# ! [doc = r\" doc \"]"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_outer_attr() { + let tokens = quote! { + #[inline] + }; + let expected = "# [inline]"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_inner_attr() { + let tokens = quote! { + #![no_std] + }; + let expected = "# ! [no_std]"; + assert_eq!(expected, tokens.to_string()); +} + +// https://github.com/dtolnay/quote/issues/130 +#[test] +fn test_star_after_repetition() { + let c = vec!['0', '1']; + let tokens = quote! { + #( + f(#c); + )* + *out = None; + }; + let expected = "f ('0') ; f ('1') ; * out = None ;"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_quote_raw_id() { + let id = quote!(r#raw_id); + assert_eq!(id.to_string(), "r#raw_id"); +} + +#[test] +fn test_quote_raw_lifetime() { + let lifetime = quote!('r#async); + assert_eq!(lifetime.to_string(), "'r#async"); +} + +#[test] +fn test_type_inference_for_span() { + trait CallSite { + fn get() -> Self; + } + + impl CallSite for Span { + fn get() -> Self { + Span::call_site() + } + } + + let span = Span::call_site(); + let _ = quote_spanned!(span=> ...); + + let delim_span = Group::new(Delimiter::Parenthesis, TokenStream::new()).delim_span(); + let _ = quote_spanned!(delim_span=> ...); + + let inferred = CallSite::get(); + let _ = quote_spanned!(inferred=> ...); + + #[cfg(feature = "proc-macro")] + if false { + let proc_macro_span = proc_macro::Span::call_site(); + let _ = quote_spanned!(proc_macro_span.into()=> ...); + } +} diff --git a/third_party/crates/quote-1.0.47/tests/ui/does-not-have-iter-interpolated-dup.rs b/third_party/crates/quote-1.0.47/tests/ui/does-not-have-iter-interpolated-dup.rs new file mode 100644 index 0000000..0a39f41 --- /dev/null +++ b/third_party/crates/quote-1.0.47/tests/ui/does-not-have-iter-interpolated-dup.rs @@ -0,0 +1,9 @@ +use quote::quote; + +fn main() { + let nonrep = ""; + + // Without some protection against repetitions with no iterator somewhere + // inside, this would loop infinitely. + quote!(#(#nonrep #nonrep)*); +} diff --git a/third_party/crates/quote-1.0.47/tests/ui/does-not-have-iter-interpolated-dup.stderr b/third_party/crates/quote-1.0.47/tests/ui/does-not-have-iter-interpolated-dup.stderr new file mode 100644 index 0000000..c759738 --- /dev/null +++ b/third_party/crates/quote-1.0.47/tests/ui/does-not-have-iter-interpolated-dup.stderr @@ -0,0 +1,13 @@ +error[E0277]: repetition contains no interpolated value that is an iterator + --> tests/ui/does-not-have-iter-interpolated-dup.rs:8:5 + | +8 | quote!(#(#nonrep #nonrep)*); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ none of the values interpolated inside this repetition are iterable + | +help: the trait `quote::__private::CheckHasIterator` is not implemented for `HasIterator` + but it is implemented for `HasIterator` + --> src/runtime.rs + | + | impl CheckHasIterator for HasIterator {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `$crate::quote_token_with_context` which comes from the expansion of the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/crates/quote-1.0.47/tests/ui/does-not-have-iter-interpolated.rs b/third_party/crates/quote-1.0.47/tests/ui/does-not-have-iter-interpolated.rs new file mode 100644 index 0000000..2c740cc --- /dev/null +++ b/third_party/crates/quote-1.0.47/tests/ui/does-not-have-iter-interpolated.rs @@ -0,0 +1,9 @@ +use quote::quote; + +fn main() { + let nonrep = ""; + + // Without some protection against repetitions with no iterator somewhere + // inside, this would loop infinitely. + quote!(#(#nonrep)*); +} diff --git a/third_party/crates/quote-1.0.47/tests/ui/does-not-have-iter-interpolated.stderr b/third_party/crates/quote-1.0.47/tests/ui/does-not-have-iter-interpolated.stderr new file mode 100644 index 0000000..999fc70 --- /dev/null +++ b/third_party/crates/quote-1.0.47/tests/ui/does-not-have-iter-interpolated.stderr @@ -0,0 +1,13 @@ +error[E0277]: repetition contains no interpolated value that is an iterator + --> tests/ui/does-not-have-iter-interpolated.rs:8:5 + | +8 | quote!(#(#nonrep)*); + | ^^^^^^^^^^^^^^^^^^^ none of the values interpolated inside this repetition are iterable + | +help: the trait `quote::__private::CheckHasIterator` is not implemented for `HasIterator` + but it is implemented for `HasIterator` + --> src/runtime.rs + | + | impl CheckHasIterator for HasIterator {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `$crate::quote_token_with_context` which comes from the expansion of the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/crates/quote-1.0.47/tests/ui/does-not-have-iter-separated.rs b/third_party/crates/quote-1.0.47/tests/ui/does-not-have-iter-separated.rs new file mode 100644 index 0000000..c027243 --- /dev/null +++ b/third_party/crates/quote-1.0.47/tests/ui/does-not-have-iter-separated.rs @@ -0,0 +1,5 @@ +use quote::quote; + +fn main() { + quote!(#(a b),*); +} diff --git a/third_party/crates/quote-1.0.47/tests/ui/does-not-have-iter-separated.stderr b/third_party/crates/quote-1.0.47/tests/ui/does-not-have-iter-separated.stderr new file mode 100644 index 0000000..a7617dc --- /dev/null +++ b/third_party/crates/quote-1.0.47/tests/ui/does-not-have-iter-separated.stderr @@ -0,0 +1,13 @@ +error[E0277]: repetition contains no interpolated value that is an iterator + --> tests/ui/does-not-have-iter-separated.rs:4:5 + | +4 | quote!(#(a b),*); + | ^^^^^^^^^^^^^^^^ none of the values interpolated inside this repetition are iterable + | +help: the trait `quote::__private::CheckHasIterator` is not implemented for `HasIterator` + but it is implemented for `HasIterator` + --> src/runtime.rs + | + | impl CheckHasIterator for HasIterator {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `$crate::quote_token_with_context` which comes from the expansion of the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/crates/quote-1.0.47/tests/ui/does-not-have-iter.rs b/third_party/crates/quote-1.0.47/tests/ui/does-not-have-iter.rs new file mode 100644 index 0000000..8908353 --- /dev/null +++ b/third_party/crates/quote-1.0.47/tests/ui/does-not-have-iter.rs @@ -0,0 +1,5 @@ +use quote::quote; + +fn main() { + quote!(#(a b)*); +} diff --git a/third_party/crates/quote-1.0.47/tests/ui/does-not-have-iter.stderr b/third_party/crates/quote-1.0.47/tests/ui/does-not-have-iter.stderr new file mode 100644 index 0000000..5f34788 --- /dev/null +++ b/third_party/crates/quote-1.0.47/tests/ui/does-not-have-iter.stderr @@ -0,0 +1,13 @@ +error[E0277]: repetition contains no interpolated value that is an iterator + --> tests/ui/does-not-have-iter.rs:4:5 + | +4 | quote!(#(a b)*); + | ^^^^^^^^^^^^^^^ none of the values interpolated inside this repetition are iterable + | +help: the trait `quote::__private::CheckHasIterator` is not implemented for `HasIterator` + but it is implemented for `HasIterator` + --> src/runtime.rs + | + | impl CheckHasIterator for HasIterator {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `$crate::quote_token_with_context` which comes from the expansion of the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/crates/quote-1.0.47/tests/ui/not-quotable.rs b/third_party/crates/quote-1.0.47/tests/ui/not-quotable.rs new file mode 100644 index 0000000..f991c18 --- /dev/null +++ b/third_party/crates/quote-1.0.47/tests/ui/not-quotable.rs @@ -0,0 +1,7 @@ +use quote::quote; +use std::net::Ipv4Addr; + +fn main() { + let ip = Ipv4Addr::LOCALHOST; + let _ = quote! { #ip }; +} diff --git a/third_party/crates/quote-1.0.47/tests/ui/not-quotable.stderr b/third_party/crates/quote-1.0.47/tests/ui/not-quotable.stderr new file mode 100644 index 0000000..d48d00d --- /dev/null +++ b/third_party/crates/quote-1.0.47/tests/ui/not-quotable.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `Ipv4Addr: ToTokens` is not satisfied + --> tests/ui/not-quotable.rs:6:13 + | +6 | let _ = quote! { #ip }; + | ^^^^^^^^^^^^^^ + | | + | the trait `ToTokens` is not implemented for `Ipv4Addr` + | required by a bound introduced by this call + | + = help: the following other types implement trait `ToTokens`: + &T + &mut T + Arc + Box + CStr + CString + Cow<'a, T> + Option + and $N others + = note: this error originates in the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/crates/quote-1.0.47/tests/ui/not-repeatable.rs b/third_party/crates/quote-1.0.47/tests/ui/not-repeatable.rs new file mode 100644 index 0000000..a8f0fe7 --- /dev/null +++ b/third_party/crates/quote-1.0.47/tests/ui/not-repeatable.rs @@ -0,0 +1,8 @@ +use quote::quote; + +struct Ipv4Addr; + +fn main() { + let ip = Ipv4Addr; + let _ = quote! { #(#ip)* }; +} diff --git a/third_party/crates/quote-1.0.47/tests/ui/not-repeatable.stderr b/third_party/crates/quote-1.0.47/tests/ui/not-repeatable.stderr new file mode 100644 index 0000000..1ab1fd4 --- /dev/null +++ b/third_party/crates/quote-1.0.47/tests/ui/not-repeatable.stderr @@ -0,0 +1,34 @@ +error[E0599]: the method `quote_into_iter` exists for struct `Ipv4Addr`, but its trait bounds were not satisfied + --> tests/ui/not-repeatable.rs:7:13 + | +3 | struct Ipv4Addr; + | --------------- method `quote_into_iter` not found for this struct because `Ipv4Addr` doesn't implement `Iterator` or `ToTokens` +... +7 | let _ = quote! { #(#ip)* }; + | ^^^^^^^^^^^^^^^^^^ method cannot be called on `Ipv4Addr` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `Ipv4Addr: Iterator` + which is required by `Ipv4Addr: quote::__private::ext::RepIteratorExt` + `&Ipv4Addr: Iterator` + which is required by `&Ipv4Addr: quote::__private::ext::RepIteratorExt` + `Ipv4Addr: ToTokens` + which is required by `Ipv4Addr: quote::__private::ext::RepToTokensExt` + `&mut Ipv4Addr: Iterator` + which is required by `&mut Ipv4Addr: quote::__private::ext::RepIteratorExt` +note: the traits `Iterator` and `ToTokens` must be implemented + --> $RUST/core/src/iter/traits/iterator.rs + | + | pub const trait Iterator { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + ::: src/to_tokens.rs + | + | pub trait ToTokens { + | ^^^^^^^^^^^^^^^^^^ + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following traits define an item `quote_into_iter`, perhaps you need to implement one of them: + candidate #1: `quote::__private::ext::RepAsIteratorExt` + candidate #2: `quote::__private::ext::RepIteratorExt` + candidate #3: `quote::__private::ext::RepToTokensExt` + = note: this error originates in the macro `$crate::quote_bind_into_iter` which comes from the expansion of the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/crates/quote-1.0.47/tests/ui/wrong-type-span.rs b/third_party/crates/quote-1.0.47/tests/ui/wrong-type-span.rs new file mode 100644 index 0000000..d5601c8 --- /dev/null +++ b/third_party/crates/quote-1.0.47/tests/ui/wrong-type-span.rs @@ -0,0 +1,7 @@ +use quote::quote_spanned; + +fn main() { + let span = ""; + let x = 0i32; + quote_spanned!(span=> #x); +} diff --git a/third_party/crates/quote-1.0.47/tests/ui/wrong-type-span.stderr b/third_party/crates/quote-1.0.47/tests/ui/wrong-type-span.stderr new file mode 100644 index 0000000..12ad307 --- /dev/null +++ b/third_party/crates/quote-1.0.47/tests/ui/wrong-type-span.stderr @@ -0,0 +1,10 @@ +error[E0308]: mismatched types + --> tests/ui/wrong-type-span.rs:6:5 + | +6 | quote_spanned!(span=> #x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected `Span`, found `&str` + | expected due to this + | + = note: this error originates in the macro `quote_spanned` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/crates/serde-1.0.229/.cargo-checksum.json b/third_party/crates/serde-1.0.229/.cargo-checksum.json new file mode 100644 index 0000000..59eaa65 --- /dev/null +++ b/third_party/crates/serde-1.0.229/.cargo-checksum.json @@ -0,0 +1 @@ +{"$comment":"This file only protects against accidental modifications. It is not a security mechanism and does not protect against malicious changes.","files":{".cargo_vcs_info.json":"a5356e10a935346365e8744c75a7a6eb0ee0edbfb8074b712b19953c6e02e57e","Cargo.lock":"27e973a8db87258e9d422ae4b72bfccbb55f2e91393f447b5943a45b90b3f9f2","Cargo.toml":"6883caefd46e86eb15d22d3a6d274ad304c5e7934ab70eb58d81b7c4a29ef9db","Cargo.toml.orig":"137d4b56580e6b18d0cad4a86aea12a8b83b8f985a931b089de553161c35af56","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"0a33359b87747c0ae2437374c1dd4fc4d151ae3122b3931e2757b45d0ed519b8","build.rs":"e2ea6a7a82f5404c3e28cb055883c737ee7903367a10206fbb47b75c009f0eb3","crates-io.md":"00b72e63d4f3393e28f9a219c8cb8c122013d82f0d10d6d551e239b13c5ba9e4","src/core/crate_root.rs":"157ca402e23c32f11a4f1797c81afb5e9f08df96768012cf3e3199153aafb2dd","src/core/de/ignored_any.rs":"6480f2b2a83dc4764d01b2eec7309729eef2492eede2e5ee98d23a60b05198eb","src/core/de/impls.rs":"2f8e2ef9d343875bb996319e69feae0dee2287e2548cedd8d3c752b64812331c","src/core/de/mod.rs":"5ec8602d593915e0cf480b0ce67b02f6ab066dac34725237d2c7b4a6ef12a845","src/core/de/value.rs":"fb6fef6d23d95d516c6e1d6b5cefd8b98ba3881214a82a8a7e0a8ffbb0a12083","src/core/format.rs":"c85071b016df643b161859682d21ce34fa0ebf2a3bdbeeea69859da48f5d934f","src/core/lib.rs":"4e5c396d38ff5d9abf45b826a67ec3444654ed0802d057f46400ebe26f5879f8","src/core/macros.rs":"a61c9d19b210697304328e6bb9380a1de713e21042256df90a2b4553f178b0be","src/core/private/content.rs":"5fdfb2bb95ecc80375507acb813a4c640496385e56fc99ab448f6b19e01fcc01","src/core/private/doc.rs":"abe656c015267555ca26ebbcf2f4dcc52c719a0b9ade3a5ed4635b2784699b8c","src/core/private/mod.rs":"3bb3427ec80077b9df1853aa17681de796de0179d74871a96b88b72469de6cfc","src/core/private/seed.rs":"3f6e098c5bd314788370dcaf3ab0152fcd7feb6bcf36a9c51808938cd58071eb","src/core/private/size_hint.rs":"350694a2abaad94ca5d33958710a5bb8973a2ea1a3dcc50a41405c943761b81f","src/core/private/string.rs":"c1500fd4b64c24a5e45fa5f48c85c802816d6954a2999a72fc5a8861687212d4","src/core/ser/fmt.rs":"bd129d9f085933b76dafef6eb43ffac893c1f6484a3064dcd82faeeebc3b203c","src/core/ser/impls.rs":"5ee7efc439345e8665da0bd79bc06c02a0506e5fd0f3a4cf11af0c7197eaa643","src/core/ser/impossible.rs":"283f628d5107aa030d2e96eeb1dee187f0ac18c24d517edeb51738ab15dfb871","src/core/ser/mod.rs":"ec097d92c8545356961e977a4c9650361cadd1d3a243d805ae7b0e0e589ae803","src/core/std_error.rs":"b36fd6a2b6898770b9f1c51517eb362af115767d0f7cb4a713e1b949530ffa8a","src/integer128.rs":"a5ca321ace6b11b71f637397cf4ea41992545a9c297a23230c8a9e8b92db71fa","src/lib.rs":"9fcd921cee5dc64077f4027a3b42347253fdc3f3d9b88660e8c872c316db3620","src/private/de.rs":"68ee17774d3bbc693d9f19803747fa2c3afdb7046482e6d94ac6cf7db5a4fe20","src/private/mod.rs":"52cc5b33364b13724ea4c2989f3ccd8ba02a2ef903761499e15264835ff76388","src/private/ser.rs":"bea364a6199b57c2aa5a96a6bb0530176850dbeaaee908a6307fe610c873c8e3"},"package":"4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"} \ No newline at end of file diff --git a/third_party/crates/serde-1.0.229/.cargo_vcs_info.json b/third_party/crates/serde-1.0.229/.cargo_vcs_info.json new file mode 100644 index 0000000..427920b --- /dev/null +++ b/third_party/crates/serde-1.0.229/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "7fc3b4c30c94f73a96ebd1553f2b090d928fc3a8" + }, + "path_in_vcs": "serde" +} \ No newline at end of file diff --git a/third_party/crates/serde-1.0.229/BUILD.bazel b/third_party/crates/serde-1.0.229/BUILD.bazel new file mode 100644 index 0000000..192090d --- /dev/null +++ b/third_party/crates/serde-1.0.229/BUILD.bazel @@ -0,0 +1,195 @@ +############################################################################### +# @generated +# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To +# regenerate this file, run the following: +# +# bazel run @@//third_party:vendor_crates +############################################################################### + +load( + "@rules_rust//cargo:defs.bzl", + "cargo_build_script", + "cargo_toml_env_vars", +) +load("@rules_rust//rust:defs.bzl", "rust_library") + +package(default_visibility = ["//visibility:public"]) + +cargo_toml_env_vars( + name = "cargo_toml_env_vars", + src = "Cargo.toml", +) + +rust_library( + name = "serde", + srcs = glob( + include = ["**/*.rs"], + allow_empty = False, + ), + compile_data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + crate_features = [ + "default", + "derive", + "serde_derive", + "std", + ], + crate_root = "src/lib.rs", + edition = "2021", + proc_macro_deps = [ + "//third_party/crates/serde_derive-1.0.229:serde_derive", + ], + rustc_env_files = [ + ":cargo_toml_env_vars", + ], + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=serde", + "manual", + "noclippy", + "norustfmt", + ], + target_compatible_with = select({ + "@rules_rust//rust/platform:aarch64-apple-darwin": [], + "@rules_rust//rust/platform:aarch64-apple-ios": [], + "@rules_rust//rust/platform:aarch64-apple-ios-macabi": [], + "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], + "@rules_rust//rust/platform:aarch64-linux-android": [], + "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], + "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], + "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-none": [], + "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], + "@rules_rust//rust/platform:aarch64-unknown-uefi": [], + "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], + "@rules_rust//rust/platform:armv7-linux-androideabi": [], + "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:i686-apple-darwin": [], + "@rules_rust//rust/platform:i686-linux-android": [], + "@rules_rust//rust/platform:i686-pc-windows-msvc": [], + "@rules_rust//rust/platform:i686-unknown-freebsd": [], + "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], + "@rules_rust//rust/platform:loongarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:mips-unknown-linux-gnu": [], + "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv32imac-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], + "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-netbsd": [], + "@rules_rust//rust/platform:sparc64-unknown-openbsd": [], + "@rules_rust//rust/platform:thumbv6m-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabihf": [], + "@rules_rust//rust/platform:thumbv7m-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabihf": [], + "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], + "@rules_rust//rust/platform:wasm32-unknown-unknown": [], + "@rules_rust//rust/platform:wasm32-wasip1": [], + "@rules_rust//rust/platform:wasm32-wasip1-threads": [], + "@rules_rust//rust/platform:wasm32-wasip2": [], + "@rules_rust//rust/platform:x86_64-apple-darwin": [], + "@rules_rust//rust/platform:x86_64-apple-ios": [], + "@rules_rust//rust/platform:x86_64-apple-ios-macabi": [], + "@rules_rust//rust/platform:x86_64-linux-android": [], + "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], + "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], + "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], + "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-none": [], + "@rules_rust//rust/platform:x86_64-unknown-uefi": [], + "//conditions:default": ["@platforms//:incompatible"], + }), + version = "1.0.229", + deps = [ + ":build_script_build", + "//third_party/crates/serde_core-1.0.229:serde_core", + ], +) + +cargo_build_script( + name = "_bs", + srcs = glob( + include = ["**/*.rs"], + allow_empty = False, + ), + build_script_env_files = [ + ":cargo_toml_env_vars", + ], + compile_data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + "**/*.rs", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + crate_features = [ + "default", + "derive", + "serde_derive", + "std", + ], + crate_name = "build_script_build", + crate_root = "build.rs", + data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + edition = "2021", + emit_warnings = False, + pkg_name = "serde", + rustc_env_files = [ + ":cargo_toml_env_vars", + ], + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=serde", + "manual", + "noclippy", + "norustfmt", + ], + version = "1.0.229", + visibility = ["//visibility:private"], +) + +alias( + name = "build_script_build", + actual = ":_bs", + tags = ["manual"], +) diff --git a/third_party/crates/serde-1.0.229/Cargo.lock b/third_party/crates/serde-1.0.229/Cargo.lock new file mode 100644 index 0000000..108fb83 --- /dev/null +++ b/third_party/crates/serde-1.0.229/Cargo.lock @@ -0,0 +1,66 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "serde" +version = "1.0.229" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fac314a64dc9a36e61a9eb4261a5e9bbfbc922b27e518af97bc32b926cf967" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" diff --git a/third_party/crates/serde-1.0.229/Cargo.toml b/third_party/crates/serde-1.0.229/Cargo.toml new file mode 100644 index 0000000..f56bd8a --- /dev/null +++ b/third_party/crates/serde-1.0.229/Cargo.toml @@ -0,0 +1,84 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.56" +name = "serde" +version = "1.0.229" +authors = [ + "Erick Tryzelaar ", + "David Tolnay ", +] +build = "build.rs" +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "A generic serialization/deserialization framework" +homepage = "https://serde.rs" +documentation = "https://docs.rs/serde" +readme = "crates-io.md" +keywords = [ + "serde", + "serialization", + "no_std", +] +categories = [ + "encoding", + "no-std", + "no-std::no-alloc", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/serde-rs/serde" + +[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] +alloc = ["serde_core/alloc"] +default = ["std"] +derive = ["serde_derive"] +rc = ["serde_core/rc"] +std = ["serde_core/std"] +unstable = ["serde_core/unstable"] + +[lib] +name = "serde" +path = "src/lib.rs" + +[dependencies.serde_core] +version = "=1.0.229" +features = ["result"] +default-features = false + +[dependencies.serde_derive] +version = "1" +optional = true diff --git a/third_party/crates/serde-1.0.229/Cargo.toml.orig b/third_party/crates/serde-1.0.229/Cargo.toml.orig new file mode 100644 index 0000000..dda0783 --- /dev/null +++ b/third_party/crates/serde-1.0.229/Cargo.toml.orig @@ -0,0 +1,62 @@ +[package] +name = "serde" +version = "1.0.229" +authors = ["Erick Tryzelaar ", "David Tolnay "] +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" +keywords = ["serde", "serialization", "no_std"] +license = "MIT OR Apache-2.0" +readme = "crates-io.md" +repository = "https://github.com/serde-rs/serde" +rust-version = "1.56" + +[dependencies] +serde_core = { version = "=1.0.229", 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 ################################################################# + +[features] +default = ["std"] + +# Provide derive(Serialize, Deserialize) macros. +derive = ["serde_derive"] + +# Provide impls for common standard library types like Vec and HashMap. +# Requires a dependency on the Rust standard library. +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 = ["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 = ["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 = ["serde_core/rc"] diff --git a/third_party/crates/serde-1.0.229/LICENSE-APACHE b/third_party/crates/serde-1.0.229/LICENSE-APACHE new file mode 100644 index 0000000..1b5ec8b --- /dev/null +++ b/third_party/crates/serde-1.0.229/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/third_party/crates/serde-1.0.229/LICENSE-MIT b/third_party/crates/serde-1.0.229/LICENSE-MIT new file mode 100644 index 0000000..31aa793 --- /dev/null +++ b/third_party/crates/serde-1.0.229/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/crates/serde-1.0.229/README.md b/third_party/crates/serde-1.0.229/README.md new file mode 100644 index 0000000..681b874 --- /dev/null +++ b/third_party/crates/serde-1.0.229/README.md @@ -0,0 +1,114 @@ +# Serde   [![Build Status]][actions] [![Latest Version]][crates.io] [![serde msrv]][Rust 1.56] [![serde_derive msrv]][Rust 1.71] + +[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 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.71]: https://blog.rust-lang.org/2023/07/13/Rust-1.71.0/ + +**Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.** + +--- + +You may be looking for: + +- [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.rs/serde) +- [Release notes](https://github.com/serde-rs/serde/releases) + +## Serde in action + +
+ +Click to show Cargo.toml. +Run this code in the playground. + + +```toml +[dependencies] + +# The core APIs, including the Serialize and Deserialize traits. Always +# required when using Serde. The "derive" feature is only required when +# using #[derive(Serialize, Deserialize)] to make Serde work with structs +# and enums defined in your crate. +serde = { version = "1.0", features = ["derive"] } + +# Each data format lives in its own crate; the sample code below uses JSON +# but you may be using a different one. +serde_json = "1.0" +``` + +
+

+ +```rust +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug)] +struct Point { + x: i32, + y: i32, +} + +fn main() { + let point = Point { x: 1, y: 2 }; + + // Convert the Point to a JSON string. + let serialized = serde_json::to_string(&point).unwrap(); + + // Prints serialized = {"x":1,"y":2} + println!("serialized = {}", serialized); + + // Convert the JSON string back to a Point. + let deserialized: Point = serde_json::from_str(&serialized).unwrap(); + + // Prints deserialized = Point { x: 1, y: 2 } + println!("deserialized = {:?}", deserialized); +} +``` + +## Getting help + +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 +[#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 +[discourse]: https://users.rust-lang.org + +
+ +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + diff --git a/third_party/crates/serde-1.0.229/build.rs b/third_party/crates/serde-1.0.229/build.rs new file mode 100644 index 0000000..3a8f419 --- /dev/null +++ b/third_party/crates/serde-1.0.229/build.rs @@ -0,0 +1,69 @@ +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::*; +} +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, + }; + + 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)"); + } + + // Current minimum supported version of serde_derive crate is Rust 1.71. + if minor < 71 { + println!("cargo:rustc-cfg=no_serde_derive"); + } + + // 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 = 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/third_party/crates/serde-1.0.229/crates-io.md b/third_party/crates/serde-1.0.229/crates-io.md new file mode 100644 index 0000000..e6e7d9f --- /dev/null +++ b/third_party/crates/serde-1.0.229/crates-io.md @@ -0,0 +1,65 @@ + + +**Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.** + +--- + +You may be looking for: + +- [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.rs/serde) +- [Release notes](https://github.com/serde-rs/serde/releases) + +## Serde in action + +```rust +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug)] +struct Point { + x: i32, + y: i32, +} + +fn main() { + let point = Point { x: 1, y: 2 }; + + // Convert the Point to a JSON string. + let serialized = serde_json::to_string(&point).unwrap(); + + // Prints serialized = {"x":1,"y":2} + println!("serialized = {}", serialized); + + // Convert the JSON string back to a Point. + let deserialized: Point = serde_json::from_str(&serialized).unwrap(); + + // Prints deserialized = Point { x: 1, y: 2 } + println!("deserialized = {:?}", deserialized); +} +``` + +## Getting help + +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 +[#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 +[discourse]: https://users.rust-lang.org diff --git a/third_party/crates/serde-1.0.229/src/core/crate_root.rs b/third_party/crates/serde-1.0.229/src/core/crate_root.rs new file mode 100644 index 0000000..2cf75a4 --- /dev/null +++ b/third_party/crates/serde-1.0.229/src/core/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/third_party/crates/serde-1.0.229/src/core/de/ignored_any.rs b/third_party/crates/serde-1.0.229/src/core/de/ignored_any.rs new file mode 100644 index 0000000..2360a17 --- /dev/null +++ b/third_party/crates/serde-1.0.229/src/core/de/ignored_any.rs @@ -0,0 +1,238 @@ +use crate::lib::*; + +use crate::de::{ + Deserialize, Deserializer, EnumAccess, Error, MapAccess, SeqAccess, VariantAccess, Visitor, +}; + +/// An efficient way of discarding data from a deserializer. +/// +/// Think of this like `serde_json::Value` in that it can be deserialized from +/// any type, except that it does not store any information about the data that +/// gets deserialized. +/// +/// ```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`. +/// /// +/// /// For example to deserialize only the element at index 3: +/// /// +/// /// ``` +/// /// NthElement::new(3).deserialize(deserializer) +/// /// ``` +/// pub struct NthElement { +/// n: usize, +/// marker: PhantomData, +/// } +/// +/// impl NthElement { +/// pub fn new(n: usize) -> Self { +/// NthElement { +/// n: n, +/// marker: PhantomData, +/// } +/// } +/// } +/// +/// impl<'de, T> Visitor<'de> for NthElement +/// where +/// T: Deserialize<'de>, +/// { +/// type Value = T; +/// +/// fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { +/// write!( +/// formatter, +/// "a sequence in which we care about element {}", +/// self.n +/// ) +/// } +/// +/// fn visit_seq(self, mut seq: A) -> Result +/// where +/// A: SeqAccess<'de>, +/// { +/// // Skip over the first `n` elements. +/// for i in 0..self.n { +/// // It is an error if the sequence ends before we get to element `n`. +/// if seq.next_element::()?.is_none() { +/// return Err(de::Error::invalid_length(i, &self)); +/// } +/// } +/// +/// // Deserialize the one we care about. +/// let nth = match seq.next_element()? { +/// Some(nth) => nth, +/// None => { +/// return Err(de::Error::invalid_length(self.n, &self)); +/// } +/// }; +/// +/// // Skip over any remaining elements in the sequence after `n`. +/// while let Some(IgnoredAny) = seq.next_element()? { +/// // ignore +/// } +/// +/// Ok(nth) +/// } +/// } +/// +/// impl<'de, T> DeserializeSeed<'de> for NthElement +/// where +/// T: Deserialize<'de>, +/// { +/// type Value = T; +/// +/// fn deserialize(self, deserializer: D) -> Result +/// where +/// D: Deserializer<'de>, +/// { +/// deserializer.deserialize_seq(self) +/// } +/// } +/// +/// # fn example<'de, D>(deserializer: D) -> Result<(), D::Error> +/// # where +/// # D: Deserializer<'de>, +/// # { +/// // Deserialize only the sequence element at index 3 from this deserializer. +/// // The element at index 3 is required to be a string. Elements before and +/// // after index 3 are allowed to be of any type. +/// let s: String = NthElement::new(3).deserialize(deserializer)?; +/// # Ok(()) +/// # } +/// ``` +#[derive(Copy, Clone, Debug, Default, PartialEq)] +pub struct IgnoredAny; + +impl<'de> Visitor<'de> for IgnoredAny { + type Value = IgnoredAny; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("anything at all") + } + + #[inline] + fn visit_bool(self, x: bool) -> Result { + let _ = x; + Ok(IgnoredAny) + } + + #[inline] + fn visit_i64(self, x: i64) -> Result { + let _ = x; + 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; + Ok(IgnoredAny) + } + + #[inline] + fn visit_str(self, s: &str) -> Result + where + E: Error, + { + let _ = s; + Ok(IgnoredAny) + } + + #[inline] + fn visit_none(self) -> Result { + Ok(IgnoredAny) + } + + #[inline] + fn visit_some(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + IgnoredAny::deserialize(deserializer) + } + + #[inline] + fn visit_newtype_struct(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + IgnoredAny::deserialize(deserializer) + } + + #[inline] + fn visit_unit(self) -> Result { + Ok(IgnoredAny) + } + + #[inline] + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + while let Some(IgnoredAny) = tri!(seq.next_element()) { + // Gobble + } + Ok(IgnoredAny) + } + + #[inline] + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + while let Some((IgnoredAny, IgnoredAny)) = tri!(map.next_entry()) { + // Gobble + } + Ok(IgnoredAny) + } + + #[inline] + fn visit_bytes(self, bytes: &[u8]) -> Result + where + E: Error, + { + let _ = bytes; + Ok(IgnoredAny) + } + + fn visit_enum(self, data: A) -> Result + where + A: EnumAccess<'de>, + { + tri!(data.variant::()).1.newtype_variant() + } +} + +impl<'de> Deserialize<'de> for IgnoredAny { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_ignored_any(IgnoredAny) + } +} diff --git a/third_party/crates/serde-1.0.229/src/core/de/impls.rs b/third_party/crates/serde-1.0.229/src/core/de/impls.rs new file mode 100644 index 0000000..3a1458e --- /dev/null +++ b/third_party/crates/serde-1.0.229/src/core/de/impls.rs @@ -0,0 +1,3173 @@ +use crate::lib::*; + +use crate::de::{ + Deserialize, Deserializer, EnumAccess, Error, MapAccess, SeqAccess, Unexpected, VariantAccess, + Visitor, +}; +use crate::private::{self, InPlaceSeed}; + +#[cfg(any(feature = "std", feature = "alloc"))] +use crate::private::size_hint; + +//////////////////////////////////////////////////////////////////////////////// + +struct UnitVisitor; + +impl<'de> Visitor<'de> for UnitVisitor { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("unit") + } + + fn visit_unit(self) -> Result + where + E: Error, + { + Ok(()) + } +} + +impl<'de> Deserialize<'de> for () { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_unit(UnitVisitor) + } +} + +#[cfg(feature = "unstable")] +#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] +impl<'de> Deserialize<'de> for ! { + fn deserialize(_deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Err(Error::custom("cannot deserialize `!`")) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +struct BoolVisitor; + +impl<'de> Visitor<'de> for BoolVisitor { + type Value = bool; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a boolean") + } + + fn visit_bool(self, v: bool) -> Result + where + E: Error, + { + Ok(v) + } +} + +impl<'de> Deserialize<'de> for bool { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_bool(BoolVisitor) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +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) + } + } + + #[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) + } + } + }; + + ($primitive:ident, $deserialize:ident $($method:ident!($($val:ident : $visit:ident)*);)*) => { + impl<'de> Deserialize<'de> for $primitive { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct PrimitiveVisitor; + + impl<'de> Visitor<'de> for PrimitiveVisitor { + type Value = $primitive; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(stringify!($primitive)) + } + + $($($method!($val : $visit);)*)* + } + + deserializer.$deserialize(PrimitiveVisitor) + } + } + }; +} + +macro_rules! num_self { + ($ty:ident : $visit:ident) => { + #[inline] + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + Ok(v) + } + }; + + (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)) + } + } + }; + + (saturating $primitive:ident $ty:ident : $visit:ident) => { + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + Ok(Saturating(v)) + } + }; +} + +macro_rules! num_as_self { + ($ty:ident : $visit:ident) => { + #[inline] + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + Ok(v as Self::Value) + } + }; + + (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)) + } + } + }; + + (saturating $primitive:ident $ty:ident : $visit:ident) => { + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + Ok(Saturating(v as $primitive)) + } + }; +} + +macro_rules! num_as_copysign_self { + ($ty:ident : $visit:ident) => { + #[inline] + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + #[cfg(not(feature = "std"))] + { + Ok(v as Self::Value) + } + + #[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)) + } + } + }; +} + +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)) + } + }; + + (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)) + } + } + }; +} + +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)) + } + }; + + (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)) + } + }; + + (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)) + } + } + }; +} + +macro_rules! uint_to_self { + ($ty:ident : $visit:ident) => { + #[inline] + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + Self::Value::try_from(v as u64) + .map_err(|_| Error::invalid_value(Unexpected::Unsigned(v as u64), &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 u64) { + if let Some(nonzero) = Self::Value::new(v) { + return Ok(nonzero); + } + } + Err(Error::invalid_value(Unexpected::Unsigned(v as u64), &self)) + } + }; + + (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)) + } + } + }; +} + +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); +} + +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, + )) + } + } + }; + + (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); +} + +//////////////////////////////////////////////////////////////////////////////// + +struct CharVisitor; + +impl<'de> Visitor<'de> for CharVisitor { + type Value = char; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a character") + } + + #[inline] + fn visit_char(self, v: char) -> Result + where + E: Error, + { + Ok(v) + } + + #[inline] + fn visit_str(self, v: &str) -> Result + where + E: Error, + { + let mut iter = v.chars(); + match (iter.next(), iter.next()) { + (Some(c), None) => Ok(c), + _ => Err(Error::invalid_value(Unexpected::Str(v), &self)), + } + } +} + +impl<'de> Deserialize<'de> for char { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_char(CharVisitor) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(any(feature = "std", feature = "alloc"))] +struct StringVisitor; +#[cfg(any(feature = "std", feature = "alloc"))] +struct StringInPlaceVisitor<'a>(&'a mut String); + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'de> Visitor<'de> for StringVisitor { + type Value = String; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a string") + } + + fn visit_str(self, v: &str) -> Result + where + E: Error, + { + Ok(v.to_owned()) + } + + fn visit_string(self, v: String) -> Result + where + E: Error, + { + Ok(v) + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: Error, + { + match str::from_utf8(v) { + Ok(s) => Ok(s.to_owned()), + Err(_) => Err(Error::invalid_value(Unexpected::Bytes(v), &self)), + } + } + + fn visit_byte_buf(self, v: Vec) -> Result + where + E: Error, + { + match String::from_utf8(v) { + Ok(s) => Ok(s), + Err(e) => Err(Error::invalid_value( + Unexpected::Bytes(&e.into_bytes()), + &self, + )), + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, 'de> Visitor<'de> for StringInPlaceVisitor<'a> { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a string") + } + + fn visit_str(self, v: &str) -> Result + where + E: Error, + { + self.0.clear(); + self.0.push_str(v); + Ok(()) + } + + fn visit_string(self, v: String) -> Result + where + E: Error, + { + *self.0 = v; + Ok(()) + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: Error, + { + match str::from_utf8(v) { + Ok(s) => { + self.0.clear(); + self.0.push_str(s); + Ok(()) + } + Err(_) => Err(Error::invalid_value(Unexpected::Bytes(v), &self)), + } + } + + fn visit_byte_buf(self, v: Vec) -> Result + where + E: Error, + { + match String::from_utf8(v) { + Ok(s) => { + *self.0 = s; + Ok(()) + } + Err(e) => Err(Error::invalid_value( + Unexpected::Bytes(&e.into_bytes()), + &self, + )), + } + } +} + +#[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 + D: Deserializer<'de>, + { + deserializer.deserialize_string(StringVisitor) + } + + fn deserialize_in_place(deserializer: D, place: &mut Self) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_string(StringInPlaceVisitor(place)) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +struct StrVisitor; + +impl<'a> Visitor<'a> for StrVisitor { + type Value = &'a str; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a borrowed string") + } + + fn visit_borrowed_str(self, v: &'a str) -> Result + where + E: Error, + { + Ok(v) // so easy + } + + fn visit_borrowed_bytes(self, v: &'a [u8]) -> Result + where + E: Error, + { + str::from_utf8(v).map_err(|_| Error::invalid_value(Unexpected::Bytes(v), &self)) + } +} + +impl<'de: 'a, 'a> Deserialize<'de> for &'a str { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(StrVisitor) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +struct BytesVisitor; + +impl<'a> Visitor<'a> for BytesVisitor { + type Value = &'a [u8]; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a borrowed byte array") + } + + fn visit_borrowed_bytes(self, v: &'a [u8]) -> Result + where + E: Error, + { + Ok(v) + } + + fn visit_borrowed_str(self, v: &'a str) -> Result + where + E: Error, + { + Ok(v.as_bytes()) + } +} + +impl<'de: 'a, 'a> Deserialize<'de> for &'a [u8] { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_bytes(BytesVisitor) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(any(feature = "std", all(not(no_core_cstr), feature = "alloc")))] +struct CStringVisitor; + +#[cfg(any(feature = "std", all(not(no_core_cstr), feature = "alloc")))] +impl<'de> Visitor<'de> for CStringVisitor { + type Value = CString; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("byte array") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let capacity = size_hint::cautious::(seq.size_hint()); + let mut values = Vec::::with_capacity(capacity); + + while let Some(value) = tri!(seq.next_element()) { + values.push(value); + } + + CString::new(values).map_err(Error::custom) + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: Error, + { + CString::new(v).map_err(Error::custom) + } + + fn visit_byte_buf(self, v: Vec) -> Result + where + E: Error, + { + CString::new(v).map_err(Error::custom) + } + + fn visit_str(self, v: &str) -> Result + where + E: Error, + { + CString::new(v).map_err(Error::custom) + } + + fn visit_string(self, v: String) -> Result + where + E: Error, + { + CString::new(v).map_err(Error::custom) + } +} + +#[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 + D: Deserializer<'de>, + { + deserializer.deserialize_byte_buf(CStringVisitor) + } +} + +macro_rules! forwarded_impl { + ( + $(#[$attr:meta])* + ($($id:ident),*), $ty:ty, $func:expr + ) => { + $(#[$attr])* + impl<'de $(, $id : Deserialize<'de>,)*> Deserialize<'de> for $ty { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Deserialize::deserialize(deserializer).map($func) + } + } + } +} + +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 +} + +forwarded_impl! { + (T), Reverse, Reverse +} + +//////////////////////////////////////////////////////////////////////////////// + +struct OptionVisitor { + marker: PhantomData, +} + +impl<'de, T> Visitor<'de> for OptionVisitor +where + T: Deserialize<'de>, +{ + type Value = Option; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("option") + } + + #[inline] + fn visit_unit(self) -> Result + where + E: Error, + { + Ok(None) + } + + #[inline] + fn visit_none(self) -> Result + where + E: Error, + { + Ok(None) + } + + #[inline] + fn visit_some(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + T::deserialize(deserializer).map(Some) + } + + fn __private_visit_untagged_option(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Ok(T::deserialize(deserializer).ok()) + } +} + +impl<'de, T> Deserialize<'de> for Option +where + T: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_option(OptionVisitor { + marker: PhantomData, + }) + } + + // The Some variant's repr is opaque, so we can't play cute tricks with its + // tag to have deserialize_in_place build the content in place unconditionally. + // + // FIXME: investigate whether branching on the old value being Some to + // deserialize_in_place the value is profitable (probably data-dependent?) +} + +//////////////////////////////////////////////////////////////////////////////// + +struct PhantomDataVisitor { + marker: PhantomData, +} + +impl<'de, T> Visitor<'de> for PhantomDataVisitor +where + T: ?Sized, +{ + type Value = PhantomData; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("unit") + } + + #[inline] + fn visit_unit(self) -> Result + where + E: Error, + { + Ok(PhantomData) + } +} + +impl<'de, T> Deserialize<'de> for PhantomData +where + T: ?Sized, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let visitor = PhantomDataVisitor { + marker: PhantomData, + }; + deserializer.deserialize_unit_struct("PhantomData", visitor) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! seq_impl { + ( + $(#[$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)*)*, + $($typaram: $bound1 $(+ $bound2)*,)* + { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct SeqVisitor { + marker: PhantomData<$ty>, + } + + impl<'de, T $(, $typaram)*> Visitor<'de> for SeqVisitor + where + T: Deserialize<'de> $(+ $tbound1 $(+ $tbound2)*)*, + $($typaram: $bound1 $(+ $bound2)*,)* + { + type Value = $ty; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a sequence") + } + + #[inline] + fn visit_seq(self, mut $access: A) -> Result + where + A: SeqAccess<'de>, + { + let mut values = $with_capacity; + + while let Some(value) = tri!($access.next_element()) { + $insert(&mut values, value); + } + + Ok(values) + } + } + + let visitor = SeqVisitor { marker: PhantomData }; + deserializer.deserialize_seq(visitor) + } + + fn deserialize_in_place(deserializer: D, place: &mut Self) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + struct SeqInPlaceVisitor<'a, T: 'a $(, $typaram: 'a)*>(&'a mut $ty); + + impl<'a, 'de, T $(, $typaram)*> Visitor<'de> for SeqInPlaceVisitor<'a, T $(, $typaram)*> + where + T: Deserialize<'de> $(+ $tbound1 $(+ $tbound2)*)*, + $($typaram: $bound1 $(+ $bound2)*,)* + { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a sequence") + } + + #[inline] + fn visit_seq(self, mut $access: A) -> Result + where + A: SeqAccess<'de>, + { + $clear(&mut *self.0); + $reserve(&mut *self.0, size_hint::cautious::($access.size_hint())); + + // FIXME: try to overwrite old values here? (Vec, VecDeque, LinkedList) + while let Some(value) = tri!($access.next_element()) { + $insert(&mut *self.0, value); + } + + Ok(()) + } + } + + deserializer.deserialize_seq(SeqInPlaceVisitor(place)) + } + } + } +} + +// Dummy impl of reserve +#[cfg(any(feature = "std", feature = "alloc"))] +fn nop_reserve(_seq: T, _n: usize) {} + +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::reserve, + BinaryHeap::push +); + +seq_impl!( + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + BTreeSet, + seq, + BTreeSet::clear, + BTreeSet::new(), + nop_reserve, + BTreeSet::insert +); + +seq_impl!( + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + LinkedList, + seq, + LinkedList::clear, + LinkedList::new(), + nop_reserve, + LinkedList::push_back +); + +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::reserve, + HashSet::insert +); + +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::reserve, + VecDeque::push_back +); + +//////////////////////////////////////////////////////////////////////////////// + +#[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>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct VecVisitor { + marker: PhantomData, + } + + impl<'de, T> Visitor<'de> for VecVisitor + where + T: Deserialize<'de>, + { + type Value = Vec; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a sequence") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let capacity = size_hint::cautious::(seq.size_hint()); + let mut values = Vec::::with_capacity(capacity); + + while let Some(value) = tri!(seq.next_element()) { + values.push(value); + } + + Ok(values) + } + } + + let visitor = VecVisitor { + marker: PhantomData, + }; + deserializer.deserialize_seq(visitor) + } + + fn deserialize_in_place(deserializer: D, place: &mut Self) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + struct VecInPlaceVisitor<'a, T: 'a>(&'a mut Vec); + + impl<'a, 'de, T> Visitor<'de> for VecInPlaceVisitor<'a, T> + where + T: Deserialize<'de>, + { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a sequence") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let hint = size_hint::cautious::(seq.size_hint()); + if let Some(additional) = hint.checked_sub(self.0.len()) { + self.0.reserve(additional); + } + + for i in 0..self.0.len() { + let next = { + let next_place = InPlaceSeed(&mut self.0[i]); + tri!(seq.next_element_seed(next_place)) + }; + if next.is_none() { + self.0.truncate(i); + return Ok(()); + } + } + + while let Some(value) = tri!(seq.next_element()) { + self.0.push(value); + } + + Ok(()) + } + } + + deserializer.deserialize_seq(VecInPlaceVisitor(place)) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +struct ArrayVisitor { + marker: PhantomData, +} +struct ArrayInPlaceVisitor<'a, A: 'a>(&'a mut A); + +impl ArrayVisitor { + fn new() -> Self { + ArrayVisitor { + marker: PhantomData, + } + } +} + +impl<'de, T> Visitor<'de> for ArrayVisitor<[T; 0]> { + type Value = [T; 0]; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("an empty array") + } + + #[inline] + fn visit_seq(self, _: A) -> Result + where + A: SeqAccess<'de>, + { + Ok([]) + } +} + +// Does not require T: Deserialize<'de>. +impl<'de, T> Deserialize<'de> for [T; 0] { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_tuple(0, ArrayVisitor::<[T; 0]>::new()) + } +} + +macro_rules! array_impls { + ($($len:expr => ($($n:tt)+))+) => { + $( + impl<'de, T> Visitor<'de> for ArrayVisitor<[T; $len]> + where + T: Deserialize<'de>, + { + type Value = [T; $len]; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(concat!("an array of length ", $len)) + } + + #[inline] + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + Ok([$( + match tri!(seq.next_element()) { + Some(val) => val, + None => return Err(Error::invalid_length($n, &self)), + } + ),+]) + } + } + + impl<'a, 'de, T> Visitor<'de> for ArrayInPlaceVisitor<'a, [T; $len]> + where + T: Deserialize<'de>, + { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(concat!("an array of length ", $len)) + } + + #[inline] + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let mut fail_idx = None; + for (idx, dest) in self.0[..].iter_mut().enumerate() { + if tri!(seq.next_element_seed(InPlaceSeed(dest))).is_none() { + fail_idx = Some(idx); + break; + } + } + if let Some(idx) = fail_idx { + return Err(Error::invalid_length(idx, &self)); + } + Ok(()) + } + } + + impl<'de, T> Deserialize<'de> for [T; $len] + where + T: Deserialize<'de>, + { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_tuple($len, ArrayVisitor::<[T; $len]>::new()) + } + + fn deserialize_in_place(deserializer: D, place: &mut Self) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_tuple($len, ArrayInPlaceVisitor(place)) + } + } + )+ + } +} + +array_impls! { + 1 => (0) + 2 => (0 1) + 3 => (0 1 2) + 4 => (0 1 2 3) + 5 => (0 1 2 3 4) + 6 => (0 1 2 3 4 5) + 7 => (0 1 2 3 4 5 6) + 8 => (0 1 2 3 4 5 6 7) + 9 => (0 1 2 3 4 5 6 7 8) + 10 => (0 1 2 3 4 5 6 7 8 9) + 11 => (0 1 2 3 4 5 6 7 8 9 10) + 12 => (0 1 2 3 4 5 6 7 8 9 10 11) + 13 => (0 1 2 3 4 5 6 7 8 9 10 11 12) + 14 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13) + 15 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14) + 16 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) + 17 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16) + 18 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17) + 19 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18) + 20 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19) + 21 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20) + 22 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21) + 23 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22) + 24 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23) + 25 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24) + 26 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25) + 27 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26) + 28 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27) + 29 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28) + 30 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29) + 31 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30) + 32 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31) +} + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! tuple_impls { + ($($len:tt => ($($n:tt $name:ident)+))+) => { + $( + #[cfg_attr(docsrs, doc(hidden))] + impl<'de, $($name),+> Deserialize<'de> for ($($name,)+) + where + $($name: Deserialize<'de>,)+ + { + tuple_impl_body!($len => ($($n $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,)+)>, + } + + impl<'de, $($name: Deserialize<'de>),+> Visitor<'de> for TupleVisitor<$($name,)+> { + type Value = ($($name,)+); + + 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>, + { + $( + let $name = match tri!(seq.next_element()) { + Some(value) => value, + None => return Err(Error::invalid_length($n, &self)), + }; + )+ + + Ok(($($name,)+)) + } + } + + deserializer.deserialize_tuple($len, TupleVisitor { marker: PhantomData }) + } + + #[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,)+)); + + 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)); + } + )+ + + 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! { + 2 => (0 T0 1 T1) + 3 => (0 T0 1 T1 2 T2) + 4 => (0 T0 1 T1 2 T2 3 T3) + 5 => (0 T0 1 T1 2 T2 3 T3 4 T4) + 6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5) + 7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6) + 8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7) + 9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8) + 10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9) + 11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10) + 12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11) + 13 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12) + 14 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13) + 15 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14) + 16 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15) +} + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! map_impl { + ( + $(#[$attr:meta])* + $ty:ident , + $access:ident, + $with_capacity:expr, + ) => { + $(#[$attr])* + impl<'de, K, V $(, $typaram)*> Deserialize<'de> for $ty + where + K: Deserialize<'de> $(+ $kbound1 $(+ $kbound2)*)*, + V: Deserialize<'de>, + $($typaram: $bound1 $(+ $bound2)*),* + { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct MapVisitor { + marker: PhantomData<$ty>, + } + + impl<'de, K, V $(, $typaram)*> Visitor<'de> for MapVisitor + where + K: Deserialize<'de> $(+ $kbound1 $(+ $kbound2)*)*, + V: Deserialize<'de>, + $($typaram: $bound1 $(+ $bound2)*),* + { + type Value = $ty; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a map") + } + + #[inline] + fn visit_map(self, mut $access: A) -> Result + where + A: MapAccess<'de>, + { + let mut values = $with_capacity; + + while let Some((key, value)) = tri!($access.next_entry()) { + values.insert(key, value); + } + + Ok(values) + } + } + + let visitor = MapVisitor { marker: PhantomData }; + deserializer.deserialize_map(visitor) + } + } + } +} + +map_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + BTreeMap, + map, + BTreeMap::new(), +} + +map_impl! { + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + HashMap, + map, + HashMap::with_capacity_and_hasher(size_hint::cautious::<(K, V)>(map.size_hint()), S::default()), +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(any(feature = "std", not(no_core_net)))] +macro_rules! parse_ip_impl { + ($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() { + deserializer.deserialize_str(FromStrVisitor::new($expecting)) + } else { + <[u8; $size]>::deserialize(deserializer).map(<$ty>::from) + } + } + } + }; +} + +#[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 + ) => { + enum $name_kind { + $($variant),* + } + + static $variants_name: &[&str] = &[$(stringify!($variant)),*]; + + impl<'de> Deserialize<'de> for $name_kind { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct KindVisitor; + + impl<'de> Visitor<'de> for KindVisitor { + type Value = $name_kind; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str($expecting_message) + } + + fn visit_u64(self, value: u64) -> Result + where + E: Error, + { + match value { + $( + $index => Ok($name_kind :: $variant), + )* + _ => Err(Error::invalid_value(Unexpected::Unsigned(value), &self),), + } + } + + fn visit_str(self, value: &str) -> Result + where + E: Error, + { + match value { + $( + stringify!($variant) => Ok($name_kind :: $variant), + )* + _ => Err(Error::unknown_variant(value, $variants_name)), + } + } + + fn visit_bytes(self, value: &[u8]) -> Result + where + E: Error, + { + match value { + $( + $bytes => Ok($name_kind :: $variant), + )* + _ => { + match str::from_utf8(value) { + Ok(value) => Err(Error::unknown_variant(value, $variants_name)), + Err(_) => Err(Error::invalid_value(Unexpected::Bytes(value), &self)), + } + } + } + } + } + + deserializer.deserialize_identifier(KindVisitor) + } + } + } +} + +#[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 + ) => { + variant_identifier! { + $name_kind ($($variant; $bytes; $index),*) + $expecting_message, + VARIANTS + } + + struct EnumVisitor; + impl<'de> Visitor<'de> for EnumVisitor { + type Value = $name; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(concat!("a ", stringify!($name))) + } + + + fn visit_enum(self, data: A) -> Result + where + A: EnumAccess<'de>, + { + match tri!(data.variant()) { + $( + ($name_kind :: $variant, v) => v.newtype_variant().map($name :: $variant), + )* + } + } + } + $deserializer.deserialize_enum(stringify!($name), VARIANTS, EnumVisitor) + } +} + +#[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() { + deserializer.deserialize_str(FromStrVisitor::new("IP address")) + } else { + use crate::lib::net::IpAddr; + deserialize_enum! { + IpAddr IpAddrKind (V4; b"V4"; 0, V6; b"V6"; 1) + "`V4` or `V6`", + deserializer + } + } + } +} + +#[cfg(any(feature = "std", not(no_core_net)))] +parse_ip_impl!(net::Ipv4Addr, "IPv4 address", 4); + +#[cfg(any(feature = "std", not(no_core_net)))] +parse_ip_impl!(net::Ipv6Addr, "IPv6 address", 16); + +#[cfg(any(feature = "std", not(no_core_net)))] +macro_rules! parse_socket_impl { + ( + $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() { + deserializer.deserialize_str(FromStrVisitor::new($expecting)) + } else { + <(_, u16)>::deserialize(deserializer).map($new) + } + } + } + }; +} + +#[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() { + deserializer.deserialize_str(FromStrVisitor::new("socket address")) + } else { + use crate::lib::net::SocketAddr; + deserialize_enum! { + SocketAddr SocketAddrKind (V4; b"V4"; 0, V6; b"V6"; 1) + "`V4` or `V6`", + deserializer + } + } + } +} + +#[cfg(any(feature = "std", not(no_core_net)))] +parse_socket_impl! { + net::SocketAddrV4, "IPv4 socket address", + |(ip, port)| net::SocketAddrV4::new(ip, port), +} + +#[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), +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "std")] +struct PathVisitor; + +#[cfg(feature = "std")] +impl<'a> Visitor<'a> for PathVisitor { + type Value = &'a Path; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a borrowed path") + } + + fn visit_borrowed_str(self, v: &'a str) -> Result + where + E: Error, + { + Ok(v.as_ref()) + } + + fn visit_borrowed_bytes(self, v: &'a [u8]) -> Result + where + E: Error, + { + str::from_utf8(v) + .map(AsRef::as_ref) + .map_err(|_| Error::invalid_value(Unexpected::Bytes(v), &self)) + } +} + +#[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 + D: Deserializer<'de>, + { + deserializer.deserialize_str(PathVisitor) + } +} + +#[cfg(feature = "std")] +struct PathBufVisitor; + +#[cfg(feature = "std")] +impl<'de> Visitor<'de> for PathBufVisitor { + type Value = PathBuf; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("path string") + } + + fn visit_str(self, v: &str) -> Result + where + E: Error, + { + Ok(From::from(v)) + } + + fn visit_string(self, v: String) -> Result + where + E: Error, + { + Ok(From::from(v)) + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: Error, + { + str::from_utf8(v) + .map(From::from) + .map_err(|_| Error::invalid_value(Unexpected::Bytes(v), &self)) + } + + fn visit_byte_buf(self, v: Vec) -> Result + where + E: Error, + { + String::from_utf8(v) + .map(From::from) + .map_err(|e| Error::invalid_value(Unexpected::Bytes(&e.into_bytes()), &self)) + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl<'de> Deserialize<'de> for PathBuf { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_string(PathBufVisitor) + } +} + +forwarded_impl! { + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + (), Box, PathBuf::into_boxed_path +} + +//////////////////////////////////////////////////////////////////////////////// + +// If this were outside of the serde crate, it would just use: +// +// #[derive(Deserialize)] +// #[serde(variant_identifier)] +#[cfg(all(feature = "std", any(unix, windows)))] +variant_identifier! { + OsStringKind (Unix; b"Unix"; 0, Windows; b"Windows"; 1) + "`Unix` or `Windows`", + OSSTR_VARIANTS +} + +#[cfg(all(feature = "std", any(unix, windows)))] +struct OsStringVisitor; + +#[cfg(all(feature = "std", any(unix, windows)))] +impl<'de> Visitor<'de> for OsStringVisitor { + type Value = OsString; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("os string") + } + + #[cfg(unix)] + fn visit_enum(self, data: A) -> Result + where + A: EnumAccess<'de>, + { + use std::os::unix::ffi::OsStringExt; + + 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", + )), + } + } + + #[cfg(windows)] + fn visit_enum(self, data: A) -> Result + where + A: EnumAccess<'de>, + { + use std::os::windows::ffi::OsStringExt; + + match tri!(data.variant()) { + (OsStringKind::Windows, v) => v + .newtype_variant::>() + .map(|vec| OsString::from_wide(&vec)), + (OsStringKind::Unix, _) => Err(Error::custom( + "cannot deserialize Unix OS string on Windows", + )), + } + } +} + +#[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 + D: Deserializer<'de>, + { + deserializer.deserialize_enum("OsString", OSSTR_VARIANTS, OsStringVisitor) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +forwarded_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + (T), Box, Box::new +} + +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 +} + +forwarded_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + (), Box, String::into_boxed_str +} + +forwarded_impl! { + #[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"))] +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] +impl<'de, 'a, T> Deserialize<'de> for Cow<'a, T> +where + T: ?Sized + ToOwned, + T::Owned: Deserialize<'de>, +{ + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + T::Owned::deserialize(deserializer).map(Cow::Owned) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// This impl requires the [`"rc"`] Cargo feature of Serde. The resulting +/// `Weak` has a reference count of 0 and cannot be upgraded. +/// +/// [`"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")))) +)] +impl<'de, T> Deserialize<'de> for RcWeak +where + T: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + tri!(Option::::deserialize(deserializer)); + Ok(RcWeak::new()) + } +} + +/// This impl requires the [`"rc"`] Cargo feature of Serde. The resulting +/// `Weak` has a reference count of 0 and cannot be upgraded. +/// +/// [`"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")))) +)] +impl<'de, T> Deserialize<'de> for ArcWeak +where + T: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + tri!(Option::::deserialize(deserializer)); + Ok(ArcWeak::new()) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! box_forwarded_impl { + ( + $(#[$attr:meta])* + $t:ident + ) => { + $(#[$attr])* + impl<'de, T> Deserialize<'de> for $t + where + T: ?Sized, + Box: Deserialize<'de>, + { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Box::deserialize(deserializer).map(Into::into) + } + } + }; +} + +box_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 + #[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))))] + Rc +} + +box_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 + #[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))))] + Arc +} + +//////////////////////////////////////////////////////////////////////////////// + +impl<'de, T> Deserialize<'de> for Cell +where + T: Deserialize<'de> + Copy, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + T::deserialize(deserializer).map(Cell::new) + } +} + +forwarded_impl! { + (T), RefCell, RefCell::new +} + +forwarded_impl! { + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + (T), Mutex, Mutex::new +} + +forwarded_impl! { + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + (T), RwLock, RwLock::new +} + +//////////////////////////////////////////////////////////////////////////////// + +// This is a cleaned-up version of the impl generated by: +// +// #[derive(Deserialize)] +// #[serde(deny_unknown_fields)] +// struct Duration { +// secs: u64, +// nanos: u32, +// } +impl<'de> Deserialize<'de> for Duration { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + // If this were outside of the serde crate, it would just use: + // + // #[derive(Deserialize)] + // #[serde(field_identifier, rename_all = "lowercase")] + enum Field { + Secs, + Nanos, + } + + 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("`secs` or `nanos`") + } + + fn visit_str(self, value: &str) -> Result + where + E: Error, + { + match value { + "secs" => Ok(Field::Secs), + "nanos" => Ok(Field::Nanos), + _ => Err(Error::unknown_field(value, FIELDS)), + } + } + + fn visit_bytes(self, value: &[u8]) -> Result + where + E: Error, + { + match value { + b"secs" => Ok(Field::Secs), + b"nanos" => Ok(Field::Nanos), + _ => { + let value = private::string::from_utf8_lossy(value); + Err(Error::unknown_field(&*value, FIELDS)) + } + } + } + } + + deserializer.deserialize_identifier(FieldVisitor) + } + } + + 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 { + type Value = Duration; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("struct Duration") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let secs: u64 = match tri!(seq.next_element()) { + Some(value) => value, + None => { + return Err(Error::invalid_length(0, &self)); + } + }; + 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)) + } + + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + let mut secs: Option = None; + let mut nanos: Option = None; + while let Some(key) = tri!(map.next_key()) { + match key { + Field::Secs => { + if secs.is_some() { + return Err(::duplicate_field("secs")); + } + secs = Some(tri!(map.next_value())); + } + Field::Nanos => { + if nanos.is_some() { + return Err(::duplicate_field("nanos")); + } + nanos = Some(tri!(map.next_value())); + } + } + } + let secs = match secs { + Some(secs) => secs, + None => return Err(::missing_field("secs")), + }; + let nanos = match nanos { + Some(nanos) => nanos, + None => return Err(::missing_field("nanos")), + }; + tri!(check_overflow(secs, nanos)); + Ok(Duration::new(secs, nanos)) + } + } + + const FIELDS: &[&str] = &["secs", "nanos"]; + deserializer.deserialize_struct("Duration", FIELDS, DurationVisitor) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl<'de> Deserialize<'de> for SystemTime { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + // Reuse duration + enum Field { + Secs, + Nanos, + } + + 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("`secs_since_epoch` or `nanos_since_epoch`") + } + + fn visit_str(self, value: &str) -> Result + where + E: Error, + { + match value { + "secs_since_epoch" => Ok(Field::Secs), + "nanos_since_epoch" => Ok(Field::Nanos), + _ => Err(Error::unknown_field(value, FIELDS)), + } + } + + fn visit_bytes(self, value: &[u8]) -> Result + where + E: Error, + { + match value { + b"secs_since_epoch" => Ok(Field::Secs), + b"nanos_since_epoch" => Ok(Field::Nanos), + _ => { + let value = String::from_utf8_lossy(value); + Err(Error::unknown_field(&value, FIELDS)) + } + } + } + } + + deserializer.deserialize_identifier(FieldVisitor) + } + } + + 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 { + type Value = Duration; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("struct SystemTime") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let secs: u64 = match tri!(seq.next_element()) { + Some(value) => value, + None => { + return Err(Error::invalid_length(0, &self)); + } + }; + 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)) + } + + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + let mut secs: Option = None; + let mut nanos: Option = None; + while let Some(key) = tri!(map.next_key()) { + match key { + Field::Secs => { + if secs.is_some() { + return Err(::duplicate_field( + "secs_since_epoch", + )); + } + secs = Some(tri!(map.next_value())); + } + Field::Nanos => { + if nanos.is_some() { + return Err(::duplicate_field( + "nanos_since_epoch", + )); + } + nanos = Some(tri!(map.next_value())); + } + } + } + let secs = match secs { + Some(secs) => secs, + None => return Err(::missing_field("secs_since_epoch")), + }; + let nanos = match nanos { + Some(nanos) => nanos, + None => return Err(::missing_field("nanos_since_epoch")), + }; + tri!(check_overflow(secs, nanos)); + Ok(Duration::new(secs, nanos)) + } + } + + 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")) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +// Similar to: +// +// #[derive(Deserialize)] +// #[serde(deny_unknown_fields)] +// struct Range { +// start: Idx, +// end: Idx, +// } +impl<'de, Idx> Deserialize<'de> for Range +where + Idx: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let (start, end) = tri!(deserializer.deserialize_struct( + "Range", + range::FIELDS, + range::RangeVisitor { + expecting: "struct Range", + phantom: PhantomData, + }, + )); + Ok(start..end) + } +} + +impl<'de, Idx> Deserialize<'de> for RangeInclusive +where + Idx: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + 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 crate::lib::*; + + use crate::de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor}; + use crate::private; + + pub const FIELDS: &[&str] = &["start", "end"]; + + // If this were outside of the serde crate, it would just use: + // + // #[derive(Deserialize)] + // #[serde(field_identifier, rename_all = "lowercase")] + enum Field { + Start, + 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("`start` or `end`") + } + + fn visit_str(self, value: &str) -> Result + where + E: Error, + { + match value { + "start" => Ok(Field::Start), + "end" => Ok(Field::End), + _ => Err(Error::unknown_field(value, FIELDS)), + } + } + + fn visit_bytes(self, value: &[u8]) -> Result + where + E: Error, + { + match value { + b"start" => Ok(Field::Start), + 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 RangeVisitor { + pub expecting: &'static str, + pub phantom: PhantomData, + } + + impl<'de, Idx> Visitor<'de> for RangeVisitor + where + Idx: Deserialize<'de>, + { + type Value = (Idx, 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)); + } + }; + let end: Idx = match tri!(seq.next_element()) { + Some(value) => value, + None => { + return Err(Error::invalid_length(1, &self)); + } + }; + Ok((start, end)) + } + + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + let mut start: Option = None; + let mut end: 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())); + } + Field::End => { + if end.is_some() { + return Err(::duplicate_field("end")); + } + end = Some(tri!(map.next_value())); + } + } + } + let start = match start { + Some(start) => start, + None => return Err(::missing_field("start")), + }; + let end = match end { + Some(end) => end, + None => return Err(::missing_field("end")), + }; + Ok((start, end)) + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +// 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>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + enum Field { + Unbounded, + Included, + Excluded, + } + + impl<'de> Deserialize<'de> for Field { + #[inline] + 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("`Unbounded`, `Included` or `Excluded`") + } + + fn visit_u64(self, value: u64) -> Result + where + E: Error, + { + match value { + 0 => Ok(Field::Unbounded), + 1 => Ok(Field::Included), + 2 => Ok(Field::Excluded), + _ => Err(Error::invalid_value(Unexpected::Unsigned(value), &self)), + } + } + + fn visit_str(self, value: &str) -> Result + where + E: Error, + { + match value { + "Unbounded" => Ok(Field::Unbounded), + "Included" => Ok(Field::Included), + "Excluded" => Ok(Field::Excluded), + _ => Err(Error::unknown_variant(value, VARIANTS)), + } + } + + fn visit_bytes(self, value: &[u8]) -> Result + where + E: Error, + { + match value { + b"Unbounded" => Ok(Field::Unbounded), + b"Included" => Ok(Field::Included), + b"Excluded" => Ok(Field::Excluded), + _ => match str::from_utf8(value) { + Ok(value) => Err(Error::unknown_variant(value, VARIANTS)), + Err(_) => { + Err(Error::invalid_value(Unexpected::Bytes(value), &self)) + } + }, + } + } + } + + deserializer.deserialize_identifier(FieldVisitor) + } + } + + struct BoundVisitor(PhantomData>); + + impl<'de, T> Visitor<'de> for BoundVisitor + where + T: Deserialize<'de>, + { + type Value = Bound; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("enum Bound") + } + + fn visit_enum(self, data: A) -> Result + where + A: EnumAccess<'de>, + { + 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), + } + } + } + + const VARIANTS: &[&str] = &["Unbounded", "Included", "Excluded"]; + + deserializer.deserialize_enum("Bound", VARIANTS, BoundVisitor(PhantomData)) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "result")] +#[cfg_attr(docsrs, doc(cfg(feature = "result")))] +impl<'de, T, E> Deserialize<'de> for Result +where + T: Deserialize<'de>, + E: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + // If this were outside of the serde crate, it would just use: + // + // #[derive(Deserialize)] + // #[serde(variant_identifier)] + enum Field { + Ok, + Err, + } + + impl<'de> Deserialize<'de> for Field { + #[inline] + 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("`Ok` or `Err`") + } + + fn visit_u64(self, value: u64) -> Result + where + E: Error, + { + match value { + 0 => Ok(Field::Ok), + 1 => Ok(Field::Err), + _ => Err(Error::invalid_value(Unexpected::Unsigned(value), &self)), + } + } + + fn visit_str(self, value: &str) -> Result + where + E: Error, + { + match value { + "Ok" => Ok(Field::Ok), + "Err" => Ok(Field::Err), + _ => Err(Error::unknown_variant(value, VARIANTS)), + } + } + + fn visit_bytes(self, value: &[u8]) -> Result + where + E: Error, + { + match value { + b"Ok" => Ok(Field::Ok), + b"Err" => Ok(Field::Err), + _ => match str::from_utf8(value) { + Ok(value) => Err(Error::unknown_variant(value, VARIANTS)), + Err(_) => { + Err(Error::invalid_value(Unexpected::Bytes(value), &self)) + } + }, + } + } + } + + deserializer.deserialize_identifier(FieldVisitor) + } + } + + struct ResultVisitor(PhantomData>); + + impl<'de, T, E> Visitor<'de> for ResultVisitor + where + T: Deserialize<'de>, + E: Deserialize<'de>, + { + type Value = Result; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("enum Result") + } + + fn visit_enum(self, data: A) -> Result + where + A: EnumAccess<'de>, + { + match tri!(data.variant()) { + (Field::Ok, v) => v.newtype_variant().map(Ok), + (Field::Err, v) => v.newtype_variant().map(Err), + } + } + } + + const VARIANTS: &[&str] = &["Ok", "Err"]; + + deserializer.deserialize_enum("Result", VARIANTS, ResultVisitor(PhantomData)) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl<'de, T> Deserialize<'de> for Wrapping +where + T: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Deserialize::deserialize(deserializer).map(Wrapping) + } +} + +#[cfg(all(feature = "std", not(no_std_atomic)))] +macro_rules! atomic_impl { + ($($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 + D: Deserializer<'de>, + { + Deserialize::deserialize(deserializer).map(Self::new) + } + } + )* + }; +} + +#[cfg(all(feature = "std", not(no_std_atomic)))] +atomic_impl! { + 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(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/third_party/crates/serde-1.0.229/src/core/de/mod.rs b/third_party/crates/serde-1.0.229/src/core/de/mod.rs new file mode 100644 index 0000000..2518ae6 --- /dev/null +++ b/third_party/crates/serde-1.0.229/src/core/de/mod.rs @@ -0,0 +1,2392 @@ +//! Generic data structure deserialization framework. +//! +//! The two most important traits in this module are [`Deserialize`] and +//! [`Deserializer`]. +//! +//! - **A type that implements `Deserialize` is a data structure** that can be +//! deserialized from any data format supported by Serde, and conversely +//! - **A type that implements `Deserializer` is a data format** that can +//! deserialize any data structure supported by Serde. +//! +//! # The Deserialize trait +//! +//! Serde provides [`Deserialize`] implementations for many Rust primitive and +//! standard library types. The complete list is below. 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 +//! in your program. See the [derive section of the manual] for how to use this. +//! +//! In rare cases it may be necessary to implement [`Deserialize`] manually for +//! some type in your program. See the [Implementing `Deserialize`] section of +//! the manual for more about this. +//! +//! Third-party crates may provide [`Deserialize`] implementations for types +//! that they expose. For example the [`linked-hash-map`] crate provides a +//! [`LinkedHashMap`] type that is deserializable by Serde because the +//! crate provides an implementation of [`Deserialize`] for it. +//! +//! # The Deserializer trait +//! +//! [`Deserializer`] implementations are provided by third-party crates, for +//! example [`serde_json`], [`serde_yaml`] and [`postcard`]. +//! +//! A partial list of well-maintained formats is given on the [Serde +//! website][data formats]. +//! +//! # Implementations of Deserialize provided by Serde +//! +//! This is a slightly different set of types than what is supported for +//! serialization. Some types can be serialized by Serde but not deserialized. +//! One example is `OsStr`. +//! +//! - **Primitive types**: +//! - bool +//! - i8, i16, i32, i64, i128, isize +//! - u8, u16, u32, u64, u128, usize +//! - f32, f64 +//! - char +//! - **Compound types**: +//! - \[T; 0\] through \[T; 32\] +//! - tuples up to size 16 +//! - **Common standard library types**: +//! - String +//! - Option\ +//! - Result\ +//! - PhantomData\ +//! - **Wrapper types**: +//! - Box\ +//! - Box\<\[T\]\> +//! - Box\ +//! - Cow\<'a, T\> +//! - Cell\ +//! - RefCell\ +//! - Mutex\ +//! - RwLock\ +//! - Rc\ *(if* features = \["rc"\] *is enabled)* +//! - Arc\ *(if* features = \["rc"\] *is enabled)* +//! - **Collection types**: +//! - BTreeMap\ +//! - BTreeSet\ +//! - BinaryHeap\ +//! - HashMap\ +//! - HashSet\ +//! - LinkedList\ +//! - VecDeque\ +//! - Vec\ +//! - **Zero-copy types**: +//! - &str +//! - &\[u8\] +//! - **FFI types**: +//! - CString +//! - Box\ +//! - OsString +//! - **Miscellaneous standard library types**: +//! - Duration +//! - SystemTime +//! - Path +//! - PathBuf +//! - Range\ +//! - RangeInclusive\ +//! - Bound\ +//! - num::NonZero* +//! - `!` *(unstable)* +//! - **Net types**: +//! - IpAddr +//! - Ipv4Addr +//! - Ipv6Addr +//! - SocketAddr +//! - SocketAddrV4 +//! - SocketAddrV6 +//! +//! [Implementing `Deserialize`]: https://serde.rs/impl-deserialize.html +//! [`Deserialize`]: crate::Deserialize +//! [`Deserializer`]: crate::Deserializer +//! [`LinkedHashMap`]: https://docs.rs/linked-hash-map/*/linked_hash_map/struct.LinkedHashMap.html +//! [`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 +//! [`serde_yaml`]: https://github.com/dtolnay/serde-yaml +//! [derive section of the manual]: https://serde.rs/derive.html +//! [data formats]: https://serde.rs/#data-formats + +use crate::lib::*; + +//////////////////////////////////////////////////////////////////////////////// + +pub mod value; + +mod ignored_any; +mod impls; + +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; + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! declare_error_trait { + (Error: Sized $(+ $($supertrait:ident)::+)*) => { + /// The `Error` trait allows `Deserialize` implementations to create descriptive + /// error messages belonging to the `Deserializer` against which they are + /// currently running. + /// + /// Every `Deserializer` declares an `Error` type that encompasses both + /// general-purpose deserialization errors as well as errors specific to the + /// particular deserialization format. For example the `Error` type of + /// `serde_json` can represent errors like an invalid JSON escape sequence or an + /// unterminated string literal, in addition to the error cases that are part of + /// this trait. + /// + /// Most deserializers should only need to provide the `Error::custom` method + /// and inherit the default behavior for the other methods. + /// + /// # Example implementation + /// + /// The [example data format] presented on the website shows an error + /// 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. + /// + /// ```edition2021 + /// # use std::str::FromStr; + /// # + /// # struct IpAddr; + /// # + /// # impl FromStr for IpAddr { + /// # type Err = String; + /// # + /// # fn from_str(_: &str) -> Result { + /// # unimplemented!() + /// # } + /// # } + /// # + /// use serde::de::{self, Deserialize, Deserializer}; + /// + /// impl<'de> Deserialize<'de> for IpAddr { + /// fn deserialize(deserializer: D) -> Result + /// where + /// D: Deserializer<'de>, + /// { + /// let s = String::deserialize(deserializer)?; + /// s.parse().map_err(de::Error::custom) + /// } + /// } + /// ``` + fn custom(msg: T) -> Self + where + T: Display; + + /// Raised when a `Deserialize` receives a type different from what it was + /// expecting. + /// + /// The `unexp` argument provides information about what type was received. + /// This is the type that was present in the input file or other source data + /// of the Deserializer. + /// + /// The `exp` argument provides information about what type was being + /// expected. This is the type that is written in the program. + /// + /// For example if we try to deserialize a String out of a JSON file + /// containing an integer, the unexpected type is the integer and the + /// expected type is the string. + #[cold] + fn invalid_type(unexp: Unexpected, exp: &dyn Expected) -> Self { + Error::custom(format_args!("invalid type: {}, expected {}", unexp, exp)) + } + + /// Raised when a `Deserialize` receives a value of the right type but that + /// is wrong for some other reason. + /// + /// The `unexp` argument provides information about what value was received. + /// This is the value that was present in the input file or other source + /// data of the Deserializer. + /// + /// The `exp` argument provides information about what value was being + /// expected. This is the type that is written in the program. + /// + /// For example if we try to deserialize a String out of some binary data + /// 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: &dyn Expected) -> Self { + Error::custom(format_args!("invalid value: {}, expected {}", unexp, exp)) + } + + /// Raised when deserializing a sequence or map and the input data contains + /// too many or too few elements. + /// + /// The `len` argument is the number of elements encountered. The sequence + /// or map may have expected more arguments or fewer arguments. + /// + /// The `exp` argument provides information about what data was being + /// expected. For example `exp` might say that a tuple of size 6 was + /// expected. + #[cold] + fn invalid_length(len: usize, exp: &dyn Expected) -> Self { + Error::custom(format_args!("invalid length {}, expected {}", len, exp)) + } + + /// Raised when a `Deserialize` enum type received a variant with an + /// unrecognized name. + #[cold] + fn unknown_variant(variant: &str, expected: &'static [&'static str]) -> Self { + if expected.is_empty() { + Error::custom(format_args!( + "unknown variant `{}`, there are no variants", + variant + )) + } else { + Error::custom(format_args!( + "unknown variant `{}`, expected {}", + variant, + OneOf { names: expected } + )) + } + } + + /// Raised when a `Deserialize` struct type received a field with an + /// unrecognized name. + #[cold] + fn unknown_field(field: &str, expected: &'static [&'static str]) -> Self { + if expected.is_empty() { + Error::custom(format_args!( + "unknown field `{}`, there are no fields", + field + )) + } else { + Error::custom(format_args!( + "unknown field `{}`, expected {}", + field, + OneOf { names: expected } + )) + } + } + + /// Raised when a `Deserialize` struct type expected to receive a required + /// field with a particular name but that field was not present in the + /// input. + #[cold] + fn missing_field(field: &'static str) -> Self { + Error::custom(format_args!("missing field `{}`", field)) + } + + /// Raised when a `Deserialize` struct type received more than one of the + /// same field. + #[cold] + fn duplicate_field(field: &'static str) -> Self { + Error::custom(format_args!("duplicate field `{}`", field)) + } + } + } +} + +#[cfg(feature = "std")] +declare_error_trait!(Error: Sized + StdError); + +#[cfg(not(feature = "std"))] +declare_error_trait!(Error: Sized + Debug + Display); + +/// `Unexpected` represents an unexpected invocation of any one of the `Visitor` +/// trait methods. +/// +/// This is used as an argument to the `invalid_type`, `invalid_value`, and +/// `invalid_length` methods of the `Error` trait to build error messages. +/// +/// ```edition2021 +/// # use std::fmt; +/// # +/// # use serde::de::{self, Unexpected, Visitor}; +/// # +/// # struct Example; +/// # +/// # impl<'de> Visitor<'de> for Example { +/// # type Value = (); +/// # +/// # fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { +/// # write!(formatter, "definitely not a boolean") +/// # } +/// # +/// fn visit_bool(self, v: bool) -> Result +/// where +/// E: de::Error, +/// { +/// Err(de::Error::invalid_type(Unexpected::Bool(v), &self)) +/// } +/// # } +/// ``` +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum Unexpected<'a> { + /// The input contained a boolean value that was not expected. + Bool(bool), + + /// The input contained an unsigned integer `u8`, `u16`, `u32` or `u64` that + /// was not expected. + Unsigned(u64), + + /// The input contained a signed integer `i8`, `i16`, `i32` or `i64` that + /// was not expected. + Signed(i64), + + /// The input contained a floating point `f32` or `f64` that was not + /// expected. + Float(f64), + + /// The input contained a `char` that was not expected. + Char(char), + + /// The input contained a `&str` or `String` that was not expected. + Str(&'a str), + + /// The input contained a `&[u8]` or `Vec` that was not expected. + Bytes(&'a [u8]), + + /// The input contained a unit `()` that was not expected. + Unit, + + /// The input contained an `Option` that was not expected. + Option, + + /// The input contained a newtype struct that was not expected. + NewtypeStruct, + + /// The input contained a sequence that was not expected. + Seq, + + /// The input contained a map that was not expected. + Map, + + /// The input contained an enum that was not expected. + Enum, + + /// The input contained a unit variant that was not expected. + UnitVariant, + + /// The input contained a newtype variant that was not expected. + NewtypeVariant, + + /// The input contained a tuple variant that was not expected. + TupleVariant, + + /// The input contained a struct variant that was not expected. + StructVariant, + + /// A message stating what uncategorized thing the input contained that was + /// not expected. + /// + /// The message should be a noun or noun phrase, not capitalized and without + /// a period. An example message is "unoriginal superhero". + Other(&'a str), +} + +impl<'a> fmt::Display for Unexpected<'a> { + 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 `{}`", WithDecimalPoint(f)), + Char(c) => write!(formatter, "character `{}`", c), + Str(s) => write!(formatter, "string {:?}", s), + 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), + } + } +} + +/// `Expected` represents an explanation of what data a `Visitor` was expecting +/// to receive. +/// +/// This is used as an argument to the `invalid_type`, `invalid_value`, and +/// `invalid_length` methods of the `Error` trait to build error messages. The +/// message should be a noun or noun phrase that completes the sentence "This +/// Visitor expects to receive ...", for example the message could be "an +/// integer between 0 and 64". The message should not be capitalized and should +/// not end with a period. +/// +/// Within the context of a `Visitor` implementation, the `Visitor` itself +/// (`&self`) is an implementation of this trait. +/// +/// ```edition2021 +/// # use serde::de::{self, Unexpected, Visitor}; +/// # use std::fmt; +/// # +/// # struct Example; +/// # +/// # impl<'de> Visitor<'de> for Example { +/// # type Value = (); +/// # +/// # fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { +/// # write!(formatter, "definitely not a boolean") +/// # } +/// # +/// fn visit_bool(self, v: bool) -> Result +/// where +/// E: de::Error, +/// { +/// Err(de::Error::invalid_type(Unexpected::Bool(v), &self)) +/// } +/// # } +/// ``` +/// +/// Outside of a `Visitor`, `&"..."` can be used. +/// +/// ```edition2021 +/// # use serde::de::{self, Unexpected}; +/// # +/// # fn example() -> Result<(), E> +/// # where +/// # E: de::Error, +/// # { +/// # let v = true; +/// 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. + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result; +} + +impl<'de, T> Expected for T +where + T: Visitor<'de>, +{ + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + self.expecting(formatter) + } +} + +impl Expected for &str { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(self) + } +} + +impl Display for dyn Expected + '_ { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Expected::fmt(self, formatter) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A **data structure** that can be deserialized from any data format supported +/// by Serde. +/// +/// Serde provides `Deserialize` implementations for many Rust primitive and +/// 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 +/// in your program. See the [derive section of the manual][derive] for how to +/// use this. +/// +/// In rare cases it may be necessary to implement `Deserialize` manually for +/// some type in your program. See the [Implementing +/// `Deserialize`][impl-deserialize] section of the manual for more about this. +/// +/// Third-party crates may provide `Deserialize` implementations for types that +/// they expose. For example the `linked-hash-map` crate provides a +/// `LinkedHashMap` type that is deserializable by Serde because the crate +/// provides an implementation of `Deserialize` for it. +/// +/// [derive]: https://serde.rs/derive.html +/// [impl-deserialize]: https://serde.rs/impl-deserialize.html +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the lifetime of data that may be +/// borrowed by `Self` when deserialized. See the page [Understanding +/// 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. + /// + /// See the [Implementing `Deserialize`][impl-deserialize] section of the + /// manual for more information about how to implement this method. + /// + /// [impl-deserialize]: https://serde.rs/impl-deserialize.html + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>; + + /// Deserializes a value into `self` from the given Deserializer. + /// + /// The purpose of this method is to allow the deserializer to reuse + /// resources and avoid copies. As such, if this method returns an error, + /// `self` will be in an indeterminate state where some parts of the struct + /// have been overwritten. Although whatever state that is will be + /// memory-safe. + /// + /// This is generally useful when repeatedly deserializing values that + /// are processed one at a time, where the value of `self` doesn't matter + /// when the next deserialization occurs. + /// + /// If you manually implement this, your recursive deserializations should + /// use `deserialize_in_place`. + /// + /// This method is stable and an official public API, but hidden from the + /// documentation because it is almost never what newbies are looking for. + /// Showing it in rustdoc would cause it to be featured more prominently + /// than it deserves. + #[doc(hidden)] + fn deserialize_in_place(deserializer: D, place: &mut Self) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + // Default implementation just delegates to `deserialize` impl. + *place = tri!(Deserialize::deserialize(deserializer)); + Ok(()) + } +} + +/// A data structure that can be deserialized without borrowing any data from +/// the deserializer. +/// +/// This is primarily useful for trait bounds on functions. For example a +/// `from_str` function may be able to deserialize a data structure that borrows +/// from the input string, but a `from_reader` function may only deserialize +/// owned data. +/// +/// ```edition2021 +/// # use serde::de::{Deserialize, DeserializeOwned}; +/// # use std::io::{Read, Result}; +/// # +/// # trait Ignore { +/// fn from_str<'a, T>(s: &'a str) -> Result +/// where +/// T: Deserialize<'a>; +/// +/// fn from_reader(rdr: R) -> Result +/// where +/// R: Read, +/// T: DeserializeOwned; +/// # } +/// ``` +/// +/// # Lifetime +/// +/// The relationship between `Deserialize` and `DeserializeOwned` in trait +/// bounds is explained in more detail on the page [Understanding deserializer +/// 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> {} + +/// `DeserializeSeed` is the stateful form of the `Deserialize` trait. If you +/// ever find yourself looking for a way to pass data into a `Deserialize` impl, +/// this trait is the way to do it. +/// +/// As one example of stateful deserialization consider deserializing a JSON +/// array into an existing buffer. Using the `Deserialize` trait we could +/// deserialize a JSON array into a `Vec` but it would be a freshly allocated +/// `Vec`; there is no way for `Deserialize` to reuse a previously allocated +/// buffer. Using `DeserializeSeed` instead makes this possible as in the +/// example code below. +/// +/// The canonical API for stateless deserialization looks like this: +/// +/// ```edition2021 +/// # use serde::Deserialize; +/// # +/// # enum Error {} +/// # +/// fn func<'de, T: Deserialize<'de>>() -> Result +/// # { +/// # unimplemented!() +/// # } +/// ``` +/// +/// Adjusting an API like this to support stateful deserialization is a matter +/// of accepting a seed as input: +/// +/// ```edition2021 +/// # use serde::de::DeserializeSeed; +/// # +/// # enum Error {} +/// # +/// fn func_seed<'de, T: DeserializeSeed<'de>>(seed: T) -> Result +/// # { +/// # let _ = seed; +/// # unimplemented!() +/// # } +/// ``` +/// +/// In practice the majority of deserialization is stateless. An API expecting a +/// seed can be appeased by passing `std::marker::PhantomData` as a seed in the +/// case of stateless deserialization. +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the lifetime of data that may be +/// borrowed by `Self::Value` when deserialized. See the page [Understanding +/// deserializer lifetimes] for a more detailed explanation of these lifetimes. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +/// +/// # Example +/// +/// Suppose we have JSON that looks like `[[1, 2], [3, 4, 5], [6]]` and we need +/// to deserialize it into a flat representation like `vec![1, 2, 3, 4, 5, 6]`. +/// Allocating a brand new `Vec` for each subarray would be slow. Instead we +/// would like to allocate a single `Vec` and then deserialize each subarray +/// into it. This requires stateful deserialization using the `DeserializeSeed` +/// trait. +/// +/// ```edition2021 +/// use serde::de::{Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor}; +/// use std::fmt; +/// use std::marker::PhantomData; +/// +/// // 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 +/// // `ExtendVec` will be traversing the inner arrays of the JSON input and +/// // appending each integer into the existing Vec. +/// struct ExtendVec<'a, T: 'a>(&'a mut Vec); +/// +/// impl<'de, 'a, T> DeserializeSeed<'de> for ExtendVec<'a, T> +/// where +/// T: Deserialize<'de>, +/// { +/// // The return type of the `deserialize` method. This implementation +/// // appends onto an existing vector but does not create any new data +/// // structure, so the return type is (). +/// type Value = (); +/// +/// fn deserialize(self, deserializer: D) -> Result +/// where +/// D: Deserializer<'de>, +/// { +/// // Visitor implementation that will walk an inner array of the JSON +/// // input. +/// struct ExtendVecVisitor<'a, T: 'a>(&'a mut Vec); +/// +/// impl<'de, 'a, T> Visitor<'de> for ExtendVecVisitor<'a, T> +/// where +/// T: Deserialize<'de>, +/// { +/// type Value = (); +/// +/// fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { +/// write!(formatter, "an array of integers") +/// } +/// +/// fn visit_seq(self, mut seq: A) -> Result<(), A::Error> +/// 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()? { +/// self.0.push(elem); +/// } +/// Ok(()) +/// } +/// } +/// +/// deserializer.deserialize_seq(ExtendVecVisitor(self.0)) +/// } +/// } +/// +/// // Visitor implementation that will walk the outer array of the JSON input. +/// struct FlattenedVecVisitor(PhantomData); +/// +/// impl<'de, T> Visitor<'de> for FlattenedVecVisitor +/// where +/// T: Deserialize<'de>, +/// { +/// // This Visitor constructs a single Vec to hold the flattened +/// // contents of the inner arrays. +/// type Value = Vec; +/// +/// fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { +/// write!(formatter, "an array of arrays") +/// } +/// +/// fn visit_seq(self, mut seq: A) -> Result, A::Error> +/// where +/// A: SeqAccess<'de>, +/// { +/// // Create a single Vec to hold the flattened contents. +/// let mut vec = Vec::new(); +/// +/// // Each iteration through this loop is one inner array. +/// while let Some(()) = seq.next_element_seed(ExtendVec(&mut vec))? { +/// // Nothing to do; inner array has been appended into `vec`. +/// } +/// +/// // Return the finished vec. +/// Ok(vec) +/// } +/// } +/// +/// # fn example<'de, D>(deserializer: D) -> Result<(), D::Error> +/// # where +/// # D: Deserializer<'de>, +/// # { +/// let visitor = FlattenedVecVisitor(PhantomData); +/// let flattened: Vec = deserializer.deserialize_seq(visitor)?; +/// # 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; + + /// Equivalent to the more common `Deserialize::deserialize` method, except + /// with some initial piece of data (the seed) passed in. + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>; +} + +impl<'de, T> DeserializeSeed<'de> for PhantomData +where + T: Deserialize<'de>, +{ + type Value = T; + + #[inline] + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + T::deserialize(deserializer) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A **data format** that can deserialize any data structure supported by +/// Serde. +/// +/// The role of this trait is to define the deserialization half of the [Serde +/// data model], which is a way to categorize every Rust data type into one of +/// 29 possible types. Each method of the `Deserializer` trait corresponds to one +/// of the types of the data model. +/// +/// Implementations of `Deserialize` map themselves into this data model by +/// passing to the `Deserializer` a `Visitor` implementation that can receive +/// these various types. +/// +/// The types that make up the Serde data model are: +/// +/// - **14 primitive types** +/// - bool +/// - i8, i16, i32, i64, i128 +/// - u8, u16, u32, u64, u128 +/// - f32, f64 +/// - char +/// - **string** +/// - UTF-8 bytes with a length and no null terminator. +/// - When serializing, all strings are handled equally. When deserializing, +/// there are three flavors of strings: transient, owned, and borrowed. +/// - **byte array** - \[u8\] +/// - Similar to strings, during deserialization byte arrays can be +/// transient, owned, or borrowed. +/// - **option** +/// - Either none or some value. +/// - **unit** +/// - The type of `()` in Rust. It represents an anonymous value containing +/// no data. +/// - **unit_struct** +/// - For example `struct Unit` or `PhantomData`. It represents a named +/// value containing no data. +/// - **unit_variant** +/// - For example the `E::A` and `E::B` in `enum E { A, B }`. +/// - **newtype_struct** +/// - For example `struct Millimeters(u8)`. +/// - **newtype_variant** +/// - For example the `E::N` in `enum E { N(u8) }`. +/// - **seq** +/// - A variably sized heterogeneous sequence of values, for example `Vec` +/// or `HashSet`. When serializing, the length may or may not be known +/// before iterating through all the data. When deserializing, the length +/// is determined by looking at the serialized data. +/// - **tuple** +/// - A statically sized heterogeneous sequence of values for which the +/// length will be known at deserialization time without looking at the +/// serialized data, for example `(u8,)` or `(String, u64, Vec)` or +/// `[u64; 10]`. +/// - **tuple_struct** +/// - A named tuple, for example `struct Rgb(u8, u8, u8)`. +/// - **tuple_variant** +/// - For example the `E::T` in `enum E { T(u8, u8) }`. +/// - **map** +/// - A heterogeneous key-value pairing, for example `BTreeMap`. +/// - **struct** +/// - A heterogeneous key-value pairing in which the keys are strings and +/// will be known at deserialization time without looking at the serialized +/// data, for example `struct S { r: u8, g: u8, b: u8 }`. +/// - **struct_variant** +/// - For example the `E::S` in `enum E { S { r: u8, g: u8, b: u8 } }`. +/// +/// The `Deserializer` trait supports two entry point styles which enables +/// different kinds of deserialization. +/// +/// 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 +/// document. Without knowing what is in a JSON document, we can deserialize +/// it to `serde_json::Value` by going through +/// `Deserializer::deserialize_any`. +/// +/// 2. The various `deserialize_*` methods. Non-self-describing formats like +/// 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 +/// `Deserializer::deserialize_any`. +/// +/// When implementing `Deserialize`, you should avoid relying on +/// `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 Postcard and many +/// others. +/// +/// [Serde data model]: https://serde.rs/data-model.html +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the lifetime of data that may be +/// borrowed from the input when deserializing. See the page [Understanding +/// deserializer lifetimes] for a more detailed explanation of these lifetimes. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +/// +/// # Example implementation +/// +/// The [example data format] presented on the website contains example code for +/// 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. + type Error: Error; + + /// Require the `Deserializer` to figure out how to drive the visitor based + /// on what data type is in the input. + /// + /// When implementing `Deserialize`, you should avoid relying on + /// `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 Postcard and + /// many others. + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a `bool` value. + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting an `i8` value. + fn deserialize_i8(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting an `i16` value. + fn deserialize_i16(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting an `i32` value. + fn deserialize_i32(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting an `i64` value. + fn deserialize_i64(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// 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. + fn deserialize_u8(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a `u16` value. + fn deserialize_u16(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a `u32` value. + fn deserialize_u32(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a `u64` value. + fn deserialize_u64(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// 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. + fn deserialize_f32(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a `f64` value. + fn deserialize_f64(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a `char` value. + fn deserialize_char(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a string value and does + /// not benefit from taking ownership of buffered data owned by the + /// `Deserializer`. + /// + /// If the `Visitor` would benefit from taking ownership of `String` data, + /// indicate this to the `Deserializer` by using `deserialize_string` + /// instead. + fn deserialize_str(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a string value and would + /// benefit from taking ownership of buffered data owned by the + /// `Deserializer`. + /// + /// If the `Visitor` would not benefit from taking ownership of `String` + /// data, indicate that to the `Deserializer` by using `deserialize_str` + /// instead. + fn deserialize_string(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a byte array and does not + /// benefit from taking ownership of buffered data owned by the + /// `Deserializer`. + /// + /// If the `Visitor` would benefit from taking ownership of `Vec` data, + /// indicate this to the `Deserializer` by using `deserialize_byte_buf` + /// instead. + fn deserialize_bytes(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a byte array and would + /// benefit from taking ownership of buffered data owned by the + /// `Deserializer`. + /// + /// If the `Visitor` would not benefit from taking ownership of `Vec` + /// data, indicate that to the `Deserializer` by using `deserialize_bytes` + /// instead. + fn deserialize_byte_buf(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting an optional value. + /// + /// This allows deserializers that encode an optional value as a nullable + /// value to convert the null value into `None` and a regular value into + /// `Some(value)`. + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a unit value. + fn deserialize_unit(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a unit struct with a + /// particular name. + fn deserialize_unit_struct( + self, + name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a newtype struct with a + /// particular name. + fn deserialize_newtype_struct( + self, + name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a sequence of values. + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a sequence of values and + /// knows how many values there are without looking at the serialized data. + fn deserialize_tuple(self, len: usize, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a tuple struct with a + /// particular name and number of fields. + fn deserialize_tuple_struct( + self, + name: &'static str, + len: usize, + visitor: V, + ) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a map of key-value pairs. + fn deserialize_map(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a struct with a particular + /// name and fields. + fn deserialize_struct( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting an enum value with a + /// particular name and possible variants. + fn deserialize_enum( + self, + name: &'static str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting the name of a struct + /// field or the discriminant of an enum variant. + fn deserialize_identifier(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type needs to deserialize a value whose type + /// doesn't matter because it is ignored. + /// + /// Deserializers for non-self-describing formats may not support this mode. + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Determine whether `Deserialize` implementations should expect to + /// deserialize their human-readable form. + /// + /// 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 Postcard will prefer the + /// compact one. + /// + /// ```edition2021 + /// # use std::ops::Add; + /// # use std::str::FromStr; + /// # + /// # struct Timestamp; + /// # + /// # impl Timestamp { + /// # const EPOCH: Timestamp = Timestamp; + /// # } + /// # + /// # impl FromStr for Timestamp { + /// # type Err = String; + /// # fn from_str(_: &str) -> Result { + /// # unimplemented!() + /// # } + /// # } + /// # + /// # struct Duration; + /// # + /// # impl Duration { + /// # fn seconds(_: u64) -> Self { unimplemented!() } + /// # } + /// # + /// # impl Add for Timestamp { + /// # type Output = Timestamp; + /// # fn add(self, _: Duration) -> Self::Output { + /// # unimplemented!() + /// # } + /// # } + /// # + /// use serde::de::{self, Deserialize, Deserializer}; + /// + /// impl<'de> Deserialize<'de> for Timestamp { + /// fn deserialize(deserializer: D) -> Result + /// where + /// D: Deserializer<'de>, + /// { + /// if deserializer.is_human_readable() { + /// // Deserialize from a human-readable string like "2015-05-15T17:01:00Z". + /// let s = String::deserialize(deserializer)?; + /// Timestamp::from_str(&s).map_err(de::Error::custom) + /// } else { + /// // Deserialize from a compact binary representation, seconds since + /// // the Unix epoch. + /// let n = u64::deserialize(deserializer)?; + /// Ok(Timestamp::EPOCH + Duration::seconds(n)) + /// } + /// } + /// } + /// ``` + /// + /// The default implementation of this method returns `true`. Data formats + /// may override this to `false` to request a compact form for types that + /// support one. Note that modifying this method to change a format from + /// human-readable to compact or vice versa should be regarded as a breaking + /// change, as a value serialized in human-readable mode is not required to + /// deserialize from the same data in compact mode. + #[inline] + 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) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// This trait represents a visitor that walks through a deserializer. +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the requirement for lifetime of data +/// that may be borrowed by `Self::Value`. See the page [Understanding +/// deserializer lifetimes] for a more detailed explanation of these lifetimes. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +/// +/// # Example +/// +/// ```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. +/// struct LongString { +/// min: usize, +/// } +/// +/// impl<'de> Visitor<'de> for LongString { +/// type Value = String; +/// +/// fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { +/// write!(formatter, "a string containing at least {} bytes", self.min) +/// } +/// +/// fn visit_str(self, s: &str) -> Result +/// where +/// E: de::Error, +/// { +/// if s.len() >= self.min { +/// Ok(s.to_owned()) +/// } else { +/// Err(de::Error::invalid_value(Unexpected::Str(s), &self)) +/// } +/// } +/// } +/// ``` +#[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; + + /// Format a message stating what data this Visitor expects to receive. + /// + /// This is used in error messages. The message should complete the sentence + /// "This Visitor expects to receive ...", for example the message could be + /// "an integer between 0 and 64". The message should not be capitalized and + /// should not end with a period. + /// + /// ```edition2021 + /// # use std::fmt; + /// # + /// # struct S { + /// # max: usize, + /// # } + /// # + /// # impl<'de> serde::de::Visitor<'de> for S { + /// # type Value = (); + /// # + /// fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// write!(formatter, "an integer between 0 and {}", self.max) + /// } + /// # } + /// ``` + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result; + + /// The input contains a boolean. + /// + /// The default implementation fails with a type error. + fn visit_bool(self, v: bool) -> Result + where + E: Error, + { + Err(Error::invalid_type(Unexpected::Bool(v), &self)) + } + + /// The input contains an `i8`. + /// + /// The default implementation forwards to [`visit_i64`]. + /// + /// [`visit_i64`]: #method.visit_i64 + fn visit_i8(self, v: i8) -> Result + where + E: Error, + { + self.visit_i64(v as i64) + } + + /// The input contains an `i16`. + /// + /// The default implementation forwards to [`visit_i64`]. + /// + /// [`visit_i64`]: #method.visit_i64 + fn visit_i16(self, v: i16) -> Result + where + E: Error, + { + self.visit_i64(v as i64) + } + + /// The input contains an `i32`. + /// + /// The default implementation forwards to [`visit_i64`]. + /// + /// [`visit_i64`]: #method.visit_i64 + fn visit_i32(self, v: i32) -> Result + where + E: Error, + { + self.visit_i64(v as i64) + } + + /// The input contains an `i64`. + /// + /// The default implementation fails with a type error. + fn visit_i64(self, v: i64) -> Result + where + E: Error, + { + Err(Error::invalid_type(Unexpected::Signed(v), &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`. + /// + /// The default implementation forwards to [`visit_u64`]. + /// + /// [`visit_u64`]: #method.visit_u64 + fn visit_u8(self, v: u8) -> Result + where + E: Error, + { + self.visit_u64(v as u64) + } + + /// The input contains a `u16`. + /// + /// The default implementation forwards to [`visit_u64`]. + /// + /// [`visit_u64`]: #method.visit_u64 + fn visit_u16(self, v: u16) -> Result + where + E: Error, + { + self.visit_u64(v as u64) + } + + /// The input contains a `u32`. + /// + /// The default implementation forwards to [`visit_u64`]. + /// + /// [`visit_u64`]: #method.visit_u64 + fn visit_u32(self, v: u32) -> Result + where + E: Error, + { + self.visit_u64(v as u64) + } + + /// The input contains a `u64`. + /// + /// The default implementation fails with a type error. + fn visit_u64(self, v: u64) -> Result + where + E: Error, + { + Err(Error::invalid_type(Unexpected::Unsigned(v), &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`. + /// + /// The default implementation forwards to [`visit_f64`]. + /// + /// [`visit_f64`]: #method.visit_f64 + fn visit_f32(self, v: f32) -> Result + where + E: Error, + { + self.visit_f64(v as f64) + } + + /// The input contains an `f64`. + /// + /// The default implementation fails with a type error. + fn visit_f64(self, v: f64) -> Result + where + E: Error, + { + Err(Error::invalid_type(Unexpected::Float(v), &self)) + } + + /// The input contains a `char`. + /// + /// The default implementation forwards to [`visit_str`] as a one-character + /// string. + /// + /// [`visit_str`]: #method.visit_str + #[inline] + fn visit_char(self, v: char) -> Result + where + E: Error, + { + self.visit_str(v.encode_utf8(&mut [0u8; 4])) + } + + /// The input contains a string. The lifetime of the string is ephemeral and + /// it may be destroyed after this method returns. + /// + /// This method allows the `Deserializer` to avoid a copy by retaining + /// ownership of any buffered data. `Deserialize` implementations that do + /// not benefit from taking ownership of `String` data should indicate that + /// to the deserializer by using `Deserializer::deserialize_str` rather than + /// `Deserializer::deserialize_string`. + /// + /// It is never correct to implement `visit_string` without implementing + /// `visit_str`. Implement neither, both, or just `visit_str`. + fn visit_str(self, v: &str) -> Result + where + E: Error, + { + Err(Error::invalid_type(Unexpected::Str(v), &self)) + } + + /// The input contains a string that lives at least as long as the + /// `Deserializer`. + /// + /// This enables zero-copy deserialization of strings in some formats. For + /// example JSON input containing the JSON string `"borrowed"` can be + /// deserialized with zero copying into a `&'a str` as long as the input + /// data outlives `'a`. + /// + /// The default implementation forwards to `visit_str`. + #[inline] + fn visit_borrowed_str(self, v: &'de str) -> Result + where + E: Error, + { + self.visit_str(v) + } + + /// The input contains a string and ownership of the string is being given + /// to the `Visitor`. + /// + /// This method allows the `Visitor` to avoid a copy by taking ownership of + /// a string created by the `Deserializer`. `Deserialize` implementations + /// that benefit from taking ownership of `String` data should indicate that + /// to the deserializer by using `Deserializer::deserialize_string` rather + /// than `Deserializer::deserialize_str`, although not every deserializer + /// will honor such a request. + /// + /// It is never correct to implement `visit_string` without implementing + /// `visit_str`. Implement neither, both, or just `visit_str`. + /// + /// The default implementation forwards to `visit_str` and then drops the + /// `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, + { + self.visit_str(&v) + } + + /// The input contains a byte array. The lifetime of the byte array is + /// ephemeral and it may be destroyed after this method returns. + /// + /// This method allows the `Deserializer` to avoid a copy by retaining + /// ownership of any buffered data. `Deserialize` implementations that do + /// not benefit from taking ownership of `Vec` data should indicate that + /// to the deserializer by using `Deserializer::deserialize_bytes` rather + /// than `Deserializer::deserialize_byte_buf`. + /// + /// It is never correct to implement `visit_byte_buf` without implementing + /// `visit_bytes`. Implement neither, both, or just `visit_bytes`. + fn visit_bytes(self, v: &[u8]) -> Result + where + E: Error, + { + Err(Error::invalid_type(Unexpected::Bytes(v), &self)) + } + + /// The input contains a byte array that lives at least as long as the + /// `Deserializer`. + /// + /// This enables zero-copy deserialization of bytes in some formats. For + /// 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`. + #[inline] + fn visit_borrowed_bytes(self, v: &'de [u8]) -> Result + where + E: Error, + { + self.visit_bytes(v) + } + + /// The input contains a byte array and ownership of the byte array is being + /// given to the `Visitor`. + /// + /// This method allows the `Visitor` to avoid a copy by taking ownership of + /// a byte buffer created by the `Deserializer`. `Deserialize` + /// implementations that benefit from taking ownership of `Vec` data + /// should indicate that to the deserializer by using + /// `Deserializer::deserialize_byte_buf` rather than + /// `Deserializer::deserialize_bytes`, although not every deserializer will + /// honor such a request. + /// + /// It is never correct to implement `visit_byte_buf` without implementing + /// `visit_bytes`. Implement neither, both, or just `visit_bytes`. + /// + /// 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, + { + self.visit_bytes(&v) + } + + /// The input contains an optional that is absent. + /// + /// The default implementation fails with a type error. + fn visit_none(self) -> Result + where + E: Error, + { + Err(Error::invalid_type(Unexpected::Option, &self)) + } + + /// The input contains an optional that is present. + /// + /// The default implementation fails with a type error. + fn visit_some(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let _ = deserializer; + Err(Error::invalid_type(Unexpected::Option, &self)) + } + + /// The input contains a unit `()`. + /// + /// The default implementation fails with a type error. + fn visit_unit(self) -> Result + where + E: Error, + { + Err(Error::invalid_type(Unexpected::Unit, &self)) + } + + /// The input contains a newtype struct. + /// + /// The content of the newtype struct may be read from the given + /// `Deserializer`. + /// + /// The default implementation fails with a type error. + fn visit_newtype_struct(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let _ = deserializer; + Err(Error::invalid_type(Unexpected::NewtypeStruct, &self)) + } + + /// The input contains a sequence of elements. + /// + /// The default implementation fails with a type error. + fn visit_seq(self, seq: A) -> Result + where + A: SeqAccess<'de>, + { + let _ = seq; + Err(Error::invalid_type(Unexpected::Seq, &self)) + } + + /// The input contains a key-value map. + /// + /// The default implementation fails with a type error. + fn visit_map(self, map: A) -> Result + where + A: MapAccess<'de>, + { + let _ = map; + Err(Error::invalid_type(Unexpected::Map, &self)) + } + + /// The input contains an enum. + /// + /// The default implementation fails with a type error. + fn visit_enum(self, data: A) -> Result + where + A: EnumAccess<'de>, + { + let _ = data; + Err(Error::invalid_type(Unexpected::Enum, &self)) + } + + // Used when deserializing a flattened Option field. Not public API. + #[doc(hidden)] + fn __private_visit_untagged_option(self, _: D) -> Result + where + D: Deserializer<'de>, + { + Err(()) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// Provides a `Visitor` access to each element of a sequence in the input. +/// +/// This is a trait that a `Deserializer` passes to a `Visitor` implementation, +/// which deserializes each item in a sequence. +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the lifetime of data that may be +/// borrowed by deserialized sequence elements. See the page [Understanding +/// deserializer lifetimes] for a more detailed explanation of these lifetimes. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// 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. + type Error: Error; + + /// This returns `Ok(Some(value))` for the next value in the sequence, or + /// `Ok(None)` if there are no more remaining items. + /// + /// `Deserialize` implementations should typically use + /// `SeqAccess::next_element` instead. + fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> + where + T: DeserializeSeed<'de>; + + /// This returns `Ok(Some(value))` for the next value in the sequence, or + /// `Ok(None)` if there are no more remaining items. + /// + /// This method exists as a convenience for `Deserialize` implementations. + /// `SeqAccess` implementations should not override the default behavior. + #[inline] + fn next_element(&mut self) -> Result, Self::Error> + where + T: Deserialize<'de>, + { + self.next_element_seed(PhantomData) + } + + /// Returns the number of elements remaining in the sequence, if known. + #[inline] + fn size_hint(&self) -> Option { + None + } +} + +impl<'de, A> SeqAccess<'de> for &mut A +where + A: ?Sized + SeqAccess<'de>, +{ + type Error = A::Error; + + #[inline] + fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> + where + T: DeserializeSeed<'de>, + { + (**self).next_element_seed(seed) + } + + #[inline] + fn next_element(&mut self) -> Result, Self::Error> + where + T: Deserialize<'de>, + { + (**self).next_element() + } + + #[inline] + fn size_hint(&self) -> Option { + (**self).size_hint() + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// Provides a `Visitor` access to each entry of a map in the input. +/// +/// This is a trait that a `Deserializer` passes to a `Visitor` implementation. +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the lifetime of data that may be +/// borrowed by deserialized map entries. See the page [Understanding +/// deserializer lifetimes] for a more detailed explanation of these lifetimes. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// 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. + type Error: Error; + + /// This returns `Ok(Some(key))` for the next key in the map, or `Ok(None)` + /// if there are no more remaining entries. + /// + /// `Deserialize` implementations should typically use + /// `MapAccess::next_key` or `MapAccess::next_entry` instead. + fn next_key_seed(&mut self, seed: K) -> Result, Self::Error> + where + K: DeserializeSeed<'de>; + + /// This returns a `Ok(value)` for the next value in the map. + /// + /// `Deserialize` implementations should typically use + /// `MapAccess::next_value` instead. + /// + /// # Panics + /// + /// Calling `next_value_seed` before `next_key_seed` is incorrect and is + /// allowed to panic or return bogus results. + fn next_value_seed(&mut self, seed: V) -> Result + where + V: DeserializeSeed<'de>; + + /// This returns `Ok(Some((key, value)))` for the next (key-value) pair in + /// the map, or `Ok(None)` if there are no more remaining items. + /// + /// `MapAccess` implementations should override the default behavior if a + /// more efficient implementation is possible. + /// + /// `Deserialize` implementations should typically use + /// `MapAccess::next_entry` instead. + #[inline] + fn next_entry_seed( + &mut self, + kseed: K, + vseed: V, + ) -> Result, Self::Error> + where + K: DeserializeSeed<'de>, + V: DeserializeSeed<'de>, + { + match tri!(self.next_key_seed(kseed)) { + Some(key) => { + let value = tri!(self.next_value_seed(vseed)); + Ok(Some((key, value))) + } + None => Ok(None), + } + } + + /// This returns `Ok(Some(key))` for the next key in the map, or `Ok(None)` + /// if there are no more remaining entries. + /// + /// This method exists as a convenience for `Deserialize` implementations. + /// `MapAccess` implementations should not override the default behavior. + #[inline] + fn next_key(&mut self) -> Result, Self::Error> + where + K: Deserialize<'de>, + { + self.next_key_seed(PhantomData) + } + + /// This returns a `Ok(value)` for the next value in the map. + /// + /// This method exists as a convenience for `Deserialize` implementations. + /// `MapAccess` implementations should not override the default behavior. + /// + /// # Panics + /// + /// Calling `next_value` before `next_key` is incorrect and is allowed to + /// panic or return bogus results. + #[inline] + fn next_value(&mut self) -> Result + where + V: Deserialize<'de>, + { + self.next_value_seed(PhantomData) + } + + /// This returns `Ok(Some((key, value)))` for the next (key-value) pair in + /// the map, or `Ok(None)` if there are no more remaining items. + /// + /// This method exists as a convenience for `Deserialize` implementations. + /// `MapAccess` implementations should not override the default behavior. + #[inline] + fn next_entry(&mut self) -> Result, Self::Error> + where + K: Deserialize<'de>, + V: Deserialize<'de>, + { + self.next_entry_seed(PhantomData, PhantomData) + } + + /// Returns the number of entries remaining in the map, if known. + #[inline] + fn size_hint(&self) -> Option { + None + } +} + +impl<'de, A> MapAccess<'de> for &mut A +where + A: ?Sized + MapAccess<'de>, +{ + type Error = A::Error; + + #[inline] + fn next_key_seed(&mut self, seed: K) -> Result, Self::Error> + where + K: DeserializeSeed<'de>, + { + (**self).next_key_seed(seed) + } + + #[inline] + fn next_value_seed(&mut self, seed: V) -> Result + where + V: DeserializeSeed<'de>, + { + (**self).next_value_seed(seed) + } + + #[inline] + fn next_entry_seed( + &mut self, + kseed: K, + vseed: V, + ) -> Result, Self::Error> + where + K: DeserializeSeed<'de>, + V: DeserializeSeed<'de>, + { + (**self).next_entry_seed(kseed, vseed) + } + + #[inline] + fn next_entry(&mut self) -> Result, Self::Error> + where + K: Deserialize<'de>, + V: Deserialize<'de>, + { + (**self).next_entry() + } + + #[inline] + fn next_key(&mut self) -> Result, Self::Error> + where + K: Deserialize<'de>, + { + (**self).next_key() + } + + #[inline] + fn next_value(&mut self) -> Result + where + V: Deserialize<'de>, + { + (**self).next_value() + } + + #[inline] + fn size_hint(&self) -> Option { + (**self).size_hint() + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// Provides a `Visitor` access to the data of an enum in the input. +/// +/// `EnumAccess` is created by the `Deserializer` and passed to the +/// `Visitor` in order to identify which variant of an enum to deserialize. +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the lifetime of data that may be +/// borrowed by the deserialized enum variant. See the page [Understanding +/// deserializer lifetimes] for a more detailed explanation of these lifetimes. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// 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. + type Error: Error; + /// The `Visitor` that will be used to deserialize the content of the enum + /// variant. + type Variant: VariantAccess<'de, Error = Self::Error>; + + /// `variant` is called to identify which variant to deserialize. + /// + /// `Deserialize` implementations should typically use `EnumAccess::variant` + /// instead. + fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> + where + V: DeserializeSeed<'de>; + + /// `variant` is called to identify which variant to deserialize. + /// + /// This method exists as a convenience for `Deserialize` implementations. + /// `EnumAccess` implementations should not override the default behavior. + #[inline] + fn variant(self) -> Result<(V, Self::Variant), Self::Error> + where + V: Deserialize<'de>, + { + self.variant_seed(PhantomData) + } +} + +/// `VariantAccess` is a visitor that is created by the `Deserializer` and +/// passed to the `Deserialize` to deserialize the content of a particular enum +/// variant. +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the lifetime of data that may be +/// borrowed by the deserialized enum variant. See the page [Understanding +/// deserializer lifetimes] for a more detailed explanation of these lifetimes. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// 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`. + type Error: Error; + + /// Called when deserializing a variant with no values. + /// + /// If the data contains a different type of variant, the following + /// `invalid_type` error should be constructed: + /// + /// ```edition2021 + /// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected}; + /// # + /// # struct X; + /// # + /// # impl<'de> VariantAccess<'de> for X { + /// # type Error = value::Error; + /// # + /// fn unit_variant(self) -> Result<(), Self::Error> { + /// // What the data actually contained; suppose it is a tuple variant. + /// let unexp = Unexpected::TupleVariant; + /// Err(de::Error::invalid_type(unexp, &"unit variant")) + /// } + /// # + /// # fn newtype_variant_seed(self, _: T) -> Result + /// # where + /// # T: DeserializeSeed<'de>, + /// # { unimplemented!() } + /// # + /// # fn tuple_variant(self, _: usize, _: V) -> Result + /// # where + /// # V: Visitor<'de>, + /// # { unimplemented!() } + /// # + /// # fn struct_variant(self, _: &[&str], _: V) -> Result + /// # where + /// # V: Visitor<'de>, + /// # { unimplemented!() } + /// # } + /// ``` + fn unit_variant(self) -> Result<(), Self::Error>; + + /// Called when deserializing a variant with a single value. + /// + /// `Deserialize` implementations should typically use + /// `VariantAccess::newtype_variant` instead. + /// + /// If the data contains a different type of variant, the following + /// `invalid_type` error should be constructed: + /// + /// ```edition2021 + /// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected}; + /// # + /// # struct X; + /// # + /// # impl<'de> VariantAccess<'de> for X { + /// # type Error = value::Error; + /// # + /// # fn unit_variant(self) -> Result<(), Self::Error> { + /// # unimplemented!() + /// # } + /// # + /// fn newtype_variant_seed(self, _seed: T) -> Result + /// where + /// T: DeserializeSeed<'de>, + /// { + /// // What the data actually contained; suppose it is a unit variant. + /// let unexp = Unexpected::UnitVariant; + /// Err(de::Error::invalid_type(unexp, &"newtype variant")) + /// } + /// # + /// # fn tuple_variant(self, _: usize, _: V) -> Result + /// # where + /// # V: Visitor<'de>, + /// # { unimplemented!() } + /// # + /// # fn struct_variant(self, _: &[&str], _: V) -> Result + /// # where + /// # V: Visitor<'de>, + /// # { unimplemented!() } + /// # } + /// ``` + fn newtype_variant_seed(self, seed: T) -> Result + where + T: DeserializeSeed<'de>; + + /// Called when deserializing a variant with a single value. + /// + /// This method exists as a convenience for `Deserialize` implementations. + /// `VariantAccess` implementations should not override the default + /// behavior. + #[inline] + fn newtype_variant(self) -> Result + where + T: Deserialize<'de>, + { + self.newtype_variant_seed(PhantomData) + } + + /// Called when deserializing a tuple-like variant. + /// + /// The `len` is the number of fields expected in the tuple variant. + /// + /// If the data contains a different type of variant, the following + /// `invalid_type` error should be constructed: + /// + /// ```edition2021 + /// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected}; + /// # + /// # struct X; + /// # + /// # impl<'de> VariantAccess<'de> for X { + /// # type Error = value::Error; + /// # + /// # fn unit_variant(self) -> Result<(), Self::Error> { + /// # unimplemented!() + /// # } + /// # + /// # fn newtype_variant_seed(self, _: T) -> Result + /// # where + /// # T: DeserializeSeed<'de>, + /// # { unimplemented!() } + /// # + /// fn tuple_variant(self, _len: usize, _visitor: V) -> Result + /// where + /// V: Visitor<'de>, + /// { + /// // What the data actually contained; suppose it is a unit variant. + /// let unexp = Unexpected::UnitVariant; + /// Err(de::Error::invalid_type(unexp, &"tuple variant")) + /// } + /// # + /// # fn struct_variant(self, _: &[&str], _: V) -> Result + /// # where + /// # V: Visitor<'de>, + /// # { unimplemented!() } + /// # } + /// ``` + fn tuple_variant(self, len: usize, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Called when deserializing a struct-like variant. + /// + /// The `fields` are the names of the fields of the struct variant. + /// + /// If the data contains a different type of variant, the following + /// `invalid_type` error should be constructed: + /// + /// ```edition2021 + /// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected}; + /// # + /// # struct X; + /// # + /// # impl<'de> VariantAccess<'de> for X { + /// # type Error = value::Error; + /// # + /// # fn unit_variant(self) -> Result<(), Self::Error> { + /// # unimplemented!() + /// # } + /// # + /// # fn newtype_variant_seed(self, _: T) -> Result + /// # where + /// # T: DeserializeSeed<'de>, + /// # { unimplemented!() } + /// # + /// # fn tuple_variant(self, _: usize, _: V) -> Result + /// # where + /// # V: Visitor<'de>, + /// # { unimplemented!() } + /// # + /// fn struct_variant( + /// self, + /// _fields: &'static [&'static str], + /// _visitor: V, + /// ) -> Result + /// where + /// V: Visitor<'de>, + /// { + /// // What the data actually contained; suppose it is a unit variant. + /// let unexp = Unexpected::UnitVariant; + /// Err(de::Error::invalid_type(unexp, &"struct variant")) + /// } + /// # } + /// ``` + fn struct_variant( + self, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>; +} + +//////////////////////////////////////////////////////////////////////////////// + +/// Converts an existing value into a `Deserializer` from which other values can +/// be deserialized. +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the lifetime of data that may be +/// borrowed from the resulting `Deserializer`. See the page [Understanding +/// deserializer lifetimes] for a more detailed explanation of these lifetimes. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +/// +/// # Example +/// +/// ```edition2021 +/// use serde::de::{value, Deserialize, IntoDeserializer}; +/// use serde_derive::Deserialize; +/// use std::str::FromStr; +/// +/// #[derive(Deserialize)] +/// enum Setting { +/// On, +/// Off, +/// } +/// +/// impl FromStr for Setting { +/// type Err = value::Error; +/// +/// fn from_str(s: &str) -> Result { +/// Self::deserialize(s.into_deserializer()) +/// } +/// } +/// ``` +pub trait IntoDeserializer<'de, E: Error = value::Error> { + /// The type of the deserializer being converted into. + type Deserializer: Deserializer<'de, Error = E>; + + /// Convert this value into a deserializer. + fn into_deserializer(self) -> Self::Deserializer; +} + +//////////////////////////////////////////////////////////////////////////////// + +/// Used in error messages. +/// +/// - expected `a` +/// - expected `a` or `b` +/// - expected one of `a`, `b`, `c` +/// +/// The slice of names must not be empty. +struct OneOf { + names: &'static [&'static str], +} + +impl Display for OneOf { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self.names.len() { + 0 => panic!(), // special case elsewhere + 1 => write!(formatter, "`{}`", self.names[0]), + 2 => write!(formatter, "`{}` or `{}`", self.names[0], self.names[1]), + _ => { + tri!(formatter.write_str("one of ")); + for (i, alt) in self.names.iter().enumerate() { + if i > 0 { + tri!(formatter.write_str(", ")); + } + 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/third_party/crates/serde-1.0.229/src/core/de/value.rs b/third_party/crates/serde-1.0.229/src/core/de/value.rs new file mode 100644 index 0000000..3d5475d --- /dev/null +++ b/third_party/crates/serde-1.0.229/src/core/de/value.rs @@ -0,0 +1,1895 @@ +//! Building blocks for deserializing basic values using the `IntoDeserializer` +//! trait. +//! +//! ```edition2021 +//! use serde::de::{value, Deserialize, IntoDeserializer}; +//! use serde_derive::Deserialize; +//! use std::str::FromStr; +//! +//! #[derive(Deserialize)] +//! enum Setting { +//! On, +//! Off, +//! } +//! +//! impl FromStr for Setting { +//! type Err = value::Error; +//! +//! fn from_str(s: &str) -> Result { +//! Self::deserialize(s.into_deserializer()) +//! } +//! } +//! ``` + +use crate::lib::*; + +use self::private::{First, Second}; +use crate::de::{self, Deserializer, Expected, IntoDeserializer, SeqAccess, Visitor}; +use crate::private::size_hint; +use crate::ser; + +//////////////////////////////////////////////////////////////////////////////// + +// For structs that contain a PhantomData. We do not want the trait +// bound `E: Clone` inferred by derive(Clone). +macro_rules! impl_copy_clone { + ($ty:ident $(<$lifetime:tt>)*) => { + impl<$($lifetime,)* E> Copy for $ty<$($lifetime,)* E> {} + + impl<$($lifetime,)* E> Clone for $ty<$($lifetime,)* E> { + fn clone(&self) -> Self { + *self + } + } + }; +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A minimal representation of all possible errors that can occur using the +/// `IntoDeserializer` trait. +#[derive(Clone, PartialEq)] +pub struct Error { + err: ErrorImpl, +} + +#[cfg(any(feature = "std", feature = "alloc"))] +type ErrorImpl = Box; +#[cfg(not(any(feature = "std", feature = "alloc")))] +type ErrorImpl = (); + +impl de::Error for Error { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cold] + fn custom(msg: T) -> Self + where + T: Display, + { + Error { + err: msg.to_string().into_boxed_str(), + } + } + + #[cfg(not(any(feature = "std", feature = "alloc")))] + #[cold] + fn custom(msg: T) -> Self + where + T: Display, + { + let _ = msg; + Error { err: () } + } +} + +impl ser::Error for Error { + #[cold] + fn custom(msg: T) -> Self + where + T: Display, + { + de::Error::custom(msg) + } +} + +impl Display for Error { + #[cfg(any(feature = "std", feature = "alloc"))] + 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) -> 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 + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl<'de, E> IntoDeserializer<'de, E> for () +where + E: de::Error, +{ + type Deserializer = UnitDeserializer; + + fn into_deserializer(self) -> UnitDeserializer { + UnitDeserializer::new() + } +} + +/// A deserializer holding a `()`. +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, +{ + type Error = E; + + 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 + } + + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_unit() + } + + fn deserialize_option(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_none() + } +} + +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, +{ + type Deserializer = NeverDeserializer; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} + +#[cfg(feature = "unstable")] +impl<'de, E> de::Deserializer<'de> for NeverDeserializer +where + E: de::Error, +{ + type Error = E; + + fn deserialize_any(self, _visitor: V) -> Result + where + V: de::Visitor<'de>, + { + self.never + } + + 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(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] + pub struct $name { + value: $ty, + marker: PhantomData + } + + impl_copy_clone!($name); + + impl<'de, E> IntoDeserializer<'de, E> for $ty + where + E: de::Error, + { + type Deserializer = $name; + + fn into_deserializer(self) -> $name { + $name::new(self) + } + } + + impl $name { + #[allow(missing_docs)] + pub fn new(value: $ty) -> Self { + $name { + value, + marker: PhantomData, + } + } + } + + impl<'de, E> de::Deserializer<'de> for $name + where + E: de::Error, + { + type Error = E; + + 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 deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + 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() + } + } + } +} + +primitive_deserializer!(bool, "a `bool`.", BoolDeserializer, visit_bool); +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); + +/// A deserializer holding a `u32`. +pub struct U32Deserializer { + value: u32, + marker: PhantomData, +} + +impl_copy_clone!(U32Deserializer); + +impl<'de, E> IntoDeserializer<'de, E> for u32 +where + E: de::Error, +{ + type Deserializer = U32Deserializer; + + fn into_deserializer(self) -> U32Deserializer { + U32Deserializer::new(self) + } +} + +impl U32Deserializer { + #[allow(missing_docs)] + pub fn new(value: u32) -> Self { + U32Deserializer { + value, + marker: PhantomData, + } + } +} + +impl<'de, E> de::Deserializer<'de> for U32Deserializer +where + E: de::Error, +{ + type Error = E; + + 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 + } + + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_u32(self.value) + } + + fn deserialize_enum( + self, + name: &str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + let _ = name; + let _ = variants; + visitor.visit_enum(self) + } +} + +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, +{ + type Error = E; + type Variant = private::UnitOnly; + + fn variant_seed(self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error> + where + T: de::DeserializeSeed<'de>, + { + seed.deserialize(self).map(private::unit_only) + } +} + +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`. +pub struct StrDeserializer<'a, E> { + value: &'a str, + marker: PhantomData, +} + +impl_copy_clone!(StrDeserializer<'de>); + +impl<'de, 'a, E> IntoDeserializer<'de, E> for &'a str +where + E: de::Error, +{ + 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, + marker: PhantomData, + } + } +} + +impl<'de, 'a, E> de::Deserializer<'de> for StrDeserializer<'a, E> +where + E: de::Error, +{ + type Error = E; + + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_str(self.value) + } + + fn deserialize_enum( + self, + name: &str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + let _ = name; + let _ = variants; + visitor.visit_enum(self) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct identifier ignored_any + } +} + +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, +{ + type Error = E; + type Variant = private::UnitOnly; + + fn variant_seed(self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error> + where + T: de::DeserializeSeed<'de>, + { + seed.deserialize(self).map(private::unit_only) + } +} + +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. +pub struct BorrowedStrDeserializer<'de, E> { + value: &'de str, + marker: PhantomData, +} + +impl_copy_clone!(BorrowedStrDeserializer<'de>); + +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, + marker: PhantomData, + } + } +} + +impl<'de, E> de::Deserializer<'de> for BorrowedStrDeserializer<'de, E> +where + E: de::Error, +{ + type Error = E; + + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_borrowed_str(self.value) + } + + fn deserialize_enum( + self, + name: &str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + let _ = name; + let _ = variants; + visitor.visit_enum(self) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct identifier ignored_any + } +} + +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, +{ + type Error = E; + type Variant = private::UnitOnly; + + fn variant_seed(self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error> + where + T: de::DeserializeSeed<'de>, + { + seed.deserialize(self).map(private::unit_only) + } +} + +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"))] +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] +pub struct StringDeserializer { + value: String, + marker: PhantomData, +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl Clone for StringDeserializer { + fn clone(&self) -> Self { + StringDeserializer { + value: self.value.clone(), + marker: PhantomData, + } + } +} + +#[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, +{ + 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, + marker: PhantomData, + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'de, E> de::Deserializer<'de> for StringDeserializer +where + E: de::Error, +{ + type Error = E; + + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_string(self.value) + } + + fn deserialize_enum( + self, + name: &str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + let _ = name; + let _ = variants; + visitor.visit_enum(self) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct identifier ignored_any + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +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, +{ + type Error = E; + type Variant = private::UnitOnly; + + fn variant_seed(self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error> + where + T: de::DeserializeSeed<'de>, + { + seed.deserialize(self).map(private::unit_only) + } +} + +#[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"))] +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] +pub struct CowStrDeserializer<'a, E> { + value: Cow<'a, str>, + marker: PhantomData, +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, E> Clone for CowStrDeserializer<'a, E> { + fn clone(&self) -> Self { + CowStrDeserializer { + value: self.value.clone(), + marker: PhantomData, + } + } +} + +#[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, +{ + 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, + marker: PhantomData, + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'de, 'a, E> de::Deserializer<'de> for CowStrDeserializer<'a, E> +where + E: de::Error, +{ + type Error = E; + + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + match self.value { + Cow::Borrowed(string) => visitor.visit_str(string), + Cow::Owned(string) => visitor.visit_string(string), + } + } + + fn deserialize_enum( + self, + name: &str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + let _ = name; + let _ = variants; + visitor.visit_enum(self) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct identifier ignored_any + } +} + +#[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 + E: de::Error, +{ + type Error = E; + type Variant = private::UnitOnly; + + fn variant_seed(self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error> + where + T: de::DeserializeSeed<'de>, + { + seed.deserialize(self).map(private::unit_only) + } +} + +#[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. Always calls [`Visitor::visit_borrowed_bytes`]. +pub struct BorrowedBytesDeserializer<'de, E> { + value: &'de [u8], + marker: PhantomData, +} + +impl<'de, E> BorrowedBytesDeserializer<'de, E> { + /// Create a new borrowed deserializer from the given borrowed bytes. + pub fn new(value: &'de [u8]) -> Self { + BorrowedBytesDeserializer { + value, + marker: PhantomData, + } + } +} + +impl_copy_clone!(BorrowedBytesDeserializer<'de>); + +impl<'de, E> Deserializer<'de> for BorrowedBytesDeserializer<'de, E> +where + E: de::Error, +{ + type Error = E; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_borrowed_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, 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)] +pub struct SeqDeserializer { + iter: iter::Fuse, + count: usize, + marker: PhantomData, +} + +impl SeqDeserializer +where + I: Iterator, +{ + /// Construct a new `SeqDeserializer`. + pub fn new(iter: I) -> Self { + SeqDeserializer { + iter: iter.fuse(), + count: 0, + marker: PhantomData, + } + } +} + +impl SeqDeserializer +where + I: Iterator, + E: de::Error, +{ + /// Check for remaining elements after passing a `SeqDeserializer` to + /// `Visitor::visit_seq`. + pub 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, I, T, E> de::Deserializer<'de> for SeqDeserializer +where + I: Iterator, + T: IntoDeserializer<'de, E>, + E: de::Error, +{ + type Error = E; + + fn deserialize_any(mut self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + let v = tri!(visitor.visit_seq(&mut self)); + tri!(self.end()); + Ok(v) + } + + 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, 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, + T: IntoDeserializer<'de, E>, + E: de::Error, +{ + type Error = E; + + fn next_element_seed(&mut self, seed: V) -> Result, Self::Error> + where + V: de::DeserializeSeed<'de>, + { + match self.iter.next() { + Some(value) => { + self.count += 1; + seed.deserialize(value.into_deserializer()).map(Some) + } + None => Ok(None), + } + } + + fn size_hint(&self) -> Option { + size_hint::from_bounds(&self.iter) + } +} + +struct ExpectedInSeq(usize); + +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) + } + } +} + +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>, + E: de::Error, +{ + type Deserializer = SeqDeserializer<::IntoIter, E>; + + fn into_deserializer(self) -> Self::Deserializer { + SeqDeserializer::new(self.into_iter()) + } +} + +#[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, + E: de::Error, +{ + type Deserializer = SeqDeserializer<::IntoIter, E>; + + fn into_deserializer(self) -> Self::Deserializer { + SeqDeserializer::new(self.into_iter()) + } +} + +#[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, + S: BuildHasher, + E: de::Error, +{ + type Deserializer = SeqDeserializer<::IntoIter, E>; + + fn into_deserializer(self) -> Self::Deserializer { + SeqDeserializer::new(self.into_iter()) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A deserializer holding a `SeqAccess`. +#[derive(Clone, Debug)] +pub struct SeqAccessDeserializer { + seq: A, +} + +impl SeqAccessDeserializer { + /// Construct a new `SeqAccessDeserializer`. + pub fn new(seq: A) -> Self { + SeqAccessDeserializer { seq } + } +} + +impl<'de, A> de::Deserializer<'de> for SeqAccessDeserializer +where + A: de::SeqAccess<'de>, +{ + type Error = A::Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_seq(self.seq) + } + + 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 SeqAccessDeserializer +where + A: de::SeqAccess<'de>, +{ + type Deserializer = Self; + + fn into_deserializer(self) -> Self { + self + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A deserializer that iterates over a map. +pub struct MapDeserializer<'de, I, E> +where + I: Iterator, + I::Item: private::Pair, +{ + iter: iter::Fuse, + value: Option>, + count: usize, + lifetime: PhantomData<&'de ()>, + error: PhantomData, +} + +impl<'de, I, E> MapDeserializer<'de, I, E> +where + I: Iterator, + I::Item: private::Pair, +{ + /// Construct a new `MapDeserializer`. + pub fn new(iter: I) -> Self { + MapDeserializer { + iter: iter.fuse(), + value: None, + count: 0, + lifetime: PhantomData, + error: PhantomData, + } + } +} + +impl<'de, I, E> MapDeserializer<'de, I, E> +where + I: Iterator, + I::Item: private::Pair, + E: de::Error, +{ + /// Check for remaining elements after passing a `MapDeserializer` to + /// `Visitor::visit_map`. + pub 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), + )) + } + } +} + +impl<'de, I, E> MapDeserializer<'de, I, E> +where + I: Iterator, + I::Item: private::Pair, +{ + fn next_pair(&mut self) -> Option<(First, Second)> { + match self.iter.next() { + Some(kv) => { + self.count += 1; + Some(private::Pair::split(kv)) + } + None => None, + } + } +} + +impl<'de, I, E> de::Deserializer<'de> for MapDeserializer<'de, I, E> +where + I: Iterator, + I::Item: private::Pair, + First: IntoDeserializer<'de, E>, + Second: IntoDeserializer<'de, E>, + E: de::Error, +{ + type Error = E; + + fn deserialize_any(mut self, visitor: V) -> Result + where + V: de::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: de::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: de::Visitor<'de>, + { + let _ = len; + self.deserialize_seq(visitor) + } + + 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 + } +} + +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, + I::Item: private::Pair, + First: IntoDeserializer<'de, E>, + Second: IntoDeserializer<'de, E>, + E: de::Error, +{ + type Error = E; + + fn next_key_seed(&mut self, seed: T) -> Result, Self::Error> + where + T: de::DeserializeSeed<'de>, + { + match self.next_pair() { + Some((key, value)) => { + self.value = Some(value); + seed.deserialize(key.into_deserializer()).map(Some) + } + None => Ok(None), + } + } + + fn next_value_seed(&mut self, seed: T) -> Result + where + T: de::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(value.into_deserializer()) + } + + fn next_entry_seed( + &mut self, + kseed: TK, + vseed: TV, + ) -> Result, Self::Error> + where + TK: de::DeserializeSeed<'de>, + TV: de::DeserializeSeed<'de>, + { + match self.next_pair() { + Some((key, value)) => { + let key = tri!(kseed.deserialize(key.into_deserializer())); + let value = tri!(vseed.deserialize(value.into_deserializer())); + Ok(Some((key, value))) + } + None => Ok(None), + } + } + + fn size_hint(&self) -> Option { + size_hint::from_bounds(&self.iter) + } +} + +impl<'de, I, E> de::SeqAccess<'de> for MapDeserializer<'de, I, E> +where + I: Iterator, + I::Item: private::Pair, + First: IntoDeserializer<'de, E>, + Second: IntoDeserializer<'de, E>, + E: de::Error, +{ + 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 = PairDeserializer(k, v, PhantomData); + seed.deserialize(de).map(Some) + } + None => Ok(None), + } + } + + fn size_hint(&self) -> Option { + size_hint::from_bounds(&self.iter) + } +} + +// Cannot #[derive(Clone)] because of the bound `Second: Clone`. +impl<'de, I, E> Clone for MapDeserializer<'de, I, E> +where + I: Iterator + Clone, + I::Item: private::Pair, + Second: Clone, +{ + fn clone(&self) -> Self { + MapDeserializer { + iter: self.iter.clone(), + value: self.value.clone(), + count: self.count, + lifetime: self.lifetime, + error: self.error, + } + } +} + +impl<'de, I, E> Debug for MapDeserializer<'de, I, E> +where + I: Iterator + Debug, + I::Item: private::Pair, + Second: Debug, +{ + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_struct("MapDeserializer") + .field("iter", &self.iter) + .field("value", &self.value) + .field("count", &self.count) + .finish() + } +} + +// Used in the `impl SeqAccess for MapDeserializer` to visit the map as a +// sequence of pairs. +struct PairDeserializer(A, B, PhantomData); + +impl<'de, A, B, E> de::Deserializer<'de> for PairDeserializer +where + A: IntoDeserializer<'de, E>, + B: IntoDeserializer<'de, E>, + E: de::Error, +{ + type Error = E; + + 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: de::Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: de::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(Option, Option, PhantomData); + +impl<'de, A, B, E> de::SeqAccess<'de> for PairVisitor +where + A: IntoDeserializer<'de, E>, + B: IntoDeserializer<'de, E>, + E: de::Error, +{ + type Error = E; + + fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> + where + T: de::DeserializeSeed<'de>, + { + if let Some(k) = self.0.take() { + seed.deserialize(k.into_deserializer()).map(Some) + } else if let Some(v) = self.1.take() { + seed.deserialize(v.into_deserializer()).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); + +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) + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[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, + V: IntoDeserializer<'de, E>, + E: de::Error, +{ + type Deserializer = MapDeserializer<'de, ::IntoIter, E>; + + fn into_deserializer(self) -> Self::Deserializer { + MapDeserializer::new(self.into_iter()) + } +} + +#[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, + V: IntoDeserializer<'de, E>, + S: BuildHasher, + E: de::Error, +{ + type Deserializer = MapDeserializer<'de, ::IntoIter, E>; + + fn into_deserializer(self) -> Self::Deserializer { + MapDeserializer::new(self.into_iter()) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A deserializer holding a `MapAccess`. +#[derive(Clone, Debug)] +pub struct MapAccessDeserializer { + map: A, +} + +impl MapAccessDeserializer { + /// Construct a new `MapAccessDeserializer`. + pub fn new(map: A) -> Self { + MapAccessDeserializer { map } + } +} + +impl<'de, A> de::Deserializer<'de> for MapAccessDeserializer +where + A: de::MapAccess<'de>, +{ + type Error = A::Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_map(self.map) + } + + fn deserialize_enum( + self, + _name: &str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_enum(self) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct identifier ignored_any + } +} + +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>, +{ + type Error = A::Error; + type Variant = private::MapAsEnum; + + fn variant_seed(mut self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error> + where + T: de::DeserializeSeed<'de>, + { + 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")), + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// 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 crate::lib::*; + + use crate::de::{ + self, DeserializeSeed, Deserializer, MapAccess, Unexpected, VariantAccess, Visitor, + }; + + pub struct UnitOnly { + marker: PhantomData, + } + + pub fn unit_only(t: T) -> (T, UnitOnly) { + ( + t, + UnitOnly { + marker: PhantomData, + }, + ) + } + + impl<'de, E> de::VariantAccess<'de> for UnitOnly + where + E: de::Error, + { + type Error = E; + + fn unit_variant(self) -> Result<(), Self::Error> { + Ok(()) + } + + fn newtype_variant_seed(self, _seed: T) -> Result + where + T: de::DeserializeSeed<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"newtype variant", + )) + } + + fn tuple_variant(self, _len: usize, _visitor: V) -> Result + where + V: de::Visitor<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"tuple variant", + )) + } + + fn struct_variant( + self, + _fields: &'static [&'static str], + _visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"struct variant", + )) + } + } + + pub struct MapAsEnum { + map: A, + } + + pub fn map_as_enum(map: A) -> MapAsEnum { + MapAsEnum { map } + } + + impl<'de, A> VariantAccess<'de> for MapAsEnum + where + A: MapAccess<'de>, + { + type Error = A::Error; + + fn unit_variant(mut self) -> Result<(), Self::Error> { + self.map.next_value() + } + + fn newtype_variant_seed(mut self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + self.map.next_value_seed(seed) + } + + fn tuple_variant(mut self, len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.map.next_value_seed(SeedTupleVariant { len, visitor }) + } + + fn struct_variant( + mut self, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.map.next_value_seed(SeedStructVariant { visitor }) + } + } + + struct SeedTupleVariant { + len: usize, + visitor: V, + } + + impl<'de, V> DeserializeSeed<'de> for SeedTupleVariant + where + V: Visitor<'de>, + { + type Value = V::Value; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_tuple(self.len, self.visitor) + } + } + + struct SeedStructVariant { + visitor: V, + } + + impl<'de, V> DeserializeSeed<'de> for SeedStructVariant + where + V: Visitor<'de>, + { + type Value = V::Value; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_map(self.visitor) + } + } + + /// Avoid having to restate the generic types on `MapDeserializer`. The + /// `Iterator::Item` contains enough information to figure out K and V. + pub trait Pair { + type First; + type Second; + fn split(self) -> (Self::First, Self::Second); + } + + impl Pair for (A, B) { + type First = A; + type Second = B; + fn split(self) -> (A, B) { + self + } + } + + pub type First = ::First; + pub type Second = ::Second; +} diff --git a/third_party/crates/serde-1.0.229/src/core/format.rs b/third_party/crates/serde-1.0.229/src/core/format.rs new file mode 100644 index 0000000..9053cc0 --- /dev/null +++ b/third_party/crates/serde-1.0.229/src/core/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/third_party/crates/serde-1.0.229/src/core/lib.rs b/third_party/crates/serde-1.0.229/src/core/lib.rs new file mode 100644 index 0000000..4420e50 --- /dev/null +++ b/third_party/crates/serde-1.0.229/src/core/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.229")] +// 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/third_party/crates/serde-1.0.229/src/core/macros.rs b/third_party/crates/serde-1.0.229/src/core/macros.rs new file mode 100644 index 0000000..b956730 --- /dev/null +++ b/third_party/crates/serde-1.0.229/src/core/macros.rs @@ -0,0 +1,230 @@ +// 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. +/// +/// Some [`Deserializer`] implementations for self-describing formats do not +/// care what hint the [`Visitor`] gives them, they just want to blindly call +/// the [`Visitor`] method corresponding to the data they can tell is in the +/// input. This requires repetitive implementations of all the [`Deserializer`] +/// trait methods. +/// +/// ```edition2021 +/// # use serde::forward_to_deserialize_any; +/// # use serde::de::{value, Deserializer, Visitor}; +/// # +/// # struct MyDeserializer; +/// # +/// # impl<'de> Deserializer<'de> for MyDeserializer { +/// # type Error = value::Error; +/// # +/// # fn deserialize_any(self, _: V) -> Result +/// # where +/// # V: Visitor<'de>, +/// # { +/// # unimplemented!() +/// # } +/// # +/// #[inline] +/// fn deserialize_bool(self, visitor: V) -> Result +/// where +/// V: Visitor<'de>, +/// { +/// self.deserialize_any(visitor) +/// } +/// # +/// # forward_to_deserialize_any! { +/// # 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 +/// # } +/// # } +/// ``` +/// +/// The `forward_to_deserialize_any!` macro implements these simple forwarding +/// methods so that they forward directly to [`Deserializer::deserialize_any`]. +/// You can choose which methods to forward. +/// +/// ```edition2021 +/// # use serde::forward_to_deserialize_any; +/// # use serde::de::{value, Deserializer, Visitor}; +/// # +/// # struct MyDeserializer; +/// # +/// impl<'de> Deserializer<'de> for MyDeserializer { +/// # type Error = value::Error; +/// # +/// fn deserialize_any(self, visitor: V) -> Result +/// where +/// V: Visitor<'de>, +/// { +/// /* ... */ +/// # let _ = visitor; +/// # unimplemented!() +/// } +/// +/// 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 +/// } +/// } +/// ``` +/// +/// The macro assumes the convention that your `Deserializer` lifetime parameter +/// is called `'de` and that the `Visitor` type parameters on each method are +/// called `V`. A different type parameter and a different lifetime can be +/// specified explicitly if necessary. +/// +/// ```edition2021 +/// # use serde::forward_to_deserialize_any; +/// # use serde::de::{value, Deserializer, Visitor}; +/// # use std::marker::PhantomData; +/// # +/// # struct MyDeserializer(PhantomData); +/// # +/// # impl<'q, V> Deserializer<'q> for MyDeserializer { +/// # type Error = value::Error; +/// # +/// # fn deserialize_any(self, visitor: W) -> Result +/// # where +/// # W: Visitor<'q>, +/// # { +/// # unimplemented!() +/// # } +/// # +/// 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 +/// } +/// # } +/// ``` +/// +/// [`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)*) => { + $(forward_to_deserialize_any_helper!{$func<$lifetime, $visitor>})* + }; + // This case must be after the previous one. + ($($func:ident)*) => { + $(forward_to_deserialize_any_helper!{$func<'de, V>})* + }; +} + +#[doc(hidden)] +#[macro_export] +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::__private::Result<$v::Value, >::Error> + where + $v: $crate::de::Visitor<$l>, + { + $( + let _ = $arg; + )* + self.deserialize_any(visitor) + } + }; +} + +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! forward_to_deserialize_any_helper { + (bool<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_bool<$l, $v>()} + }; + (i8<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_i8<$l, $v>()} + }; + (i16<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_i16<$l, $v>()} + }; + (i32<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_i32<$l, $v>()} + }; + (i64<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_i64<$l, $v>()} + }; + (i128<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_i128<$l, $v>()} + }; + (u8<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_u8<$l, $v>()} + }; + (u16<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_u16<$l, $v>()} + }; + (u32<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_u32<$l, $v>()} + }; + (u64<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_u64<$l, $v>()} + }; + (u128<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_u128<$l, $v>()} + }; + (f32<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_f32<$l, $v>()} + }; + (f64<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_f64<$l, $v>()} + }; + (char<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_char<$l, $v>()} + }; + (str<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_str<$l, $v>()} + }; + (string<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_string<$l, $v>()} + }; + (bytes<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_bytes<$l, $v>()} + }; + (byte_buf<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_byte_buf<$l, $v>()} + }; + (option<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_option<$l, $v>()} + }; + (unit<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_unit<$l, $v>()} + }; + (unit_struct<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_unit_struct<$l, $v>(name: &'static str)} + }; + (newtype_struct<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_newtype_struct<$l, $v>(name: &'static str)} + }; + (seq<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_seq<$l, $v>()} + }; + (tuple<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_tuple<$l, $v>(len: usize)} + }; + (tuple_struct<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_tuple_struct<$l, $v>(name: &'static str, len: usize)} + }; + (map<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_map<$l, $v>()} + }; + (struct<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_struct<$l, $v>(name: &'static str, fields: &'static [&'static str])} + }; + (enum<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_enum<$l, $v>(name: &'static str, variants: &'static [&'static str])} + }; + (identifier<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_identifier<$l, $v>()} + }; + (ignored_any<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_ignored_any<$l, $v>()} + }; +} diff --git a/third_party/crates/serde-1.0.229/src/core/private/content.rs b/third_party/crates/serde-1.0.229/src/core/private/content.rs new file mode 100644 index 0000000..f29a9b5 --- /dev/null +++ b/third_party/crates/serde-1.0.229/src/core/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/third_party/crates/serde-1.0.229/src/core/private/doc.rs b/third_party/crates/serde-1.0.229/src/core/private/doc.rs new file mode 100644 index 0000000..2cc07f0 --- /dev/null +++ b/third_party/crates/serde-1.0.229/src/core/private/doc.rs @@ -0,0 +1,165 @@ +// 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 { + () => { + trait Serialize { + fn serialize(&self, serializer: S) -> Result + where + S: $crate::Serializer; + } + }; +} + +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! __serialize_unimplemented { + ($($func:ident)*) => { + $( + __serialize_unimplemented_helper!($func); + )* + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __serialize_unimplemented_method { + ($func:ident $(<$t:ident>)* ($($arg:ty),*) -> $ret:ident) => { + fn $func $(<$t>)* (self $(, _: $arg)*) -> $crate::__private::Result + where + $($t: ?Sized + $crate::Serialize,)* + { + unimplemented!() + } + }; +} + +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! __serialize_unimplemented_helper { + (bool) => { + __serialize_unimplemented_method!(serialize_bool(bool) -> Ok); + }; + (i8) => { + __serialize_unimplemented_method!(serialize_i8(i8) -> Ok); + }; + (i16) => { + __serialize_unimplemented_method!(serialize_i16(i16) -> Ok); + }; + (i32) => { + __serialize_unimplemented_method!(serialize_i32(i32) -> Ok); + }; + (i64) => { + __serialize_unimplemented_method!(serialize_i64(i64) -> Ok); + }; + (u8) => { + __serialize_unimplemented_method!(serialize_u8(u8) -> Ok); + }; + (u16) => { + __serialize_unimplemented_method!(serialize_u16(u16) -> Ok); + }; + (u32) => { + __serialize_unimplemented_method!(serialize_u32(u32) -> Ok); + }; + (u64) => { + __serialize_unimplemented_method!(serialize_u64(u64) -> Ok); + }; + (f32) => { + __serialize_unimplemented_method!(serialize_f32(f32) -> Ok); + }; + (f64) => { + __serialize_unimplemented_method!(serialize_f64(f64) -> Ok); + }; + (char) => { + __serialize_unimplemented_method!(serialize_char(char) -> Ok); + }; + (str) => { + __serialize_unimplemented_method!(serialize_str(&str) -> Ok); + }; + (bytes) => { + __serialize_unimplemented_method!(serialize_bytes(&[u8]) -> Ok); + }; + (none) => { + __serialize_unimplemented_method!(serialize_none() -> Ok); + }; + (some) => { + __serialize_unimplemented_method!(serialize_some(&T) -> Ok); + }; + (unit) => { + __serialize_unimplemented_method!(serialize_unit() -> Ok); + }; + (unit_struct) => { + __serialize_unimplemented_method!(serialize_unit_struct(&str) -> Ok); + }; + (unit_variant) => { + __serialize_unimplemented_method!(serialize_unit_variant(&str, u32, &str) -> Ok); + }; + (newtype_struct) => { + __serialize_unimplemented_method!(serialize_newtype_struct(&str, &T) -> Ok); + }; + (newtype_variant) => { + __serialize_unimplemented_method!(serialize_newtype_variant(&str, u32, &str, &T) -> Ok); + }; + (seq) => { + type SerializeSeq = $crate::ser::Impossible; + __serialize_unimplemented_method!(serialize_seq(Option) -> SerializeSeq); + }; + (tuple) => { + type SerializeTuple = $crate::ser::Impossible; + __serialize_unimplemented_method!(serialize_tuple(usize) -> SerializeTuple); + }; + (tuple_struct) => { + type SerializeTupleStruct = $crate::ser::Impossible; + __serialize_unimplemented_method!(serialize_tuple_struct(&str, usize) -> SerializeTupleStruct); + }; + (tuple_variant) => { + type SerializeTupleVariant = $crate::ser::Impossible; + __serialize_unimplemented_method!(serialize_tuple_variant(&str, u32, &str, usize) -> SerializeTupleVariant); + }; + (map) => { + type SerializeMap = $crate::ser::Impossible; + __serialize_unimplemented_method!(serialize_map(Option) -> SerializeMap); + }; + (struct) => { + type SerializeStruct = $crate::ser::Impossible; + __serialize_unimplemented_method!(serialize_struct(&str, usize) -> SerializeStruct); + }; + (struct_variant) => { + type SerializeStructVariant = $crate::ser::Impossible; + __serialize_unimplemented_method!(serialize_struct_variant(&str, u32, &str, usize) -> SerializeStructVariant); + }; +} diff --git a/third_party/crates/serde-1.0.229/src/core/private/mod.rs b/third_party/crates/serde-1.0.229/src/core/private/mod.rs new file mode 100644 index 0000000..dd5f93f --- /dev/null +++ b/third_party/crates/serde-1.0.229/src/core/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/third_party/crates/serde-1.0.229/src/core/private/seed.rs b/third_party/crates/serde-1.0.229/src/core/private/seed.rs new file mode 100644 index 0000000..bcf267c --- /dev/null +++ b/third_party/crates/serde-1.0.229/src/core/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/third_party/crates/serde-1.0.229/src/core/private/size_hint.rs b/third_party/crates/serde-1.0.229/src/core/private/size_hint.rs new file mode 100644 index 0000000..783281b --- /dev/null +++ b/third_party/crates/serde-1.0.229/src/core/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/third_party/crates/serde-1.0.229/src/core/private/string.rs b/third_party/crates/serde-1.0.229/src/core/private/string.rs new file mode 100644 index 0000000..c8121a0 --- /dev/null +++ b/third_party/crates/serde-1.0.229/src/core/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/third_party/crates/serde-1.0.229/src/core/ser/fmt.rs b/third_party/crates/serde-1.0.229/src/core/ser/fmt.rs new file mode 100644 index 0000000..4b1549f --- /dev/null +++ b/third_party/crates/serde-1.0.229/src/core/ser/fmt.rs @@ -0,0 +1,170 @@ +use crate::lib::*; +use crate::ser::{Error, Impossible, Serialize, Serializer}; + +impl Error for fmt::Error { + fn custom(_msg: T) -> Self { + fmt::Error + } +} + +macro_rules! fmt_primitives { + ($($f:ident: $t:ty,)*) => { + $( + fn $f(self, v: $t) -> fmt::Result { + Display::fmt(&v, self) + } + )* + }; +} + +/// ```edition2021 +/// use serde::ser::Serialize; +/// use serde_derive::Serialize; +/// use std::fmt::{self, Display}; +/// +/// #[derive(Serialize)] +/// #[serde(rename_all = "kebab-case")] +/// pub enum MessageType { +/// StartRequest, +/// EndRequest, +/// } +/// +/// impl Display for MessageType { +/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// self.serialize(f) +/// } +/// } +/// ``` +impl<'a> Serializer for &mut fmt::Formatter<'a> { + type Ok = (); + type Error = fmt::Error; + type SerializeSeq = Impossible<(), fmt::Error>; + type SerializeTuple = Impossible<(), fmt::Error>; + type SerializeTupleStruct = Impossible<(), fmt::Error>; + type SerializeTupleVariant = Impossible<(), fmt::Error>; + type SerializeMap = Impossible<(), fmt::Error>; + type SerializeStruct = Impossible<(), fmt::Error>; + type SerializeStructVariant = Impossible<(), fmt::Error>; + + fmt_primitives! { + serialize_bool: bool, + serialize_i8: i8, + 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, + serialize_str: &str, + serialize_unit_struct: &'static str, + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> fmt::Result { + Display::fmt(variant, self) + } + + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> fmt::Result + where + T: ?Sized + Serialize, + { + Serialize::serialize(value, self) + } + + fn serialize_bytes(self, _v: &[u8]) -> fmt::Result { + Err(fmt::Error) + } + + fn serialize_none(self) -> fmt::Result { + Err(fmt::Error) + } + + fn serialize_some(self, _value: &T) -> fmt::Result + where + T: ?Sized + Serialize, + { + Err(fmt::Error) + } + + fn serialize_unit(self) -> fmt::Result { + Err(fmt::Error) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> fmt::Result + where + T: ?Sized + Serialize, + { + Err(fmt::Error) + } + + fn serialize_seq(self, _len: Option) -> Result { + Err(fmt::Error) + } + + fn serialize_tuple(self, _len: usize) -> Result { + Err(fmt::Error) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + Err(fmt::Error) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(fmt::Error) + } + + fn serialize_map(self, _len: Option) -> Result { + Err(fmt::Error) + } + + fn serialize_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + Err(fmt::Error) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(fmt::Error) + } + + fn collect_str(self, value: &T) -> fmt::Result + where + T: ?Sized + Display, + { + Display::fmt(value, self) + } +} diff --git a/third_party/crates/serde-1.0.229/src/core/ser/impls.rs b/third_party/crates/serde-1.0.229/src/core/ser/impls.rs new file mode 100644 index 0000000..a7a175d --- /dev/null +++ b/third_party/crates/serde-1.0.229/src/core/ser/impls.rs @@ -0,0 +1,1045 @@ +use crate::lib::*; + +use crate::ser::{Error, Serialize, SerializeTuple, Serializer}; + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! primitive_impl { + ($ty:ident, $method:ident $($cast:tt)*) => { + impl Serialize for $ty { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.$method(*self $($cast)*) + } + } + } +} + +primitive_impl!(bool, serialize_bool); +primitive_impl!(isize, serialize_i64 as i64); +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); + +//////////////////////////////////////////////////////////////////////////////// + +impl Serialize for str { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(self) + } +} + +#[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 + where + S: Serializer, + { + serializer.serialize_str(self) + } +} + +impl<'a> Serialize for fmt::Arguments<'a> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_str(self) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[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 + where + S: Serializer, + { + serializer.serialize_bytes(self.to_bytes()) + } +} + +#[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 + where + S: Serializer, + { + serializer.serialize_bytes(self.to_bytes()) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl Serialize for Option +where + T: Serialize, +{ + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match *self { + Some(ref value) => serializer.serialize_some(value), + None => serializer.serialize_none(), + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl Serialize for PhantomData +where + T: ?Sized, +{ + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_unit_struct("PhantomData") + } +} + +//////////////////////////////////////////////////////////////////////////////// + +// Does not require T: Serialize. +impl Serialize for [T; 0] { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + tri!(serializer.serialize_tuple(0)).end() + } +} + +macro_rules! array_impls { + ($($len:tt)+) => { + $( + impl Serialize for [T; $len] + where + T: Serialize, + { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut seq = tri!(serializer.serialize_tuple($len)); + for e in self { + tri!(seq.serialize_element(e)); + } + seq.end() + } + } + )+ + } +} + +array_impls! { + 01 02 03 04 05 06 07 08 09 10 + 11 12 13 14 15 16 17 18 19 20 + 21 22 23 24 25 26 27 28 29 30 + 31 32 +} + +//////////////////////////////////////////////////////////////////////////////// + +impl Serialize for [T] +where + T: Serialize, +{ + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_seq(self) + } +} + +macro_rules! seq_impl { + ( + $(#[$attr:meta])* + $ty:ident + ) => { + $(#[$attr])* + impl Serialize for $ty + where + T: Serialize, + { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_seq(self) + } + } + } +} + +seq_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + BinaryHeap +} + +seq_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + BTreeSet +} + +seq_impl! { + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + HashSet +} + +seq_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + LinkedList +} + +seq_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + Vec +} + +seq_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + VecDeque +} + +//////////////////////////////////////////////////////////////////////////////// + +impl Serialize for Range +where + Idx: Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use super::SerializeStruct; + 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() + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl Serialize for RangeInclusive +where + Idx: Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use super::SerializeStruct; + 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() + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl Serialize for Bound +where + T: Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match *self { + Bound::Unbounded => serializer.serialize_unit_variant("Bound", 0, "Unbounded"), + Bound::Included(ref value) => { + serializer.serialize_newtype_variant("Bound", 1, "Included", value) + } + Bound::Excluded(ref value) => { + serializer.serialize_newtype_variant("Bound", 2, "Excluded", value) + } + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl Serialize for () { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_unit() + } +} + +#[cfg(feature = "unstable")] +#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] +impl Serialize for ! { + fn serialize(&self, _serializer: S) -> Result + where + S: Serializer, + { + *self + } +} + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! tuple_impls { + ($($len:expr => ($($n:tt $name:ident)+))+) => { + $( + #[cfg_attr(docsrs, doc(hidden))] + impl<$($name),+> Serialize for ($($name,)+) + where + $($name: Serialize,)+ + { + 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! { + 2 => (0 T0 1 T1) + 3 => (0 T0 1 T1 2 T2) + 4 => (0 T0 1 T1 2 T2 3 T3) + 5 => (0 T0 1 T1 2 T2 3 T3 4 T4) + 6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5) + 7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6) + 8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7) + 9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8) + 10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9) + 11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10) + 12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11) + 13 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12) + 14 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13) + 15 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14) + 16 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15) +} + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! map_impl { + ( + $(#[$attr:meta])* + $ty:ident + ) => { + $(#[$attr])* + impl Serialize for $ty + where + K: Serialize, + V: Serialize, + { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_map(self) + } + } + } +} + +map_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + BTreeMap +} + +map_impl! { + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + HashMap +} + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! deref_impl { + ( + $(#[$attr:meta])* + <$($desc:tt)+ + ) => { + $(#[$attr])* + impl <$($desc)+ { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + (**self).serialize(serializer) + } + } + }; +} + +deref_impl! { + <'a, T> Serialize for &'a T where T: ?Sized + 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 +} + +deref_impl! { + /// This impl requires the [`"rc"`] Cargo feature of Serde. + /// + /// Serializing a data structure containing `Rc` will serialize a copy of + /// the contents of the `Rc` each time the `Rc` is referenced within the + /// data structure. Serialization will not attempt to deduplicate these + /// repeated data. + /// + /// [`"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")))))] + Serialize for Rc where T: ?Sized + Serialize +} + +deref_impl! { + /// This impl requires the [`"rc"`] Cargo feature of Serde. + /// + /// Serializing a data structure containing `Arc` will serialize a copy of + /// the contents of the `Arc` each time the `Arc` is referenced within the + /// data structure. Serialization will not attempt to deduplicate these + /// repeated data. + /// + /// [`"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")))))] + Serialize for Arc where T: ?Sized + Serialize +} + +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 +} + +//////////////////////////////////////////////////////////////////////////////// + +/// This impl requires the [`"rc"`] Cargo feature of Serde. +/// +/// [`"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")))) +)] +impl Serialize for RcWeak +where + T: ?Sized + Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.upgrade().serialize(serializer) + } +} + +/// This impl requires the [`"rc"`] Cargo feature of Serde. +/// +/// [`"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")))) +)] +impl Serialize for ArcWeak +where + T: ?Sized + Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.upgrade().serialize(serializer) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! nonzero_integers { + ($($T:ident,)+) => { + $( + impl Serialize for num::$T { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.get().serialize(serializer) + } + } + )+ + } +} + +nonzero_integers! { + NonZeroI8, + NonZeroI16, + NonZeroI32, + NonZeroI64, + NonZeroI128, + NonZeroIsize, + NonZeroU8, + NonZeroU16, + NonZeroU32, + NonZeroU64, + NonZeroU128, + NonZeroUsize, +} + +impl Serialize for Cell +where + T: Serialize + Copy, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.get().serialize(serializer) + } +} + +impl Serialize for RefCell +where + T: ?Sized + Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self.try_borrow() { + Ok(value) => value.serialize(serializer), + Err(_) => Err(S::Error::custom("already mutably borrowed")), + } + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl Serialize for Mutex +where + T: ?Sized + Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self.lock() { + Ok(locked) => locked.serialize(serializer), + Err(_) => Err(S::Error::custom("lock poison error while serializing")), + } + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl Serialize for RwLock +where + T: ?Sized + Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self.read() { + Ok(locked) => locked.serialize(serializer), + Err(_) => Err(S::Error::custom("lock poison error while serializing")), + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "result")] +#[cfg_attr(docsrs, doc(cfg(feature = "result")))] +impl Serialize for Result +where + T: Serialize, + E: Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match *self { + Result::Ok(ref value) => serializer.serialize_newtype_variant("Result", 0, "Ok", value), + Result::Err(ref value) => { + serializer.serialize_newtype_variant("Result", 1, "Err", value) + } + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl Serialize for Duration { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use super::SerializeStruct; + 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() + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[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 = 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() + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// Serialize a value that implements `Display` as a string, when that string is +/// 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(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 mut writer = crate::format::Buf::new(&mut buffer); + write!(&mut writer, "{}", $value).unwrap(); + $serializer.serialize_str(writer.as_str()) + }}; +} + +#[cfg(any(feature = "std", not(no_core_net)))] +impl Serialize for net::IpAddr { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + if serializer.is_human_readable() { + match *self { + net::IpAddr::V4(ref a) => a.serialize(serializer), + net::IpAddr::V6(ref a) => a.serialize(serializer), + } + } else { + match *self { + net::IpAddr::V4(ref a) => { + serializer.serialize_newtype_variant("IpAddr", 0, "V4", a) + } + net::IpAddr::V6(ref a) => { + serializer.serialize_newtype_variant("IpAddr", 1, "V6", a) + } + } + } + } +} + +#[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 + S: Serializer, + { + if serializer.is_human_readable() { + const MAX_LEN: usize = 15; + debug_assert_eq!(MAX_LEN, "101.102.103.104".len()); + 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(any(feature = "std", not(no_core_net)))] +impl Serialize for net::Ipv6Addr { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + if serializer.is_human_readable() { + const MAX_LEN: usize = 39; + debug_assert_eq!(MAX_LEN, "1001:1002:1003:1004:1005:1006:1007:1008".len()); + serialize_display_bounded_length!(self, MAX_LEN, serializer) + } else { + self.octets().serialize(serializer) + } + } +} + +#[cfg(any(feature = "std", not(no_core_net)))] +impl Serialize for net::SocketAddr { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + if serializer.is_human_readable() { + match *self { + net::SocketAddr::V4(ref addr) => addr.serialize(serializer), + net::SocketAddr::V6(ref addr) => addr.serialize(serializer), + } + } else { + match *self { + net::SocketAddr::V4(ref addr) => { + serializer.serialize_newtype_variant("SocketAddr", 0, "V4", addr) + } + net::SocketAddr::V6(ref addr) => { + serializer.serialize_newtype_variant("SocketAddr", 1, "V6", addr) + } + } + } + } +} + +#[cfg(any(feature = "std", not(no_core_net)))] +impl Serialize for net::SocketAddrV4 { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + if serializer.is_human_readable() { + const MAX_LEN: usize = 21; + debug_assert_eq!(MAX_LEN, "101.102.103.104:65000".len()); + serialize_display_bounded_length!(self, MAX_LEN, serializer) + } else { + (self.ip(), self.port()).serialize(serializer) + } + } +} + +#[cfg(any(feature = "std", not(no_core_net)))] +impl Serialize for net::SocketAddrV6 { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + if serializer.is_human_readable() { + const MAX_LEN: usize = 58; + debug_assert_eq!( + MAX_LEN, + "[1001:1002:1003:1004:1005:1006:1007:1008%4294967295]:65000".len() + ); + serialize_display_bounded_length!(self, MAX_LEN, serializer) + } else { + (self.ip(), self.port()).serialize(serializer) + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl Serialize for Path { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self.to_str() { + Some(s) => s.serialize(serializer), + None => Err(Error::custom("path contains invalid UTF-8 characters")), + } + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl Serialize for PathBuf { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_path().serialize(serializer) + } +} + +#[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 + where + S: Serializer, + { + use std::os::unix::ffi::OsStrExt; + serializer.serialize_newtype_variant("OsString", 0, "Unix", self.as_bytes()) + } + + #[cfg(windows)] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use std::os::windows::ffi::OsStrExt; + let val = self.encode_wide().collect::>(); + serializer.serialize_newtype_variant("OsString", 1, "Windows", &val) + } +} + +#[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 + S: Serializer, + { + self.as_os_str().serialize(serializer) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl Serialize for Wrapping +where + T: Serialize, +{ + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.0.serialize(serializer) + } +} + +#[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, +{ + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.0.serialize(serializer) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(all(feature = "std", not(no_std_atomic)))] +macro_rules! atomic_impl { + ($($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, + { + // Matches the atomic ordering used in libcore for the Debug impl + self.load(Ordering::Relaxed).serialize(serializer) + } + } + )* + } +} + +#[cfg(all(feature = "std", not(no_std_atomic)))] +atomic_impl! { + 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" +} diff --git a/third_party/crates/serde-1.0.229/src/core/ser/impossible.rs b/third_party/crates/serde-1.0.229/src/core/ser/impossible.rs new file mode 100644 index 0000000..fe69ae2 --- /dev/null +++ b/third_party/crates/serde-1.0.229/src/core/ser/impossible.rs @@ -0,0 +1,216 @@ +//! This module contains `Impossible` serializer and its implementations. + +use crate::lib::*; + +use crate::ser::{ + self, Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, + SerializeTuple, SerializeTupleStruct, SerializeTupleVariant, +}; + +/// Helper type for implementing a `Serializer` that does not support +/// serializing one of the compound types. +/// +/// This type cannot be instantiated, but implements every one of the traits +/// corresponding to the [`Serializer`] compound types: [`SerializeSeq`], +/// [`SerializeTuple`], [`SerializeTupleStruct`], [`SerializeTupleVariant`], +/// [`SerializeMap`], [`SerializeStruct`], and [`SerializeStructVariant`]. +/// +/// ```edition2021 +/// # use serde::ser::{Serializer, Impossible}; +/// # use serde_core::__private::doc::Error; +/// # +/// # struct MySerializer; +/// # +/// impl Serializer for MySerializer { +/// type Ok = (); +/// type Error = Error; +/// +/// type SerializeSeq = Impossible<(), Error>; +/// /* other associated types */ +/// +/// /// This data format does not support serializing sequences. +/// fn serialize_seq(self, +/// len: Option) +/// -> Result { +/// // Given Impossible cannot be instantiated, the only +/// // thing we can do here is to return an error. +/// # stringify! { +/// Err(...) +/// # }; +/// # unimplemented!() +/// } +/// +/// /* other Serializer methods */ +/// # 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 +/// # } +/// } +/// ``` +/// +/// [`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, + error: PhantomData, +} + +enum Void {} + +impl SerializeSeq for Impossible +where + Error: ser::Error, +{ + type Ok = Ok; + type Error = Error; + + fn serialize_element(&mut self, value: &T) -> Result<(), Error> + where + T: ?Sized + Serialize, + { + let _ = value; + match self.void {} + } + + fn end(self) -> Result { + match self.void {} + } +} + +impl SerializeTuple for Impossible +where + Error: ser::Error, +{ + type Ok = Ok; + type Error = Error; + + fn serialize_element(&mut self, value: &T) -> Result<(), Error> + where + T: ?Sized + Serialize, + { + let _ = value; + match self.void {} + } + + fn end(self) -> Result { + match self.void {} + } +} + +impl SerializeTupleStruct for Impossible +where + Error: ser::Error, +{ + type Ok = Ok; + type Error = Error; + + fn serialize_field(&mut self, value: &T) -> Result<(), Error> + where + T: ?Sized + Serialize, + { + let _ = value; + match self.void {} + } + + fn end(self) -> Result { + match self.void {} + } +} + +impl SerializeTupleVariant for Impossible +where + Error: ser::Error, +{ + type Ok = Ok; + type Error = Error; + + fn serialize_field(&mut self, value: &T) -> Result<(), Error> + where + T: ?Sized + Serialize, + { + let _ = value; + match self.void {} + } + + fn end(self) -> Result { + match self.void {} + } +} + +impl SerializeMap for Impossible +where + Error: ser::Error, +{ + type Ok = Ok; + type Error = Error; + + fn serialize_key(&mut self, key: &T) -> Result<(), Error> + where + T: ?Sized + Serialize, + { + let _ = key; + match self.void {} + } + + fn serialize_value(&mut self, value: &T) -> Result<(), Error> + where + T: ?Sized + Serialize, + { + let _ = value; + match self.void {} + } + + fn end(self) -> Result { + match self.void {} + } +} + +impl SerializeStruct for Impossible +where + Error: ser::Error, +{ + type Ok = Ok; + type Error = Error; + + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> + where + T: ?Sized + Serialize, + { + let _ = key; + let _ = value; + match self.void {} + } + + fn end(self) -> Result { + match self.void {} + } +} + +impl SerializeStructVariant for Impossible +where + Error: ser::Error, +{ + type Ok = Ok; + type Error = Error; + + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> + where + T: ?Sized + Serialize, + { + let _ = key; + let _ = value; + match self.void {} + } + + fn end(self) -> Result { + match self.void {} + } +} diff --git a/third_party/crates/serde-1.0.229/src/core/ser/mod.rs b/third_party/crates/serde-1.0.229/src/core/ser/mod.rs new file mode 100644 index 0000000..62e59d9 --- /dev/null +++ b/third_party/crates/serde-1.0.229/src/core/ser/mod.rs @@ -0,0 +1,2010 @@ +//! Generic data structure serialization framework. +//! +//! The two most important traits in this module are [`Serialize`] and +//! [`Serializer`]. +//! +//! - **A type that implements `Serialize` is a data structure** that can be +//! serialized to any data format supported by Serde, and conversely +//! - **A type that implements `Serializer` is a data format** that can +//! serialize any data structure supported by Serde. +//! +//! # The Serialize trait +//! +//! Serde provides [`Serialize`] implementations for many Rust primitive and +//! standard library types. The complete list is below. 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 your program. See the [derive section of the manual] for how to use this. +//! +//! In rare cases it may be necessary to implement [`Serialize`] manually for +//! some type in your program. See the [Implementing `Serialize`] section of the +//! manual for more about this. +//! +//! Third-party crates may provide [`Serialize`] implementations for types that +//! they expose. For example the [`linked-hash-map`] crate provides a +//! [`LinkedHashMap`] type that is serializable by Serde because the crate +//! provides an implementation of [`Serialize`] for it. +//! +//! # The Serializer trait +//! +//! [`Serializer`] implementations are provided by third-party crates, for +//! example [`serde_json`], [`serde_yaml`] and [`postcard`]. +//! +//! A partial list of well-maintained formats is given on the [Serde +//! website][data formats]. +//! +//! # Implementations of Serialize provided by Serde +//! +//! - **Primitive types**: +//! - bool +//! - i8, i16, i32, i64, i128, isize +//! - u8, u16, u32, u64, u128, usize +//! - f32, f64 +//! - char +//! - str +//! - &T and &mut T +//! - **Compound types**: +//! - \[T\] +//! - \[T; 0\] through \[T; 32\] +//! - tuples up to size 16 +//! - **Common standard library types**: +//! - String +//! - Option\ +//! - Result\ +//! - PhantomData\ +//! - **Wrapper types**: +//! - Box\ +//! - Cow\<'a, T\> +//! - Cell\ +//! - RefCell\ +//! - Mutex\ +//! - RwLock\ +//! - Rc\ *(if* features = \["rc"\] *is enabled)* +//! - Arc\ *(if* features = \["rc"\] *is enabled)* +//! - **Collection types**: +//! - BTreeMap\ +//! - BTreeSet\ +//! - BinaryHeap\ +//! - HashMap\ +//! - HashSet\ +//! - LinkedList\ +//! - VecDeque\ +//! - Vec\ +//! - **FFI types**: +//! - CStr +//! - CString +//! - OsStr +//! - OsString +//! - **Miscellaneous standard library types**: +//! - Duration +//! - SystemTime +//! - Path +//! - PathBuf +//! - Range\ +//! - RangeInclusive\ +//! - Bound\ +//! - num::NonZero* +//! - `!` *(unstable)* +//! - **Net types**: +//! - IpAddr +//! - Ipv4Addr +//! - Ipv6Addr +//! - SocketAddr +//! - SocketAddrV4 +//! - SocketAddrV6 +//! +//! [Implementing `Serialize`]: https://serde.rs/impl-serialize.html +//! [`LinkedHashMap`]: https://docs.rs/linked-hash-map/*/linked_hash_map/struct.LinkedHashMap.html +//! [`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 +//! [`serde_yaml`]: https://github.com/dtolnay/serde-yaml +//! [derive section of the manual]: https://serde.rs/derive.html +//! [data formats]: https://serde.rs/#data-formats + +use crate::lib::*; + +mod fmt; +mod impls; +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; + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! declare_error_trait { + (Error: Sized $(+ $($supertrait:ident)::+)*) => { + /// Trait used by `Serialize` implementations to generically construct + /// errors belonging to the `Serializer` against which they are + /// currently running. + /// + /// # Example implementation + /// + /// The [example data format] presented on the website shows an error + /// 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. + /// + /// The message should not be capitalized and should not end with a + /// period. + /// + /// For example, a filesystem [`Path`] may refuse to serialize + /// itself if it contains invalid UTF-8 data. + /// + /// ```edition2021 + /// # struct Path; + /// # + /// # impl Path { + /// # fn to_str(&self) -> Option<&str> { + /// # unimplemented!() + /// # } + /// # } + /// # + /// use serde::ser::{self, Serialize, Serializer}; + /// + /// impl Serialize for Path { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// match self.to_str() { + /// Some(s) => serializer.serialize_str(s), + /// None => Err(ser::Error::custom("path contains invalid UTF-8 characters")), + /// } + /// } + /// } + /// ``` + /// + /// [`Path`]: std::path::Path + /// [`Serialize`]: crate::Serialize + fn custom(msg: T) -> Self + where + T: Display; + } + } +} + +#[cfg(feature = "std")] +declare_error_trait!(Error: Sized + StdError); + +#[cfg(not(feature = "std"))] +declare_error_trait!(Error: Sized + Debug + Display); + +//////////////////////////////////////////////////////////////////////////////// + +/// A **data structure** that can be serialized into any data format supported +/// by Serde. +/// +/// Serde provides `Serialize` implementations for many Rust primitive and +/// 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 +/// your program. See the [derive section of the manual] for how to use this. +/// +/// In rare cases it may be necessary to implement `Serialize` manually for some +/// type in your program. See the [Implementing `Serialize`] section of the +/// manual for more about this. +/// +/// Third-party crates may provide `Serialize` implementations for types that +/// they expose. For example the [`linked-hash-map`] crate provides a +/// [`LinkedHashMap`] type that is serializable by Serde because the crate +/// provides an implementation of `Serialize` for it. +/// +/// [Implementing `Serialize`]: https://serde.rs/impl-serialize.html +/// [`LinkedHashMap`]: https://docs.rs/linked-hash-map/*/linked_hash_map/struct.LinkedHashMap.html +/// [`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 +#[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. + /// + /// ```edition2021 + /// use serde::ser::{Serialize, SerializeStruct, Serializer}; + /// + /// struct Person { + /// name: String, + /// age: u8, + /// phones: Vec, + /// } + /// + /// // This is what #[derive(Serialize)] would generate. + /// impl Serialize for Person { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// let mut s = serializer.serialize_struct("Person", 3)?; + /// s.serialize_field("name", &self.name)?; + /// s.serialize_field("age", &self.age)?; + /// s.serialize_field("phones", &self.phones)?; + /// s.end() + /// } + /// } + /// ``` + /// + /// [Implementing `Serialize`]: https://serde.rs/impl-serialize.html + fn serialize(&self, serializer: S) -> Result + where + S: Serializer; +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A **data format** that can serialize any data structure supported by Serde. +/// +/// The role of this trait is to define the serialization half of the [Serde +/// data model], which is a way to categorize every Rust data structure into one +/// of 29 possible types. Each method of the `Serializer` trait corresponds to +/// one of the types of the data model. +/// +/// Implementations of `Serialize` map themselves into this data model by +/// invoking exactly one of the `Serializer` methods. +/// +/// The types that make up the Serde data model are: +/// +/// - **14 primitive types** +/// - bool +/// - i8, i16, i32, i64, i128 +/// - u8, u16, u32, u64, u128 +/// - f32, f64 +/// - char +/// - **string** +/// - UTF-8 bytes with a length and no null terminator. +/// - When serializing, all strings are handled equally. When deserializing, +/// there are three flavors of strings: transient, owned, and borrowed. +/// - **byte array** - \[u8\] +/// - Similar to strings, during deserialization byte arrays can be +/// transient, owned, or borrowed. +/// - **option** +/// - Either none or some value. +/// - **unit** +/// - The type of `()` in Rust. It represents an anonymous value containing +/// no data. +/// - **unit_struct** +/// - For example `struct Unit` or `PhantomData`. It represents a named +/// value containing no data. +/// - **unit_variant** +/// - For example the `E::A` and `E::B` in `enum E { A, B }`. +/// - **newtype_struct** +/// - For example `struct Millimeters(u8)`. +/// - **newtype_variant** +/// - For example the `E::N` in `enum E { N(u8) }`. +/// - **seq** +/// - A variably sized heterogeneous sequence of values, for example +/// `Vec` or `HashSet`. When serializing, the length may or may not +/// be known before iterating through all the data. When deserializing, +/// the length is determined by looking at the serialized data. +/// - **tuple** +/// - A statically sized heterogeneous sequence of values for which the +/// length will be known at deserialization time without looking at the +/// serialized data, for example `(u8,)` or `(String, u64, Vec)` or +/// `[u64; 10]`. +/// - **tuple_struct** +/// - A named tuple, for example `struct Rgb(u8, u8, u8)`. +/// - **tuple_variant** +/// - For example the `E::T` in `enum E { T(u8, u8) }`. +/// - **map** +/// - A heterogeneous key-value pairing, for example `BTreeMap`. +/// - **struct** +/// - A heterogeneous key-value pairing in which the keys are strings and +/// will be known at deserialization time without looking at the +/// serialized data, for example `struct S { r: u8, g: u8, b: u8 }`. +/// - **struct_variant** +/// - 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 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 +/// output. +/// +/// [Serde data model]: https://serde.rs/data-model.html +/// +/// # Example implementation +/// +/// The [example data format] presented on the website contains example code for +/// 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 + /// should set `Ok = ()` and serialize into an [`io::Write`] or buffer + /// contained within the `Serializer` instance. Serializers that build + /// in-memory data structures may be simplified by using `Ok` to propagate + /// the data structure around. + /// + /// [`io::Write`]: std::io::Write + type Ok; + + /// The error type when some error occurs during serialization. + type Error: Error; + + /// Type returned from [`serialize_seq`] for serializing the content of the + /// sequence. + /// + /// [`serialize_seq`]: #tymethod.serialize_seq + type SerializeSeq: SerializeSeq; + + /// Type returned from [`serialize_tuple`] for serializing the content of + /// the tuple. + /// + /// [`serialize_tuple`]: #tymethod.serialize_tuple + type SerializeTuple: SerializeTuple; + + /// Type returned from [`serialize_tuple_struct`] for serializing the + /// content of the tuple struct. + /// + /// [`serialize_tuple_struct`]: #tymethod.serialize_tuple_struct + type SerializeTupleStruct: SerializeTupleStruct; + + /// Type returned from [`serialize_tuple_variant`] for serializing the + /// content of the tuple variant. + /// + /// [`serialize_tuple_variant`]: #tymethod.serialize_tuple_variant + type SerializeTupleVariant: SerializeTupleVariant; + + /// Type returned from [`serialize_map`] for serializing the content of the + /// map. + /// + /// [`serialize_map`]: #tymethod.serialize_map + type SerializeMap: SerializeMap; + + /// Type returned from [`serialize_struct`] for serializing the content of + /// the struct. + /// + /// [`serialize_struct`]: #tymethod.serialize_struct + type SerializeStruct: SerializeStruct; + + /// Type returned from [`serialize_struct_variant`] for serializing the + /// content of the struct variant. + /// + /// [`serialize_struct_variant`]: #tymethod.serialize_struct_variant + type SerializeStructVariant: SerializeStructVariant; + + /// Serialize a `bool` value. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for bool { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_bool(*self) + /// } + /// } + /// ``` + fn serialize_bool(self, v: bool) -> Result; + + /// Serialize an `i8` value. + /// + /// If the format does not differentiate between `i8` and `i64`, a + /// reasonable implementation would be to cast the value to `i64` and + /// forward to `serialize_i64`. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for i8 { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_i8(*self) + /// } + /// } + /// ``` + fn serialize_i8(self, v: i8) -> Result; + + /// Serialize an `i16` value. + /// + /// If the format does not differentiate between `i16` and `i64`, a + /// reasonable implementation would be to cast the value to `i64` and + /// forward to `serialize_i64`. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for i16 { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_i16(*self) + /// } + /// } + /// ``` + fn serialize_i16(self, v: i16) -> Result; + + /// Serialize an `i32` value. + /// + /// If the format does not differentiate between `i32` and `i64`, a + /// reasonable implementation would be to cast the value to `i64` and + /// forward to `serialize_i64`. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for i32 { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_i32(*self) + /// } + /// } + /// ``` + fn serialize_i32(self, v: i32) -> Result; + + /// Serialize an `i64` value. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for i64 { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_i64(*self) + /// } + /// } + /// ``` + fn serialize_i64(self, v: i64) -> Result; + + /// 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. + /// + /// If the format does not differentiate between `u8` and `u64`, a + /// reasonable implementation would be to cast the value to `u64` and + /// forward to `serialize_u64`. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for u8 { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_u8(*self) + /// } + /// } + /// ``` + fn serialize_u8(self, v: u8) -> Result; + + /// Serialize a `u16` value. + /// + /// If the format does not differentiate between `u16` and `u64`, a + /// reasonable implementation would be to cast the value to `u64` and + /// forward to `serialize_u64`. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for u16 { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_u16(*self) + /// } + /// } + /// ``` + fn serialize_u16(self, v: u16) -> Result; + + /// Serialize a `u32` value. + /// + /// If the format does not differentiate between `u32` and `u64`, a + /// reasonable implementation would be to cast the value to `u64` and + /// forward to `serialize_u64`. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for u32 { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_u32(*self) + /// } + /// } + /// ``` + fn serialize_u32(self, v: u32) -> Result; + + /// Serialize a `u64` value. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for u64 { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_u64(*self) + /// } + /// } + /// ``` + fn serialize_u64(self, v: u64) -> Result; + + /// 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. + /// + /// If the format does not differentiate between `f32` and `f64`, a + /// reasonable implementation would be to cast the value to `f64` and + /// forward to `serialize_f64`. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for f32 { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_f32(*self) + /// } + /// } + /// ``` + fn serialize_f32(self, v: f32) -> Result; + + /// Serialize an `f64` value. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for f64 { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_f64(*self) + /// } + /// } + /// ``` + fn serialize_f64(self, v: f64) -> Result; + + /// Serialize a character. + /// + /// If the format does not support characters, it is reasonable to serialize + /// it as a single element `str` or a `u32`. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for char { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_char(*self) + /// } + /// } + /// ``` + fn serialize_char(self, v: char) -> Result; + + /// Serialize a `&str`. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for str { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_str(self) + /// } + /// } + /// ``` + fn serialize_str(self, v: &str) -> Result; + + /// Serialize a chunk of raw byte data. + /// + /// Enables serializers to serialize byte slices more compactly or more + /// efficiently than other types of slices. If no efficient implementation + /// is available, a reasonable implementation would be to forward to + /// `serialize_seq`. If forwarded, the implementation looks usually just + /// like this: + /// + /// ```edition2021 + /// # use serde::ser::{Serializer, SerializeSeq}; + /// # use serde_core::__private::doc::Error; + /// # + /// # struct MySerializer; + /// # + /// # impl Serializer for MySerializer { + /// # type Ok = (); + /// # type Error = Error; + /// # + /// fn serialize_bytes(self, v: &[u8]) -> Result { + /// let mut seq = self.serialize_seq(Some(v.len()))?; + /// for b in v { + /// seq.serialize_element(b)?; + /// } + /// seq.end() + /// } + /// # + /// # 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 + /// # } + /// # } + /// ``` + fn serialize_bytes(self, v: &[u8]) -> Result; + + /// Serialize a [`None`] value. + /// + /// ```edition2021 + /// # use serde::{Serialize, Serializer}; + /// # + /// # enum Option { + /// # Some(T), + /// # None, + /// # } + /// # + /// # use self::Option::{Some, None}; + /// # + /// impl Serialize for Option + /// where + /// T: Serialize, + /// { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// match *self { + /// Some(ref value) => serializer.serialize_some(value), + /// None => serializer.serialize_none(), + /// } + /// } + /// } + /// # + /// # fn main() {} + /// ``` + /// + /// [`None`]: core::option::Option::None + fn serialize_none(self) -> Result; + + /// Serialize a [`Some(T)`] value. + /// + /// ```edition2021 + /// # use serde::{Serialize, Serializer}; + /// # + /// # enum Option { + /// # Some(T), + /// # None, + /// # } + /// # + /// # use self::Option::{Some, None}; + /// # + /// impl Serialize for Option + /// where + /// T: Serialize, + /// { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// match *self { + /// Some(ref value) => serializer.serialize_some(value), + /// None => serializer.serialize_none(), + /// } + /// } + /// } + /// # + /// # fn main() {} + /// ``` + /// + /// [`Some(T)`]: core::option::Option::Some + fn serialize_some(self, value: &T) -> Result + where + T: ?Sized + Serialize; + + /// Serialize a `()` value. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for () { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_unit() + /// } + /// } + /// ``` + fn serialize_unit(self) -> Result; + + /// Serialize a unit struct like `struct Unit` or `PhantomData`. + /// + /// A reasonable implementation would be to forward to `serialize_unit`. + /// + /// ```edition2021 + /// use serde::{Serialize, Serializer}; + /// + /// struct Nothing; + /// + /// impl Serialize for Nothing { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_unit_struct("Nothing") + /// } + /// } + /// ``` + fn serialize_unit_struct(self, name: &'static str) -> Result; + + /// Serialize a unit variant like `E::A` in `enum E { A, B }`. + /// + /// The `name` is the name of the enum, the `variant_index` is the index of + /// this variant within the enum, and the `variant` is the name of the + /// variant. + /// + /// ```edition2021 + /// use serde::{Serialize, Serializer}; + /// + /// enum E { + /// A, + /// B, + /// } + /// + /// impl Serialize for E { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// match *self { + /// E::A => serializer.serialize_unit_variant("E", 0, "A"), + /// E::B => serializer.serialize_unit_variant("E", 1, "B"), + /// } + /// } + /// } + /// ``` + fn serialize_unit_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + ) -> Result; + + /// Serialize a newtype struct like `struct Millimeters(u8)`. + /// + /// Serializers are encouraged to treat newtype structs as insignificant + /// wrappers around the data they contain. A reasonable implementation would + /// be to forward to `value.serialize(self)`. + /// + /// ```edition2021 + /// use serde::{Serialize, Serializer}; + /// + /// struct Millimeters(u8); + /// + /// impl Serialize for Millimeters { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_newtype_struct("Millimeters", &self.0) + /// } + /// } + /// ``` + fn serialize_newtype_struct( + self, + name: &'static str, + value: &T, + ) -> Result + where + T: ?Sized + Serialize; + + /// Serialize a newtype variant like `E::N` in `enum E { N(u8) }`. + /// + /// The `name` is the name of the enum, the `variant_index` is the index of + /// this variant within the enum, and the `variant` is the name of the + /// variant. The `value` is the data contained within this newtype variant. + /// + /// ```edition2021 + /// use serde::{Serialize, Serializer}; + /// + /// enum E { + /// M(String), + /// N(u8), + /// } + /// + /// impl Serialize for E { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// match *self { + /// E::M(ref s) => serializer.serialize_newtype_variant("E", 0, "M", s), + /// E::N(n) => serializer.serialize_newtype_variant("E", 1, "N", &n), + /// } + /// } + /// } + /// ``` + fn serialize_newtype_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result + where + 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 + /// `end`. + /// + /// The argument is the number of elements in the sequence, which may or may + /// not be computable before the sequence is iterated. Some serializers only + /// support sequences whose length is known up front. + /// + /// ```edition2021 + /// # use std::marker::PhantomData; + /// # + /// # struct Vec(PhantomData); + /// # + /// # impl Vec { + /// # fn len(&self) -> usize { + /// # unimplemented!() + /// # } + /// # } + /// # + /// # impl<'a, T> IntoIterator for &'a Vec { + /// # type Item = &'a T; + /// # type IntoIter = Box>; + /// # + /// # fn into_iter(self) -> Self::IntoIter { + /// # unimplemented!() + /// # } + /// # } + /// # + /// use serde::ser::{Serialize, SerializeSeq, Serializer}; + /// + /// impl Serialize for Vec + /// where + /// T: Serialize, + /// { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// let mut seq = serializer.serialize_seq(Some(self.len()))?; + /// for element in self { + /// seq.serialize_element(element)?; + /// } + /// seq.end() + /// } + /// } + /// ``` + fn serialize_seq(self, len: Option) -> Result; + + /// Begin to serialize a statically sized sequence whose length will be + /// known at deserialization time without looking at the serialized data. + /// This call must be followed by zero or more calls to `serialize_element`, + /// then a call to `end`. + /// + /// ```edition2021 + /// use serde::ser::{Serialize, SerializeTuple, Serializer}; + /// + /// # mod fool { + /// # trait Serialize {} + /// impl Serialize for (A, B, C) + /// # {} + /// # } + /// # + /// # struct Tuple3(A, B, C); + /// # + /// # impl Serialize for Tuple3 + /// where + /// A: Serialize, + /// B: Serialize, + /// C: Serialize, + /// { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// let mut tup = serializer.serialize_tuple(3)?; + /// tup.serialize_element(&self.0)?; + /// tup.serialize_element(&self.1)?; + /// tup.serialize_element(&self.2)?; + /// tup.end() + /// } + /// } + /// ``` + /// + /// ```edition2021 + /// use serde::ser::{Serialize, SerializeTuple, Serializer}; + /// + /// const VRAM_SIZE: usize = 386; + /// struct Vram([u16; VRAM_SIZE]); + /// + /// impl Serialize for Vram { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// let mut seq = serializer.serialize_tuple(VRAM_SIZE)?; + /// for element in &self.0[..] { + /// seq.serialize_element(element)?; + /// } + /// seq.end() + /// } + /// } + /// ``` + fn serialize_tuple(self, len: usize) -> Result; + + /// Begin to serialize a tuple struct like `struct Rgb(u8, u8, u8)`. This + /// call must be followed by zero or more calls to `serialize_field`, then a + /// call to `end`. + /// + /// The `name` is the name of the tuple struct and the `len` is the number + /// of data fields that will be serialized. + /// + /// ```edition2021 + /// use serde::ser::{Serialize, SerializeTupleStruct, Serializer}; + /// + /// struct Rgb(u8, u8, u8); + /// + /// impl Serialize for Rgb { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// let mut ts = serializer.serialize_tuple_struct("Rgb", 3)?; + /// ts.serialize_field(&self.0)?; + /// ts.serialize_field(&self.1)?; + /// ts.serialize_field(&self.2)?; + /// ts.end() + /// } + /// } + /// ``` + fn serialize_tuple_struct( + self, + name: &'static str, + len: usize, + ) -> Result; + + /// Begin to serialize a tuple variant like `E::T` in `enum E { T(u8, u8) + /// }`. This call must be followed by zero or more calls to + /// `serialize_field`, then a call to `end`. + /// + /// 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. + /// + /// ```edition2021 + /// use serde::ser::{Serialize, SerializeTupleVariant, Serializer}; + /// + /// enum E { + /// T(u8, u8), + /// U(String, u32, u32), + /// } + /// + /// impl Serialize for E { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// match *self { + /// E::T(ref a, ref b) => { + /// let mut tv = serializer.serialize_tuple_variant("E", 0, "T", 2)?; + /// tv.serialize_field(a)?; + /// tv.serialize_field(b)?; + /// tv.end() + /// } + /// E::U(ref a, ref b, ref c) => { + /// let mut tv = serializer.serialize_tuple_variant("E", 1, "U", 3)?; + /// tv.serialize_field(a)?; + /// tv.serialize_field(b)?; + /// tv.serialize_field(c)?; + /// tv.end() + /// } + /// } + /// } + /// } + /// ``` + fn serialize_tuple_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result; + + /// Begin to serialize a map. This call must be followed by zero or more + /// calls to `serialize_key` and `serialize_value`, then a call to `end`. + /// + /// The argument is the number of elements in the map, which may or may not + /// be computable before the map is iterated. Some serializers only support + /// maps whose length is known up front. + /// + /// ```edition2021 + /// # use std::marker::PhantomData; + /// # + /// # struct HashMap(PhantomData, PhantomData); + /// # + /// # impl HashMap { + /// # fn len(&self) -> usize { + /// # unimplemented!() + /// # } + /// # } + /// # + /// # impl<'a, K, V> IntoIterator for &'a HashMap { + /// # type Item = (&'a K, &'a V); + /// # type IntoIter = Box>; + /// # + /// # fn into_iter(self) -> Self::IntoIter { + /// # unimplemented!() + /// # } + /// # } + /// # + /// use serde::ser::{Serialize, SerializeMap, Serializer}; + /// + /// impl Serialize for HashMap + /// where + /// K: Serialize, + /// V: Serialize, + /// { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// let mut map = serializer.serialize_map(Some(self.len()))?; + /// for (k, v) in self { + /// map.serialize_entry(k, v)?; + /// } + /// map.end() + /// } + /// } + /// ``` + fn serialize_map(self, len: Option) -> Result; + + /// Begin to serialize a struct like `struct Rgb { r: u8, g: u8, b: u8 }`. + /// This call must be followed by zero or more calls to `serialize_field`, + /// 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. `len` does not include fields + /// which are skipped with [`SerializeStruct::skip_field`]. + /// + /// ```edition2021 + /// use serde::ser::{Serialize, SerializeStruct, Serializer}; + /// + /// struct Rgb { + /// r: u8, + /// g: u8, + /// b: u8, + /// } + /// + /// impl Serialize for Rgb { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// let mut rgb = serializer.serialize_struct("Rgb", 3)?; + /// rgb.serialize_field("r", &self.r)?; + /// rgb.serialize_field("g", &self.g)?; + /// rgb.serialize_field("b", &self.b)?; + /// rgb.end() + /// } + /// } + /// ``` + fn serialize_struct( + self, + name: &'static str, + len: usize, + ) -> Result; + + /// Begin to serialize a struct variant like `E::S` in `enum E { S { r: u8, + /// g: u8, b: u8 } }`. This call must be followed by zero or more calls to + /// `serialize_field`, then a call to `end`. + /// + /// 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`]. + /// + /// ```edition2021 + /// use serde::ser::{Serialize, SerializeStructVariant, Serializer}; + /// + /// enum E { + /// S { r: u8, g: u8, b: u8 }, + /// } + /// + /// impl Serialize for E { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// match *self { + /// E::S { + /// ref r, + /// ref g, + /// ref b, + /// } => { + /// let mut sv = serializer.serialize_struct_variant("E", 0, "S", 3)?; + /// sv.serialize_field("r", r)?; + /// sv.serialize_field("g", g)?; + /// sv.serialize_field("b", b)?; + /// sv.end() + /// } + /// } + /// } + /// } + /// ``` + fn serialize_struct_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result; + + /// Collect an iterator as a sequence. + /// + /// The default implementation serializes each item yielded by the iterator + /// using [`serialize_seq`]. Implementors should not need to override this + /// method. + /// + /// ```edition2021 + /// use serde::{Serialize, Serializer}; + /// + /// struct SecretlyOneHigher { + /// data: Vec, + /// } + /// + /// impl Serialize for SecretlyOneHigher { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.collect_seq(self.data.iter().map(|x| x + 1)) + /// } + /// } + /// ``` + /// + /// [`serialize_seq`]: #tymethod.serialize_seq + fn collect_seq(self, iter: I) -> Result + where + I: IntoIterator, + ::Item: Serialize, + { + 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() + } + + /// Collect an iterator as a map. + /// + /// The default implementation serializes each pair yielded by the iterator + /// using [`serialize_map`]. Implementors should not need to override this + /// method. + /// + /// ```edition2021 + /// use serde::{Serialize, Serializer}; + /// use std::collections::BTreeSet; + /// + /// struct MapToUnit { + /// keys: BTreeSet, + /// } + /// + /// // Serializes as a map in which the values are all unit. + /// impl Serialize for MapToUnit { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.collect_map(self.keys.iter().map(|k| (k, ()))) + /// } + /// } + /// ``` + /// + /// [`serialize_map`]: #tymethod.serialize_map + fn collect_map(self, iter: I) -> Result + where + K: Serialize, + V: Serialize, + I: IntoIterator, + { + 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() + } + + /// Serialize a string produced by an implementation of `Display`. + /// + /// The default implementation builds a heap-allocated [`String`] and + /// delegates to [`serialize_str`]. Serializers are encouraged to provide a + /// more efficient implementation if possible. + /// + /// ```edition2021 + /// # struct DateTime; + /// # + /// # impl DateTime { + /// # fn naive_local(&self) -> () { () } + /// # fn offset(&self) -> () { () } + /// # } + /// # + /// use serde::{Serialize, Serializer}; + /// + /// impl Serialize for DateTime { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.collect_str(&format_args!("{:?}{:?}", self.naive_local(), self.offset())) + /// } + /// } + /// ``` + /// + /// [`serialize_str`]: Self::serialize_str + #[cfg(any(feature = "std", feature = "alloc"))] + fn collect_str(self, value: &T) -> Result + where + T: ?Sized + Display, + { + self.serialize_str(&value.to_string()) + } + + /// Serialize a string produced by an implementation of `Display`. + /// + /// Serializers that use `no_std` are required to provide an implementation + /// of this method. If no more sensible behavior is possible, the + /// implementation is expected to return an error. + /// + /// ```edition2021 + /// # struct DateTime; + /// # + /// # impl DateTime { + /// # fn naive_local(&self) -> () { () } + /// # fn offset(&self) -> () { () } + /// # } + /// # + /// use serde::{Serialize, Serializer}; + /// + /// impl Serialize for DateTime { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.collect_str(&format_args!("{:?}{:?}", self.naive_local(), self.offset())) + /// } + /// } + /// ``` + #[cfg(not(any(feature = "std", feature = "alloc")))] + fn collect_str(self, value: &T) -> Result + where + T: ?Sized + Display; + + /// Determine whether `Serialize` implementations should serialize in + /// human-readable form. + /// + /// 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 Postcard will prefer the + /// compact one. + /// + /// ```edition2021 + /// # use std::fmt::{self, Display}; + /// # + /// # struct Timestamp; + /// # + /// # impl Timestamp { + /// # fn seconds_since_epoch(&self) -> u64 { unimplemented!() } + /// # } + /// # + /// # impl Display for Timestamp { + /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// # unimplemented!() + /// # } + /// # } + /// # + /// use serde::{Serialize, Serializer}; + /// + /// impl Serialize for Timestamp { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// if serializer.is_human_readable() { + /// // Serialize to a human-readable string "2015-05-15T17:01:00Z". + /// self.to_string().serialize(serializer) + /// } else { + /// // Serialize to a compact binary representation. + /// self.seconds_since_epoch().serialize(serializer) + /// } + /// } + /// } + /// ``` + /// + /// The default implementation of this method returns `true`. Data formats + /// may override this to `false` to request a compact form for types that + /// support one. Note that modifying this method to change a format from + /// human-readable to compact or vice versa should be regarded as a breaking + /// change, as a value serialized in human-readable mode is not required to + /// deserialize from the same data in compact mode. + #[inline] + fn is_human_readable(&self) -> bool { + true + } +} + +/// Returned from `Serializer::serialize_seq`. +/// +/// # Example use +/// +/// ```edition2021 +/// # use std::marker::PhantomData; +/// # +/// # struct Vec(PhantomData); +/// # +/// # impl Vec { +/// # fn len(&self) -> usize { +/// # unimplemented!() +/// # } +/// # } +/// # +/// # impl<'a, T> IntoIterator for &'a Vec { +/// # type Item = &'a T; +/// # type IntoIter = Box>; +/// # fn into_iter(self) -> Self::IntoIter { +/// # unimplemented!() +/// # } +/// # } +/// # +/// use serde::ser::{Serialize, SerializeSeq, Serializer}; +/// +/// impl Serialize for Vec +/// where +/// T: Serialize, +/// { +/// fn serialize(&self, serializer: S) -> Result +/// where +/// S: Serializer, +/// { +/// let mut seq = serializer.serialize_seq(Some(self.len()))?; +/// for element in self { +/// seq.serialize_element(element)?; +/// } +/// seq.end() +/// } +/// } +/// ``` +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// 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; + + /// Must match the `Error` type of our `Serializer`. + type Error: Error; + + /// Serialize a sequence element. + fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> + where + T: ?Sized + Serialize; + + /// Finish serializing a sequence. + fn end(self) -> Result; +} + +/// Returned from `Serializer::serialize_tuple`. +/// +/// # Example use +/// +/// ```edition2021 +/// use serde::ser::{Serialize, SerializeTuple, Serializer}; +/// +/// # mod fool { +/// # trait Serialize {} +/// impl Serialize for (A, B, C) +/// # {} +/// # } +/// # +/// # struct Tuple3(A, B, C); +/// # +/// # impl Serialize for Tuple3 +/// where +/// A: Serialize, +/// B: Serialize, +/// C: Serialize, +/// { +/// fn serialize(&self, serializer: S) -> Result +/// where +/// S: Serializer, +/// { +/// let mut tup = serializer.serialize_tuple(3)?; +/// tup.serialize_element(&self.0)?; +/// tup.serialize_element(&self.1)?; +/// tup.serialize_element(&self.2)?; +/// tup.end() +/// } +/// } +/// ``` +/// +/// ```edition2021 +/// # use std::marker::PhantomData; +/// # +/// # struct Array(PhantomData); +/// # +/// # impl Array { +/// # fn len(&self) -> usize { +/// # unimplemented!() +/// # } +/// # } +/// # +/// # impl<'a, T> IntoIterator for &'a Array { +/// # type Item = &'a T; +/// # type IntoIter = Box>; +/// # fn into_iter(self) -> Self::IntoIter { +/// # unimplemented!() +/// # } +/// # } +/// # +/// use serde::ser::{Serialize, SerializeTuple, Serializer}; +/// +/// # mod fool { +/// # trait Serialize {} +/// impl Serialize for [T; 16] +/// # {} +/// # } +/// # +/// # impl Serialize for Array +/// where +/// T: Serialize, +/// { +/// fn serialize(&self, serializer: S) -> Result +/// where +/// S: Serializer, +/// { +/// let mut seq = serializer.serialize_tuple(16)?; +/// for element in self { +/// seq.serialize_element(element)?; +/// } +/// seq.end() +/// } +/// } +/// ``` +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// 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; + + /// Must match the `Error` type of our `Serializer`. + type Error: Error; + + /// Serialize a tuple element. + fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> + where + T: ?Sized + Serialize; + + /// Finish serializing a tuple. + fn end(self) -> Result; +} + +/// Returned from `Serializer::serialize_tuple_struct`. +/// +/// # Example use +/// +/// ```edition2021 +/// use serde::ser::{Serialize, SerializeTupleStruct, Serializer}; +/// +/// struct Rgb(u8, u8, u8); +/// +/// impl Serialize for Rgb { +/// fn serialize(&self, serializer: S) -> Result +/// where +/// S: Serializer, +/// { +/// let mut ts = serializer.serialize_tuple_struct("Rgb", 3)?; +/// ts.serialize_field(&self.0)?; +/// ts.serialize_field(&self.1)?; +/// ts.serialize_field(&self.2)?; +/// ts.end() +/// } +/// } +/// ``` +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// 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; + + /// Must match the `Error` type of our `Serializer`. + type Error: Error; + + /// Serialize a tuple struct field. + fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> + where + T: ?Sized + Serialize; + + /// Finish serializing a tuple struct. + fn end(self) -> Result; +} + +/// Returned from `Serializer::serialize_tuple_variant`. +/// +/// # Example use +/// +/// ```edition2021 +/// use serde::ser::{Serialize, SerializeTupleVariant, Serializer}; +/// +/// enum E { +/// T(u8, u8), +/// U(String, u32, u32), +/// } +/// +/// impl Serialize for E { +/// fn serialize(&self, serializer: S) -> Result +/// where +/// S: Serializer, +/// { +/// match *self { +/// E::T(ref a, ref b) => { +/// let mut tv = serializer.serialize_tuple_variant("E", 0, "T", 2)?; +/// tv.serialize_field(a)?; +/// tv.serialize_field(b)?; +/// tv.end() +/// } +/// E::U(ref a, ref b, ref c) => { +/// let mut tv = serializer.serialize_tuple_variant("E", 1, "U", 3)?; +/// tv.serialize_field(a)?; +/// tv.serialize_field(b)?; +/// tv.serialize_field(c)?; +/// tv.end() +/// } +/// } +/// } +/// } +/// ``` +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// 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; + + /// Must match the `Error` type of our `Serializer`. + type Error: Error; + + /// Serialize a tuple variant field. + fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> + where + T: ?Sized + Serialize; + + /// Finish serializing a tuple variant. + fn end(self) -> Result; +} + +/// Returned from `Serializer::serialize_map`. +/// +/// # Example use +/// +/// ```edition2021 +/// # use std::marker::PhantomData; +/// # +/// # struct HashMap(PhantomData, PhantomData); +/// # +/// # impl HashMap { +/// # fn len(&self) -> usize { +/// # unimplemented!() +/// # } +/// # } +/// # +/// # impl<'a, K, V> IntoIterator for &'a HashMap { +/// # type Item = (&'a K, &'a V); +/// # type IntoIter = Box>; +/// # +/// # fn into_iter(self) -> Self::IntoIter { +/// # unimplemented!() +/// # } +/// # } +/// # +/// use serde::ser::{Serialize, SerializeMap, Serializer}; +/// +/// impl Serialize for HashMap +/// where +/// K: Serialize, +/// V: Serialize, +/// { +/// fn serialize(&self, serializer: S) -> Result +/// where +/// S: Serializer, +/// { +/// let mut map = serializer.serialize_map(Some(self.len()))?; +/// for (k, v) in self { +/// map.serialize_entry(k, v)?; +/// } +/// map.end() +/// } +/// } +/// ``` +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// 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; + + /// Must match the `Error` type of our `Serializer`. + type Error: Error; + + /// Serialize a map key. + /// + /// If possible, `Serialize` implementations are encouraged to use + /// `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> + where + T: ?Sized + Serialize; + + /// Serialize a map value. + /// + /// # Panics + /// + /// 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> + where + T: ?Sized + Serialize; + + /// Serialize a map entry consisting of a key and a value. + /// + /// Some [`Serialize`] types are not able to hold a key and value in memory + /// at the same time so `SerializeMap` implementations are required to + /// support [`serialize_key`] and [`serialize_value`] individually. The + /// `serialize_entry` method allows serializers to optimize for the case + /// where key and value are both available. [`Serialize`] implementations + /// are encouraged to use `serialize_entry` if possible. + /// + /// The default implementation delegates to [`serialize_key`] and + /// [`serialize_value`]. This is appropriate for serializers that do not + /// care about performance or are not able to optimize `serialize_entry` any + /// better than this. + /// + /// [`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: ?Sized + Serialize, + V: ?Sized + Serialize, + { + tri!(self.serialize_key(key)); + self.serialize_value(value) + } + + /// Finish serializing a map. + fn end(self) -> Result; +} + +/// Returned from `Serializer::serialize_struct`. +/// +/// # Example use +/// +/// ```edition2021 +/// use serde::ser::{Serialize, SerializeStruct, Serializer}; +/// +/// struct Rgb { +/// r: u8, +/// g: u8, +/// b: u8, +/// } +/// +/// impl Serialize for Rgb { +/// fn serialize(&self, serializer: S) -> Result +/// where +/// S: Serializer, +/// { +/// let mut rgb = serializer.serialize_struct("Rgb", 3)?; +/// rgb.serialize_field("r", &self.r)?; +/// rgb.serialize_field("g", &self.g)?; +/// rgb.serialize_field("b", &self.b)?; +/// rgb.end() +/// } +/// } +/// ``` +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// 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; + + /// Must match the `Error` type of our `Serializer`. + type Error: Error; + + /// Serialize a struct field. + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> + where + 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; + Ok(()) + } + + /// Finish serializing a struct. + fn end(self) -> Result; +} + +/// Returned from `Serializer::serialize_struct_variant`. +/// +/// # Example use +/// +/// ```edition2021 +/// use serde::ser::{Serialize, SerializeStructVariant, Serializer}; +/// +/// enum E { +/// S { r: u8, g: u8, b: u8 }, +/// } +/// +/// impl Serialize for E { +/// fn serialize(&self, serializer: S) -> Result +/// where +/// S: Serializer, +/// { +/// match *self { +/// E::S { +/// ref r, +/// ref g, +/// ref b, +/// } => { +/// let mut sv = serializer.serialize_struct_variant("E", 0, "S", 3)?; +/// sv.serialize_field("r", r)?; +/// sv.serialize_field("g", g)?; +/// sv.serialize_field("b", b)?; +/// sv.end() +/// } +/// } +/// } +/// } +/// ``` +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// 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; + + /// Must match the `Error` type of our `Serializer`. + type Error: Error; + + /// Serialize a struct variant field. + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> + where + 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; + Ok(()) + } + + /// Finish serializing a struct variant. + fn end(self) -> Result; +} + +fn iterator_len_hint(iter: &I) -> Option +where + I: Iterator, +{ + match iter.size_hint() { + (lo, Some(hi)) if lo == hi => Some(lo), + _ => None, + } +} diff --git a/third_party/crates/serde-1.0.229/src/core/std_error.rs b/third_party/crates/serde-1.0.229/src/core/std_error.rs new file mode 100644 index 0000000..e026ace --- /dev/null +++ b/third_party/crates/serde-1.0.229/src/core/std_error.rs @@ -0,0 +1,48 @@ +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. +/// +/// Serde's error traits [`serde::ser::Error`] and [`serde::de::Error`] require +/// [`std::error::Error`] as a supertrait, but only when Serde is built with +/// "std" enabled. Data formats that don't care about no\_std support should +/// generally provide their error types with a `std::error::Error` impl +/// directly: +/// +/// ```edition2021 +/// #[derive(Debug)] +/// struct MySerError {...} +/// +/// impl serde::ser::Error for MySerError {...} +/// +/// impl std::fmt::Display for MySerError {...} +/// +/// // We don't support no_std! +/// impl std::error::Error for MySerError {} +/// ``` +/// +/// Data formats that *do* support no\_std may either have a "std" feature of +/// their own: +/// +/// ```toml +/// [features] +/// std = ["serde/std"] +/// ``` +/// +/// ```edition2021 +/// #[cfg(feature = "std")] +/// impl std::error::Error for MySerError {} +/// ``` +/// +/// ... or else provide the std Error impl unconditionally via Serde's +/// re-export: +/// +/// ```edition2021 +/// impl serde::ser::StdError for MySerError {} +/// ``` +pub trait Error: Debug + Display { + /// The underlying cause of this error, if any. + fn source(&self) -> Option<&(dyn Error + 'static)> { + None + } +} diff --git a/third_party/crates/serde-1.0.229/src/integer128.rs b/third_party/crates/serde-1.0.229/src/integer128.rs new file mode 100644 index 0000000..c9ff9d6 --- /dev/null +++ b/third_party/crates/serde-1.0.229/src/integer128.rs @@ -0,0 +1,14 @@ +#[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)* + }; +} diff --git a/third_party/crates/serde-1.0.229/src/lib.rs b/third_party/crates/serde-1.0.229/src/lib.rs new file mode 100644 index 0000000..b5c71a4 --- /dev/null +++ b/third_party/crates/serde-1.0.229/src/lib.rs @@ -0,0 +1,285 @@ +//! # Serde +//! +//! Serde is a framework for ***ser***ializing and ***de***serializing Rust data +//! structures efficiently and generically. +//! +//! The Serde ecosystem consists of data structures that know how to serialize +//! and deserialize themselves along with data formats that know how to +//! serialize and deserialize other things. Serde provides the layer by which +//! 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 for additional documentation and +//! usage examples. +//! +//! ## Design +//! +//! Where many other languages rely on runtime reflection for serializing data, +//! Serde is instead built on Rust's powerful trait system. A data structure +//! that knows how to serialize and deserialize itself is one that implements +//! Serde's `Serialize` and `Deserialize` traits (or uses Serde's derive +//! attribute to automatically generate implementations at compile time). This +//! avoids any overhead of reflection or runtime type information. In fact in +//! many situations the interaction between data structure and data format can +//! be completely optimized away by the Rust compiler, leaving Serde +//! serialization to perform the same speed as a handwritten serializer for the +//! specific selection of data structure and data format. +//! +//! ## Data formats +//! +//! The following is a partial list of data formats that have been implemented +//! for Serde by the community. +//! +//! - [JSON], the ubiquitous JavaScript Object Notation used by many HTTP APIs. +//! - [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 +//! markup language. +//! - [MessagePack], an efficient binary format that resembles a compact JSON. +//! - [TOML], a minimal configuration format used by [Cargo]. +//! - [Pickle], a format common in the Python world. +//! - [RON], a Rusty Object Notation. +//! - [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. +//! - [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 +//! Rust structs. *(deserialization only)* +//! - [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. +//! - [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 +//! [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://docs.rs/toml +//! [Pickle]: https://github.com/birkenfeld/serde-pickle +//! [RON]: https://github.com/ron-rs/ron +//! [BSON]: https://github.com/mongodb/bson-rust +//! [Avro]: https://docs.rs/apache-avro +//! [JSON5]: https://github.com/callum-oakley/json5-rs +//! [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]: 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.229")] +// 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(all(feature = "unstable", docsrs), feature(never_type))] +#![allow( + unknown_lints, + bare_trait_objects, + deprecated, + mismatched_lifetime_syntaxes +)] +// 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; + +// 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(docsrs)] +#[macro_use] +#[path = "core/macros.rs"] +mod macros; + +#[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::*; + } + + pub use self::core::{f32, f64}; + pub use self::core::{ptr, str}; + + #[cfg(any(feature = "std", feature = "alloc"))] + pub use self::core::slice; + + 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 = "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; + } + + // 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), + } + }; + } + + //////////////////////////////////////////////////////////////////////////////// + + pub use serde_core::{ + de, forward_to_deserialize_any, ser, Deserialize, Deserializer, Serialize, Serializer, + }; + + // Used by generated code and doc tests. Not public API. + #[doc(hidden)] + mod private; + + include!(concat!(env!("OUT_DIR"), "/private.rs")); + }; +} + +crate_root!(); + +mod integer128; + +// 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")] +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)] +macro_rules! __require_serde_not_serde_core { + () => {}; +} diff --git a/third_party/crates/serde-1.0.229/src/private/de.rs b/third_party/crates/serde-1.0.229/src/private/de.rs new file mode 100644 index 0000000..6f657f5 --- /dev/null +++ b/third_party/crates/serde-1.0.229/src/private/de.rs @@ -0,0 +1,3501 @@ +use crate::lib::*; + +use crate::de::value::{BorrowedBytesDeserializer, BytesDeserializer}; +use crate::de::{ + Deserialize, DeserializeSeed, Deserializer, EnumAccess, Error, IntoDeserializer, VariantAccess, + Visitor, +}; + +#[cfg(any(feature = "std", feature = "alloc"))] +use crate::de::{MapAccess, Unexpected}; + +#[cfg(any(feature = "std", feature = "alloc"))] +pub use self::content::{ + 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 +where + V: Deserialize<'de>, + E: Error, +{ + 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, + { + type Error = E; + + fn deserialize_any(self, _visitor: V) -> Result + where + V: Visitor<'de>, + { + Err(Error::missing_field(self.0)) + } + + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_none() + } + + 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 + } + } + + let deserializer = MissingFieldDeserializer(field, PhantomData); + Deserialize::deserialize(deserializer) +} + +#[cfg(any(feature = "std", feature = "alloc"))] +pub fn borrow_cow_str<'de: 'a, 'a, D, R>(deserializer: D) -> Result +where + D: Deserializer<'de>, + R: From>, +{ + struct CowStrVisitor; + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'a> Visitor<'a> for CowStrVisitor { + type Value = Cow<'a, str>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a string") + } + + fn visit_str(self, v: &str) -> Result + where + E: Error, + { + Ok(Cow::Owned(v.to_owned())) + } + + fn visit_borrowed_str(self, v: &'a str) -> Result + where + E: Error, + { + Ok(Cow::Borrowed(v)) + } + + fn visit_string(self, v: String) -> Result + where + E: Error, + { + Ok(Cow::Owned(v)) + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: Error, + { + match str::from_utf8(v) { + Ok(s) => Ok(Cow::Owned(s.to_owned())), + Err(_) => Err(Error::invalid_value(Unexpected::Bytes(v), &self)), + } + } + + fn visit_borrowed_bytes(self, v: &'a [u8]) -> Result + where + E: Error, + { + match str::from_utf8(v) { + Ok(s) => Ok(Cow::Borrowed(s)), + Err(_) => Err(Error::invalid_value(Unexpected::Bytes(v), &self)), + } + } + + fn visit_byte_buf(self, v: Vec) -> Result + where + E: Error, + { + match String::from_utf8(v) { + Ok(s) => Ok(Cow::Owned(s)), + Err(e) => Err(Error::invalid_value( + Unexpected::Bytes(&e.into_bytes()), + &self, + )), + } + } + } + + deserializer.deserialize_str(CowStrVisitor).map(From::from) +} + +#[cfg(any(feature = "std", feature = "alloc"))] +pub fn borrow_cow_bytes<'de: 'a, 'a, D, R>(deserializer: D) -> Result +where + D: Deserializer<'de>, + R: From>, +{ + struct CowBytesVisitor; + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'a> Visitor<'a> for CowBytesVisitor { + type Value = Cow<'a, [u8]>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a byte array") + } + + fn visit_str(self, v: &str) -> Result + where + E: Error, + { + Ok(Cow::Owned(v.as_bytes().to_vec())) + } + + fn visit_borrowed_str(self, v: &'a str) -> Result + where + E: Error, + { + Ok(Cow::Borrowed(v.as_bytes())) + } + + fn visit_string(self, v: String) -> Result + where + E: Error, + { + Ok(Cow::Owned(v.into_bytes())) + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: Error, + { + Ok(Cow::Owned(v.to_vec())) + } + + fn visit_borrowed_bytes(self, v: &'a [u8]) -> Result + where + E: Error, + { + Ok(Cow::Borrowed(v)) + } + + fn visit_byte_buf(self, v: Vec) -> Result + where + E: Error, + { + Ok(Cow::Owned(v)) + } + } + + deserializer + .deserialize_bytes(CowBytesVisitor) + .map(From::from) +} + +#[cfg(any(feature = "std", feature = "alloc"))] +mod content { + // This module is private and nothing here should be used outside of + // generated code. + // + // We will iterate on the implementation for a few releases and only have to + // worry about backward compatibility for the `untagged` and `tag` attributes + // rather than for this entire mechanism. + // + // This issue is tracking making some of this stuff public: + // https://github.com/serde-rs/serde/issues/741 + + use crate::lib::*; + + use crate::de::{ + self, Deserialize, DeserializeSeed, Deserializer, EnumAccess, Expected, IgnoredAny, + MapAccess, SeqAccess, Unexpected, 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, + } + } + + 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> { + 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>; + + fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str("any value") + } + + fn visit_bool(self, value: bool) -> Result + where + F: de::Error, + { + Ok(Content::Bool(value)) + } + + fn visit_i8(self, value: i8) -> Result + where + F: de::Error, + { + Ok(Content::I8(value)) + } + + fn visit_i16(self, value: i16) -> Result + where + F: de::Error, + { + Ok(Content::I16(value)) + } + + fn visit_i32(self, value: i32) -> Result + where + F: de::Error, + { + Ok(Content::I32(value)) + } + + fn visit_i64(self, value: i64) -> Result + where + F: de::Error, + { + Ok(Content::I64(value)) + } + + fn visit_u8(self, value: u8) -> Result + where + F: de::Error, + { + Ok(Content::U8(value)) + } + + fn visit_u16(self, value: u16) -> Result + where + F: de::Error, + { + Ok(Content::U16(value)) + } + + fn visit_u32(self, value: u32) -> Result + where + F: de::Error, + { + Ok(Content::U32(value)) + } + + fn visit_u64(self, value: u64) -> Result + where + F: de::Error, + { + Ok(Content::U64(value)) + } + + fn visit_f32(self, value: f32) -> Result + where + F: de::Error, + { + Ok(Content::F32(value)) + } + + fn visit_f64(self, value: f64) -> Result + where + F: de::Error, + { + Ok(Content::F64(value)) + } + + fn visit_char(self, value: char) -> Result + where + F: de::Error, + { + Ok(Content::Char(value)) + } + + fn visit_str(self, value: &str) -> Result + where + F: de::Error, + { + Ok(Content::String(value.into())) + } + + fn visit_borrowed_str(self, value: &'de str) -> Result + where + F: de::Error, + { + Ok(Content::Str(value)) + } + + fn visit_string(self, value: String) -> Result + where + F: de::Error, + { + Ok(Content::String(value)) + } + + fn visit_bytes(self, value: &[u8]) -> Result + where + F: de::Error, + { + Ok(Content::ByteBuf(value.into())) + } + + fn visit_borrowed_bytes(self, value: &'de [u8]) -> Result + where + F: de::Error, + { + Ok(Content::Bytes(value)) + } + + fn visit_byte_buf(self, value: Vec) -> Result + where + F: de::Error, + { + Ok(Content::ByteBuf(value)) + } + + fn visit_unit(self) -> Result + where + F: de::Error, + { + Ok(Content::Unit) + } + + fn visit_none(self) -> Result + where + F: de::Error, + { + Ok(Content::None) + } + + fn visit_some(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + 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>, + { + 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) = tri!(visitor.next_element_seed(ContentVisitor::new())) { + vec.push(e); + } + Ok(Content::Seq(vec)) + } + + fn visit_map(self, mut visitor: V) -> Result + where + V: MapAccess<'de>, + { + 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)) + } + + fn visit_enum(self, _visitor: V) -> Result + where + V: EnumAccess<'de>, + { + Err(de::Error::custom( + "untagged and internally tagged enums do not support enum input", + )) + } + } + + /// This is the type of the map keys in an internally tagged enum. + /// + /// Not public API. + pub enum TagOrContent<'de> { + Tag, + 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>, + } + + impl<'de> TagOrContentVisitor<'de> { + fn new(name: &'static str) -> Self { + TagOrContentVisitor { + name, + value: PhantomData, + } + } + } + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'de> DeserializeSeed<'de> for TagOrContentVisitor<'de> { + type Value = TagOrContent<'de>; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + // Internally tagged enums are only supported in self-describing + // formats. + deserializer.deserialize_any(self) + } + } + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'de> Visitor<'de> for TagOrContentVisitor<'de> { + type Value = TagOrContent<'de>; + + fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "a type tag `{}` or any other value", self.name) + } + + fn visit_bool(self, value: bool) -> Result + where + F: de::Error, + { + ContentVisitor::new() + .visit_bool(value) + .map(TagOrContent::Content) + } + + fn visit_i8(self, value: i8) -> Result + where + F: de::Error, + { + ContentVisitor::new() + .visit_i8(value) + .map(TagOrContent::Content) + } + + fn visit_i16(self, value: i16) -> Result + where + F: de::Error, + { + ContentVisitor::new() + .visit_i16(value) + .map(TagOrContent::Content) + } + + fn visit_i32(self, value: i32) -> Result + where + F: de::Error, + { + ContentVisitor::new() + .visit_i32(value) + .map(TagOrContent::Content) + } + + fn visit_i64(self, value: i64) -> Result + where + F: de::Error, + { + ContentVisitor::new() + .visit_i64(value) + .map(TagOrContent::Content) + } + + fn visit_u8(self, value: u8) -> Result + where + F: de::Error, + { + ContentVisitor::new() + .visit_u8(value) + .map(TagOrContent::Content) + } + + fn visit_u16(self, value: u16) -> Result + where + F: de::Error, + { + ContentVisitor::new() + .visit_u16(value) + .map(TagOrContent::Content) + } + + fn visit_u32(self, value: u32) -> Result + where + F: de::Error, + { + ContentVisitor::new() + .visit_u32(value) + .map(TagOrContent::Content) + } + + fn visit_u64(self, value: u64) -> Result + where + F: de::Error, + { + ContentVisitor::new() + .visit_u64(value) + .map(TagOrContent::Content) + } + + fn visit_f32(self, value: f32) -> Result + where + F: de::Error, + { + ContentVisitor::new() + .visit_f32(value) + .map(TagOrContent::Content) + } + + fn visit_f64(self, value: f64) -> Result + where + F: de::Error, + { + ContentVisitor::new() + .visit_f64(value) + .map(TagOrContent::Content) + } + + fn visit_char(self, value: char) -> Result + where + F: de::Error, + { + ContentVisitor::new() + .visit_char(value) + .map(TagOrContent::Content) + } + + fn visit_str(self, value: &str) -> Result + where + F: de::Error, + { + if value == self.name { + Ok(TagOrContent::Tag) + } else { + ContentVisitor::new() + .visit_str(value) + .map(TagOrContent::Content) + } + } + + fn visit_borrowed_str(self, value: &'de str) -> Result + where + F: de::Error, + { + if value == self.name { + Ok(TagOrContent::Tag) + } else { + ContentVisitor::new() + .visit_borrowed_str(value) + .map(TagOrContent::Content) + } + } + + fn visit_string(self, value: String) -> Result + where + F: de::Error, + { + if value == self.name { + Ok(TagOrContent::Tag) + } else { + ContentVisitor::new() + .visit_string(value) + .map(TagOrContent::Content) + } + } + + fn visit_bytes(self, value: &[u8]) -> Result + where + F: de::Error, + { + if value == self.name.as_bytes() { + Ok(TagOrContent::Tag) + } else { + ContentVisitor::new() + .visit_bytes(value) + .map(TagOrContent::Content) + } + } + + fn visit_borrowed_bytes(self, value: &'de [u8]) -> Result + where + F: de::Error, + { + if value == self.name.as_bytes() { + Ok(TagOrContent::Tag) + } else { + ContentVisitor::new() + .visit_borrowed_bytes(value) + .map(TagOrContent::Content) + } + } + + fn visit_byte_buf(self, value: Vec) -> Result + where + F: de::Error, + { + if value == self.name.as_bytes() { + Ok(TagOrContent::Tag) + } else { + ContentVisitor::new() + .visit_byte_buf(value) + .map(TagOrContent::Content) + } + } + + fn visit_unit(self) -> Result + where + F: de::Error, + { + ContentVisitor::new() + .visit_unit() + .map(TagOrContent::Content) + } + + fn visit_none(self) -> Result + where + F: de::Error, + { + ContentVisitor::new() + .visit_none() + .map(TagOrContent::Content) + } + + fn visit_some(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + ContentVisitor::new() + .visit_some(deserializer) + .map(TagOrContent::Content) + } + + fn visit_newtype_struct(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + ContentVisitor::new() + .visit_newtype_struct(deserializer) + .map(TagOrContent::Content) + } + + fn visit_seq(self, visitor: V) -> Result + where + V: SeqAccess<'de>, + { + ContentVisitor::new() + .visit_seq(visitor) + .map(TagOrContent::Content) + } + + fn visit_map(self, visitor: V) -> Result + where + V: MapAccess<'de>, + { + ContentVisitor::new() + .visit_map(visitor) + .map(TagOrContent::Content) + } + + fn visit_enum(self, visitor: V) -> Result + where + V: EnumAccess<'de>, + { + ContentVisitor::new() + .visit_enum(visitor) + .map(TagOrContent::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 TaggedContentVisitor { + tag_name: &'static str, + expecting: &'static str, + value: PhantomData, + } + + impl TaggedContentVisitor { + /// Visitor for the content of an internally tagged enum with the given + /// tag name. + pub fn new(name: &'static str, expecting: &'static str) -> Self { + TaggedContentVisitor { + tag_name: name, + expecting, + value: PhantomData, + } + } + } + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'de, T> Visitor<'de> for TaggedContentVisitor + where + T: Deserialize<'de>, + { + type Value = (T, Content<'de>); + + fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str(self.expecting) + } + + fn visit_seq(self, mut seq: S) -> Result + where + S: SeqAccess<'de>, + { + 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((tag, tri!(ContentVisitor::new().deserialize(rest)))) + } + + fn visit_map(self, mut map: M) -> Result + where + M: MapAccess<'de>, + { + let mut tag = None; + 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(tri!(map.next_value())); + } + TagOrContent::Content(k) => { + 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((tag, Content::Map(vec))), + } + } + } + + /// Used by generated code to deserialize an adjacently tagged enum. + /// + /// Not public API. + pub enum TagOrContentField { + Tag, + 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; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_identifier(self) + } + } + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'de> Visitor<'de> for TagOrContentFieldVisitor { + type Value = TagOrContentField; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + 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, + { + if field == self.tag { + Ok(TagOrContentField::Tag) + } else if field == self.content { + Ok(TagOrContentField::Content) + } else { + 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 + /// ignoring unrelated fields is allowed. + /// + /// Not public API. + pub enum TagContentOtherField { + Tag, + Content, + Other, + } + + /// 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; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_identifier(self) + } + } + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'de> Visitor<'de> for TagContentOtherFieldVisitor { + type Value = TagContentOtherField; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!( + formatter, + "{:?}, {:?}, or other ignored fields", + self.tag, self.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, + { + 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.as_bytes() { + Ok(TagContentOtherField::Content) + } else { + Ok(TagContentOtherField::Other) + } + } + } + + /// Not public API + pub struct ContentDeserializer<'de, E> { + content: Content<'de>, + err: PhantomData, + } + + impl<'de, E> ContentDeserializer<'de, E> + where + E: de::Error, + { + #[cold] + fn invalid_type(self, exp: &dyn Expected) -> E { + de::Error::invalid_type(content_unexpected(&self.content), exp) + } + + fn deserialize_integer(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.content { + 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 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 + where + V: Visitor<'de>, + E: de::Error, + { + let mut seq_visitor = SeqDeserializer::new(content); + let value = tri!(visitor.visit_seq(&mut seq_visitor)); + tri!(seq_visitor.end()); + Ok(value) + } + + fn visit_content_map<'de, V, E>( + content: Vec<(Content<'de>, Content<'de>)>, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + E: de::Error, + { + 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, + { + type Error = E; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.content { + Content::Bool(v) => visitor.visit_bool(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), + Content::F32(v) => visitor.visit_f32(v), + Content::F64(v) => visitor.visit_f64(v), + Content::Char(v) => visitor.visit_char(v), + Content::String(v) => visitor.visit_string(v), + Content::Str(v) => visitor.visit_borrowed_str(v), + Content::ByteBuf(v) => visitor.visit_byte_buf(v), + Content::Bytes(v) => visitor.visit_borrowed_bytes(v), + Content::Unit => visitor.visit_unit(), + Content::None => visitor.visit_none(), + Content::Some(v) => visitor.visit_some(ContentDeserializer::new(*v)), + Content::Newtype(v) => visitor.visit_newtype_struct(ContentDeserializer::new(*v)), + Content::Seq(v) => visit_content_seq(v, visitor), + Content::Map(v) => visit_content_map(v, visitor), + } + } + + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.content { + Content::Bool(v) => visitor.visit_bool(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_i8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_i16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_i32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_i64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_u8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_u16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_u32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_u64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_f32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_float(visitor) + } + + fn deserialize_f64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_float(visitor) + } + + fn deserialize_char(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.content { + Content::Char(v) => visitor.visit_char(v), + Content::String(v) => visitor.visit_string(v), + Content::Str(v) => visitor.visit_borrowed_str(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_str(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_string(visitor) + } + + fn deserialize_string(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.content { + Content::String(v) => visitor.visit_string(v), + Content::Str(v) => visitor.visit_borrowed_str(v), + Content::ByteBuf(v) => visitor.visit_byte_buf(v), + Content::Bytes(v) => visitor.visit_borrowed_bytes(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_bytes(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_byte_buf(visitor) + } + + fn deserialize_byte_buf(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.content { + Content::String(v) => visitor.visit_string(v), + Content::Str(v) => visitor.visit_borrowed_str(v), + Content::ByteBuf(v) => visitor.visit_byte_buf(v), + Content::Bytes(v) => visitor.visit_borrowed_bytes(v), + Content::Seq(v) => visit_content_seq(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.content { + Content::None => visitor.visit_none(), + Content::Some(v) => visitor.visit_some(ContentDeserializer::new(*v)), + Content::Unit => visitor.visit_unit(), + _ => visitor.visit_some(self), + } + } + + fn deserialize_unit(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + 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)), + } + } + + fn deserialize_unit_struct( + self, + _name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match self.content { + // As a special case, allow deserializing untagged newtype + // variant containing unit struct. + // + // #[derive(Deserialize)] + // struct Info; + // + // #[derive(Deserialize)] + // #[serde(tag = "topic")] + // enum Message { + // Info(Info), + // } + // + // We want {"topic":"Info"} to deserialize even though + // 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), + } + } + + fn deserialize_newtype_struct( + self, + _name: &str, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match self.content { + Content::Newtype(v) => visitor.visit_newtype_struct(ContentDeserializer::new(*v)), + _ => visitor.visit_newtype_struct(self), + } + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.content { + Content::Seq(v) => visit_content_seq(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_tuple(self, _len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_map(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.content { + Content::Map(v) => visit_content_map(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_struct( + self, + _name: &'static str, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match self.content { + Content::Seq(v) => visit_content_seq(v, visitor), + Content::Map(v) => visit_content_map(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_enum( + self, + _name: &str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + let (variant, value) = match self.content { + Content::Map(value) => { + let mut iter = value.into_iter(); + let (variant, value) = match iter.next() { + Some(v) => v, + None => { + return Err(de::Error::invalid_value( + de::Unexpected::Map, + &"map with a single key", + )); + } + }; + // enums are encoded in json as maps with a single key:value pair + if iter.next().is_some() { + return Err(de::Error::invalid_value( + de::Unexpected::Map, + &"map with a single key", + )); + } + (variant, Some(value)) + } + s @ Content::String(_) | s @ Content::Str(_) => (s, None), + other => { + return Err(de::Error::invalid_type( + content_unexpected(&other), + &"string or map", + )); + } + }; + + visitor.visit_enum(EnumDeserializer::new(variant, value)) + } + + fn deserialize_identifier(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.content { + Content::String(v) => visitor.visit_string(v), + Content::Str(v) => visitor.visit_borrowed_str(v), + Content::ByteBuf(v) => visitor.visit_byte_buf(v), + Content::Bytes(v) => visitor.visit_borrowed_bytes(v), + Content::U8(v) => visitor.visit_u8(v), + Content::U64(v) => visitor.visit_u64(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + 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, + err: PhantomData, + } + } + } + + struct SeqDeserializer<'de, E> { + iter: > as IntoIterator>::IntoIter, + count: usize, + marker: PhantomData, + } + + 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, + { + 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), + )) + } + } + } + + #[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; + + fn deserialize_any(mut self, visitor: V) -> Result + where + V: Visitor<'de>, + { + 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 + } + } + + #[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 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(ContentDeserializer::new(value)).map(Some) + } + None => Ok(None), + } + } + + fn size_hint(&self) -> Option { + size_hint::from_bounds(&self.iter) + } + } + + 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 MapDeserializer<'de, E> { + iter: , Content<'de>)> as IntoIterator>::IntoIter, + value: Option>, + count: usize, + error: 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> MapDeserializer<'de, E> + where + E: de::Error, + { + 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), + )) + } + } + } + + 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, + } + } + } + + #[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 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) + } + } + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'de, E> SeqAccess<'de> for MapDeserializer<'de, E> + where + E: de::Error, + { + 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 = PairDeserializer(k, v, PhantomData); + seed.deserialize(de).map(Some) + } + None => Ok(None), + } + } + + fn size_hint(&self) -> Option { + size_hint::from_bounds(&self.iter) + } + } + + 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, + { + 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> EnumDeserializer<'de, E> + where + E: de::Error, + { + pub fn new(variant: Content<'de>, value: Option>) -> EnumDeserializer<'de, E> { + EnumDeserializer { + variant, + value, + err: PhantomData, + } + } + } + + #[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 variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), E> + where + V: de::DeserializeSeed<'de>, + { + 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 newtype_variant_seed(self, seed: T) -> Result + where + T: de::DeserializeSeed<'de>, + { + match self.value { + Some(value) => seed.deserialize(ContentDeserializer::new(value)), + None => Err(de::Error::invalid_type( + de::Unexpected::UnitVariant, + &"newtype variant", + )), + } + } + + 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( + content_unexpected(&other), + &"tuple variant", + )), + None => Err(de::Error::invalid_type( + de::Unexpected::UnitVariant, + &"tuple variant", + )), + } + } + + 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", + )), + } + } + } + + /// Not public API. + pub struct ContentRefDeserializer<'a, 'de: 'a, E> { + content: &'a Content<'de>, + err: PhantomData, + } + + impl<'a, 'de, E> ContentRefDeserializer<'a, 'de, E> + where + E: de::Error, + { + #[cold] + fn invalid_type(self, exp: &dyn Expected) -> E { + de::Error::invalid_type(content_unexpected(self.content), exp) + } + + fn deserialize_integer(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match *self.content { + 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 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>( + content: &'a [Content<'de>], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + E: de::Error, + { + let mut seq_visitor = SeqRefDeserializer::new(content); + let value = tri!(visitor.visit_seq(&mut seq_visitor)); + tri!(seq_visitor.end()); + Ok(value) + } + + fn visit_content_map_ref<'a, 'de, V, E>( + content: &'a [(Content<'de>, Content<'de>)], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + E: de::Error, + { + 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, + { + type Error = E; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match *self.content { + Content::Bool(v) => visitor.visit_bool(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), + Content::F32(v) => visitor.visit_f32(v), + Content::F64(v) => visitor.visit_f64(v), + Content::Char(v) => visitor.visit_char(v), + Content::String(ref v) => visitor.visit_str(v), + Content::Str(v) => visitor.visit_borrowed_str(v), + Content::ByteBuf(ref v) => visitor.visit_bytes(v), + Content::Bytes(v) => visitor.visit_borrowed_bytes(v), + Content::Unit => visitor.visit_unit(), + Content::None => visitor.visit_none(), + Content::Some(ref v) => visitor.visit_some(ContentRefDeserializer::new(v)), + Content::Newtype(ref v) => { + visitor.visit_newtype_struct(ContentRefDeserializer::new(v)) + } + Content::Seq(ref v) => visit_content_seq_ref(v, visitor), + Content::Map(ref v) => visit_content_map_ref(v, visitor), + } + } + + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match *self.content { + Content::Bool(v) => visitor.visit_bool(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_i8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_i16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_i32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_i64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_u8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_u16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_u32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_u64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_f32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_float(visitor) + } + + fn deserialize_f64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_float(visitor) + } + + fn deserialize_char(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match *self.content { + Content::Char(v) => visitor.visit_char(v), + Content::String(ref v) => visitor.visit_str(v), + Content::Str(v) => visitor.visit_borrowed_str(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_str(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match *self.content { + Content::String(ref v) => visitor.visit_str(v), + Content::Str(v) => visitor.visit_borrowed_str(v), + Content::ByteBuf(ref v) => visitor.visit_bytes(v), + Content::Bytes(v) => visitor.visit_borrowed_bytes(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_string(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_bytes(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match *self.content { + Content::String(ref v) => visitor.visit_str(v), + Content::Str(v) => visitor.visit_borrowed_str(v), + Content::ByteBuf(ref v) => visitor.visit_bytes(v), + Content::Bytes(v) => visitor.visit_borrowed_bytes(v), + Content::Seq(ref v) => visit_content_seq_ref(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_byte_buf(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_bytes(visitor) + } + + fn deserialize_option(self, visitor: V) -> Result + 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), + } + } + + fn deserialize_unit(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match *self.content { + Content::Unit => visitor.visit_unit(), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_unit_struct( + self, + _name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.deserialize_unit(visitor) + } + + fn deserialize_newtype_struct(self, _name: &str, visitor: V) -> Result + 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), + } + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match *self.content { + Content::Seq(ref v) => visit_content_seq_ref(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_tuple(self, _len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_map(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match *self.content { + Content::Map(ref v) => visit_content_map_ref(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_struct( + self, + _name: &'static str, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match *self.content { + Content::Seq(ref v) => visit_content_seq_ref(v, visitor), + Content::Map(ref v) => visit_content_map_ref(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_enum( + self, + _name: &str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + let (variant, value) = match *self.content { + Content::Map(ref value) => { + let mut iter = value.iter(); + let (variant, value) = match iter.next() { + Some(v) => v, + None => { + return Err(de::Error::invalid_value( + de::Unexpected::Map, + &"map with a single key", + )); + } + }; + // enums are encoded in json as maps with a single key:value pair + if iter.next().is_some() { + return Err(de::Error::invalid_value( + de::Unexpected::Map, + &"map with a single key", + )); + } + (variant, Some(value)) + } + ref s @ Content::String(_) | ref s @ Content::Str(_) => (s, None), + ref other => { + return Err(de::Error::invalid_type( + content_unexpected(other), + &"string or map", + )); + } + }; + + visitor.visit_enum(EnumRefDeserializer { + variant, + value, + err: PhantomData, + }) + } + + fn deserialize_identifier(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match *self.content { + Content::String(ref v) => visitor.visit_str(v), + Content::Str(v) => visitor.visit_borrowed_str(v), + Content::ByteBuf(ref v) => visitor.visit_bytes(v), + Content::Bytes(v) => visitor.visit_borrowed_bytes(v), + Content::U8(v) => visitor.visit_u8(v), + Content::U64(v) => visitor.visit_u64(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + 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, + err: PhantomData, + } + } + } + + #[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, + { + 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), + )) + } + } + } + + #[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; + + fn deserialize_any(mut self, visitor: V) -> Result + where + V: Visitor<'de>, + { + 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 + } + } + + #[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>>, + count: usize, + error: PhantomData, + } + + 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, + { + 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), + )) + } + } + } + + 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, + } + } + } + + #[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 + 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 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) + } + 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(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))) + } + None => Ok(None), + } + } + + fn size_hint(&self) -> Option { + size_hint::from_bounds(&self.iter) + } + } + + #[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, + { + 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) + } + } + + 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, + { + 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))) + } + } + + 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 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, + { + 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(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 { + if self.0.is_some() { + Some(2) + } else if self.1.is_some() { + Some(1) + } else { + Some(0) + } + } + } + + struct EnumRefDeserializer<'a, 'de: 'a, E> + where + E: de::Error, + { + variant: &'a Content<'de>, + value: Option<&'a Content<'de>>, + err: PhantomData, + } + + #[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, + { + 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)) + } + } + + 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 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 newtype_variant_seed(self, seed: T) -> Result + where + T: de::DeserializeSeed<'de>, + { + 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::invalid_type( + de::Unexpected::UnitVariant, + &"newtype variant", + )), + } + } + + fn tuple_variant(self, _len: usize, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + 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", + )), + } + } + + 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, + { + type Deserializer = Self; + + fn into_deserializer(self) -> Self { + self + } + } + + #[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, + { + type Deserializer = Self; + + fn into_deserializer(self) -> Self { + self + } + } + + /// Visitor for deserializing an internally tagged unit variant. + /// + /// Not public API. + pub struct InternallyTaggedUnitVisitor<'a> { + type_name: &'a str, + variant_name: &'a str, + } + + impl<'a> InternallyTaggedUnitVisitor<'a> { + /// Not public API. + pub fn new(type_name: &'a str, variant_name: &'a str) -> Self { + InternallyTaggedUnitVisitor { + type_name, + variant_name, + } + } + } + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'de, 'a> Visitor<'de> for InternallyTaggedUnitVisitor<'a> { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!( + formatter, + "unit variant {}::{}", + self.type_name, self.variant_name + ) + } + + fn visit_seq(self, _: S) -> Result<(), S::Error> + where + S: SeqAccess<'de>, + { + Ok(()) + } + + fn visit_map(self, mut access: M) -> Result<(), M::Error> + where + M: MapAccess<'de>, + { + while tri!(access.next_entry::()).is_some() {} + Ok(()) + } + } + + /// Visitor for deserializing an untagged unit variant. + /// + /// Not public API. + pub struct UntaggedUnitVisitor<'a> { + type_name: &'a str, + variant_name: &'a str, + } + + impl<'a> UntaggedUnitVisitor<'a> { + /// Not public API. + pub fn new(type_name: &'a str, variant_name: &'a str) -> Self { + UntaggedUnitVisitor { + type_name, + variant_name, + } + } + } + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl<'de, 'a> Visitor<'de> for UntaggedUnitVisitor<'a> { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!( + formatter, + "unit variant {}::{}", + self.type_name, self.variant_name + ) + } + + fn visit_unit(self) -> Result<(), E> + where + E: de::Error, + { + Ok(()) + } + + fn visit_none(self) -> Result<(), E> + where + E: de::Error, + { + Ok(()) + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +// Like `IntoDeserializer` but also implemented for `&[u8]`. This is used for +// the newtype fallthrough case of `field_identifier`. +// +// #[derive(Deserialize)] +// #[serde(field_identifier)] +// enum F { +// A, +// B, +// Other(String), // deserialized using IdentifierDeserializer +// } +pub trait IdentifierDeserializer<'de, E: Error> { + type Deserializer: Deserializer<'de, Error = E>; + + fn from(self) -> Self::Deserializer; +} + +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; + + fn from(self) -> Self::Deserializer { + self.into_deserializer() + } +} + +pub struct StrDeserializer<'a, E> { + value: &'a str, + marker: PhantomData, +} + +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] +impl<'de, 'a, E> Deserializer<'de> for StrDeserializer<'a, E> +where + E: Error, +{ + type Error = E; + + 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 + } +} + +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, +{ + type Error = E; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_borrowed_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 + } +} + +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] +impl<'a, E> IdentifierDeserializer<'a, E> for &'a str +where + E: Error, +{ + type Deserializer = StrDeserializer<'a, E>; + + fn from(self) -> Self::Deserializer { + StrDeserializer { + value: self, + marker: PhantomData, + } + } +} + +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] +impl<'de, E> IdentifierDeserializer<'de, E> for Borrowed<'de, str> +where + E: Error, +{ + type Deserializer = BorrowedStrDeserializer<'de, E>; + + fn from(self) -> Self::Deserializer { + BorrowedStrDeserializer { + value: self.0, + marker: PhantomData, + } + } +} + +#[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) + } +} + +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] +impl<'de, E> IdentifierDeserializer<'de, E> for Borrowed<'de, [u8]> +where + E: Error, +{ + type Deserializer = BorrowedBytesDeserializer<'de, E>; + + fn from(self) -> Self::Deserializer { + BorrowedBytesDeserializer::new(self.0) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +pub struct FlatMapDeserializer<'a, 'de: 'a, E>( + pub &'a mut Vec, Content<'de>)>>, + pub PhantomData, +); + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, 'de, E> FlatMapDeserializer<'a, 'de, E> +where + E: Error, +{ + fn deserialize_other() -> Result { + Err(Error::custom("can only flatten structs and maps")) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +macro_rules! forward_to_deserialize_other { + ($($func:ident ($($arg:ty),*))*) => { + $( + fn $func(self, $(_: $arg,)* _visitor: V) -> Result + where + V: Visitor<'de>, + { + Self::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, +{ + type Error = E; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_map(visitor) + } + + fn deserialize_enum( + self, + name: &'static str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + 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))); + } + } + + Err(Error::custom(format_args!( + "no variant of enum {} found in flattened data", + name + ))) + } + + fn deserialize_map(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_map(FlatMapAccess { + iter: self.0.iter(), + pending_content: None, + _marker: PhantomData, + }) + } + + fn deserialize_struct( + self, + _: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + 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 + where + V: Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match visitor.__private_visit_untagged_option(self) { + Ok(value) => Ok(value), + Err(()) => Self::deserialize_other(), + } + } + + fn deserialize_unit(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + 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() + deserialize_i16() + deserialize_i32() + deserialize_i64() + deserialize_u8() + deserialize_u16() + deserialize_u32() + deserialize_u64() + deserialize_f32() + deserialize_f64() + deserialize_char() + deserialize_str() + deserialize_string() + deserialize_bytes() + deserialize_byte_buf() + deserialize_seq() + deserialize_tuple(usize) + deserialize_tuple_struct(&'static str, usize) + deserialize_identifier() + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +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"))] +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] +impl<'a, 'de, E> MapAccess<'de> for FlatMapAccess<'a, 'de, E> +where + E: Error, +{ + type Error = E; + + fn next_key_seed(&mut self, seed: T) -> Result, Self::Error> + where + T: DeserializeSeed<'de>, + { + 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); + } + } + Ok(None) + } + + fn next_value_seed(&mut self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + match self.pending_content.take() { + Some(value) => seed.deserialize(ContentRefDeserializer::new(value)), + None => Err(Error::custom("value is missing")), + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +struct FlatStructAccess<'a, 'de: 'a, E> { + iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>, + pending_content: Option>, + fields: &'static [&'static str], + _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, +{ + type Error = E; + + fn next_key_seed(&mut self, seed: T) -> Result, Self::Error> + where + T: DeserializeSeed<'de>, + { + 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); + } + } + Ok(None) + } + + fn next_value_seed(&mut self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + match self.pending_content.take() { + Some(value) => seed.deserialize(ContentDeserializer::new(value)), + None => Err(Error::custom("value is missing")), + } + } +} + +/// 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"))] +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 + } +} + +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 + F: Deserialize<'de>, +{ + type Value = F; + + 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 + A: EnumAccess<'de>, + { + let (variant, variant_access) = tri!(data.variant()); + tri!(variant_access.unit_variant()); + Ok(variant) + } +} + +#[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 + D: Deserializer<'de>, + { + deserializer.deserialize_enum( + self.enum_name, + self.variants, + AdjacentlyTaggedEnumVariantVisitor { + enum_name: self.enum_name, + fields_enum: PhantomData, + }, + ) + } +} diff --git a/third_party/crates/serde-1.0.229/src/private/mod.rs b/third_party/crates/serde-1.0.229/src/private/mod.rs new file mode 100644 index 0000000..20bfa4e --- /dev/null +++ b/third_party/crates/serde-1.0.229/src/private/mod.rs @@ -0,0 +1,18 @@ +#[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/third_party/crates/serde-1.0.229/src/private/ser.rs b/third_party/crates/serde-1.0.229/src/private/ser.rs new file mode 100644 index 0000000..411e2b4 --- /dev/null +++ b/third_party/crates/serde-1.0.229/src/private/ser.rs @@ -0,0 +1,1382 @@ +use crate::lib::*; + +use crate::ser::{self, Impossible, Serialize, SerializeMap, SerializeStruct, Serializer}; + +#[cfg(any(feature = "std", feature = "alloc"))] +use self::content::{ + Content, ContentSerializer, SerializeStructVariantAsMapValue, SerializeTupleVariantAsMapValue, +}; + +/// Used to check that serde(getter) attributes return the expected type. +/// Not public API. +pub fn constrain(t: &T) -> &T { + t +} + +/// Not public API. +pub fn serialize_tagged_newtype( + serializer: S, + type_ident: &'static str, + variant_ident: &'static str, + tag: &'static str, + variant_name: &'static str, + value: &T, +) -> Result +where + S: Serializer, + T: Serialize, +{ + value.serialize(TaggedSerializer { + type_ident, + variant_ident, + tag, + variant_name, + delegate: serializer, + }) +} + +struct TaggedSerializer { + type_ident: &'static str, + variant_ident: &'static str, + tag: &'static str, + variant_name: &'static str, + delegate: S, +} + +enum Unsupported { + Boolean, + Integer, + Float, + Char, + String, + ByteArray, + Optional, + 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 { + Unsupported::Boolean => formatter.write_str("a boolean"), + Unsupported::Integer => formatter.write_str("an integer"), + Unsupported::Float => formatter.write_str("a float"), + Unsupported::Char => formatter.write_str("a char"), + Unsupported::String => formatter.write_str("a string"), + Unsupported::ByteArray => formatter.write_str("a byte array"), + Unsupported::Optional => formatter.write_str("an optional"), + 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"), + } + } +} + +impl TaggedSerializer +where + S: Serializer, +{ + fn bad_type(self, what: Unsupported) -> S::Error { + ser::Error::custom(format_args!( + "cannot serialize tagged newtype variant {}::{} containing {}", + self.type_ident, self.variant_ident, what + )) + } +} + +#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] +impl Serializer for TaggedSerializer +where + S: Serializer, +{ + type Ok = S::Ok; + type Error = S::Error; + + type SerializeSeq = Impossible; + type SerializeTuple = Impossible; + type SerializeTupleStruct = Impossible; + type SerializeMap = S::SerializeMap; + type SerializeStruct = S::SerializeStruct; + + #[cfg(not(any(feature = "std", feature = "alloc")))] + type SerializeTupleVariant = Impossible; + #[cfg(any(feature = "std", feature = "alloc"))] + type SerializeTupleVariant = SerializeTupleVariantAsMapValue; + + #[cfg(not(any(feature = "std", feature = "alloc")))] + type SerializeStructVariant = Impossible; + #[cfg(any(feature = "std", feature = "alloc"))] + type SerializeStructVariant = SerializeStructVariantAsMapValue; + + fn serialize_bool(self, _: bool) -> Result { + Err(self.bad_type(Unsupported::Boolean)) + } + + fn serialize_i8(self, _: i8) -> Result { + Err(self.bad_type(Unsupported::Integer)) + } + + fn serialize_i16(self, _: i16) -> Result { + Err(self.bad_type(Unsupported::Integer)) + } + + fn serialize_i32(self, _: i32) -> Result { + Err(self.bad_type(Unsupported::Integer)) + } + + fn serialize_i64(self, _: i64) -> Result { + Err(self.bad_type(Unsupported::Integer)) + } + + fn serialize_u8(self, _: u8) -> Result { + Err(self.bad_type(Unsupported::Integer)) + } + + fn serialize_u16(self, _: u16) -> Result { + Err(self.bad_type(Unsupported::Integer)) + } + + fn serialize_u32(self, _: u32) -> Result { + Err(self.bad_type(Unsupported::Integer)) + } + + fn serialize_u64(self, _: u64) -> Result { + Err(self.bad_type(Unsupported::Integer)) + } + + fn serialize_f32(self, _: f32) -> Result { + Err(self.bad_type(Unsupported::Float)) + } + + fn serialize_f64(self, _: f64) -> Result { + Err(self.bad_type(Unsupported::Float)) + } + + fn serialize_char(self, _: char) -> Result { + Err(self.bad_type(Unsupported::Char)) + } + + fn serialize_str(self, _: &str) -> Result { + Err(self.bad_type(Unsupported::String)) + } + + fn serialize_bytes(self, _: &[u8]) -> Result { + Err(self.bad_type(Unsupported::ByteArray)) + } + + fn serialize_none(self) -> Result { + Err(self.bad_type(Unsupported::Optional)) + } + + fn serialize_some(self, _: &T) -> Result + where + T: ?Sized + Serialize, + { + Err(self.bad_type(Unsupported::Optional)) + } + + fn serialize_unit(self) -> Result { + 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 = tri!(self.delegate.serialize_map(Some(1))); + tri!(map.serialize_entry(self.tag, self.variant_name)); + map.end() + } + + fn serialize_unit_variant( + self, + _: &'static str, + _: u32, + inner_variant: &'static str, + ) -> Result { + 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( + self, + _: &'static str, + value: &T, + ) -> Result + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant( + self, + _: &'static str, + _: u32, + inner_variant: &'static str, + inner_value: &T, + ) -> Result + where + T: ?Sized + Serialize, + { + 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() + } + + fn serialize_seq(self, _: Option) -> Result { + Err(self.bad_type(Unsupported::Sequence)) + } + + fn serialize_tuple(self, _: usize) -> Result { + Err(self.bad_type(Unsupported::Tuple)) + } + + fn serialize_tuple_struct( + self, + _: &'static str, + _: usize, + ) -> Result { + Err(self.bad_type(Unsupported::TupleStruct)) + } + + #[cfg(not(any(feature = "std", feature = "alloc")))] + fn serialize_tuple_variant( + self, + _: &'static str, + _: u32, + _: &'static str, + _: usize, + ) -> Result { + // Lack of push-based serialization means we need to buffer the content + // of the tuple variant, so it requires std. + Err(self.bad_type(Unsupported::Enum)) + } + + #[cfg(any(feature = "std", feature = "alloc"))] + fn serialize_tuple_variant( + self, + _: &'static str, + _: u32, + inner_variant: &'static str, + len: usize, + ) -> Result { + 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, + len, + )) + } + + fn serialize_map(self, len: Option) -> Result { + let mut map = tri!(self.delegate.serialize_map(len.map(|len| len + 1))); + tri!(map.serialize_entry(self.tag, self.variant_name)); + Ok(map) + } + + fn serialize_struct( + self, + name: &'static str, + len: usize, + ) -> Result { + let mut state = tri!(self.delegate.serialize_struct(name, len + 1)); + tri!(state.serialize_field(self.tag, self.variant_name)); + Ok(state) + } + + #[cfg(not(any(feature = "std", feature = "alloc")))] + fn serialize_struct_variant( + self, + _: &'static str, + _: u32, + _: &'static str, + _: usize, + ) -> Result { + // Lack of push-based serialization means we need to buffer the content + // of the struct variant, so it requires std. + Err(self.bad_type(Unsupported::Enum)) + } + + #[cfg(any(feature = "std", feature = "alloc"))] + fn serialize_struct_variant( + self, + _: &'static str, + _: u32, + inner_variant: &'static str, + len: usize, + ) -> Result { + 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, + len, + )) + } + + #[cfg(not(any(feature = "std", feature = "alloc")))] + fn collect_str(self, _: &T) -> Result + where + T: ?Sized + Display, + { + Err(self.bad_type(Unsupported::String)) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +mod content { + use crate::lib::*; + + use crate::ser::{self, Serialize, Serializer}; + + pub struct SerializeTupleVariantAsMapValue { + map: M, + name: &'static str, + fields: Vec, + } + + impl SerializeTupleVariantAsMapValue { + pub fn new(map: M, name: &'static str, len: usize) -> Self { + SerializeTupleVariantAsMapValue { + 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, + { + type Ok = M::Ok; + type Error = M::Error; + + fn serialize_field(&mut self, value: &T) -> Result<(), M::Error> + where + T: ?Sized + Serialize, + { + let value = tri!(value.serialize(ContentSerializer::::new())); + self.fields.push(value); + Ok(()) + } + + fn end(mut self) -> Result { + tri!(self + .map + .serialize_value(&Content::TupleStruct(self.name, self.fields))); + self.map.end() + } + } + + pub struct SerializeStructVariantAsMapValue { + map: M, + name: &'static str, + fields: Vec<(&'static str, Content)>, + } + + impl SerializeStructVariantAsMapValue { + pub fn new(map: M, name: &'static str, len: usize) -> Self { + SerializeStructVariantAsMapValue { + 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, + { + type Ok = M::Ok; + type Error = M::Error; + + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), M::Error> + where + T: ?Sized + Serialize, + { + let value = tri!(value.serialize(ContentSerializer::::new())); + self.fields.push((key, value)); + Ok(()) + } + + fn end(mut self) -> Result { + tri!(self + .map + .serialize_value(&Content::Struct(self.name, self.fields))); + self.map.end() + } + } + + pub enum Content { + 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), + Bytes(Vec), + + None, + Some(Box), + + Unit, + UnitStruct(&'static str), + UnitVariant(&'static str, u32, &'static str), + NewtypeStruct(&'static str, Box), + NewtypeVariant(&'static str, u32, &'static str, Box), + + Seq(Vec), + Tuple(Vec), + TupleStruct(&'static str, Vec), + TupleVariant(&'static str, u32, &'static str, Vec), + Map(Vec<(Content, Content)>), + Struct(&'static str, Vec<(&'static str, Content)>), + StructVariant( + &'static str, + u32, + &'static str, + Vec<(&'static str, Content)>, + ), + } + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl Serialize for Content { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match *self { + Content::Bool(b) => serializer.serialize_bool(b), + Content::U8(u) => serializer.serialize_u8(u), + Content::U16(u) => serializer.serialize_u16(u), + Content::U32(u) => serializer.serialize_u32(u), + Content::U64(u) => serializer.serialize_u64(u), + Content::I8(i) => serializer.serialize_i8(i), + Content::I16(i) => serializer.serialize_i16(i), + Content::I32(i) => serializer.serialize_i32(i), + Content::I64(i) => serializer.serialize_i64(i), + Content::F32(f) => serializer.serialize_f32(f), + Content::F64(f) => serializer.serialize_f64(f), + Content::Char(c) => serializer.serialize_char(c), + Content::String(ref s) => serializer.serialize_str(s), + Content::Bytes(ref b) => serializer.serialize_bytes(b), + Content::None => serializer.serialize_none(), + Content::Some(ref c) => serializer.serialize_some(&**c), + Content::Unit => serializer.serialize_unit(), + Content::UnitStruct(n) => serializer.serialize_unit_struct(n), + Content::UnitVariant(n, i, v) => serializer.serialize_unit_variant(n, i, v), + Content::NewtypeStruct(n, ref c) => serializer.serialize_newtype_struct(n, &**c), + Content::NewtypeVariant(n, i, v, ref c) => { + serializer.serialize_newtype_variant(n, i, v, &**c) + } + Content::Seq(ref elements) => elements.serialize(serializer), + Content::Tuple(ref elements) => { + use crate::ser::SerializeTuple; + let mut tuple = tri!(serializer.serialize_tuple(elements.len())); + for e in elements { + tri!(tuple.serialize_element(e)); + } + tuple.end() + } + Content::TupleStruct(n, ref fields) => { + use crate::ser::SerializeTupleStruct; + let mut ts = tri!(serializer.serialize_tuple_struct(n, fields.len())); + for f in fields { + tri!(ts.serialize_field(f)); + } + ts.end() + } + Content::TupleVariant(n, i, v, ref fields) => { + use crate::ser::SerializeTupleVariant; + let mut tv = tri!(serializer.serialize_tuple_variant(n, i, v, fields.len())); + for f in fields { + tri!(tv.serialize_field(f)); + } + tv.end() + } + Content::Map(ref entries) => { + 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 crate::ser::SerializeStruct; + let mut s = tri!(serializer.serialize_struct(n, fields.len())); + for &(k, ref v) in fields { + tri!(s.serialize_field(k, v)); + } + s.end() + } + Content::StructVariant(n, i, v, ref fields) => { + use crate::ser::SerializeStructVariant; + let mut sv = tri!(serializer.serialize_struct_variant(n, i, v, fields.len())); + for &(k, ref v) in fields { + tri!(sv.serialize_field(k, v)); + } + sv.end() + } + } + } + } + + pub struct ContentSerializer { + error: PhantomData, + } + + impl ContentSerializer { + pub fn new() -> Self { + ContentSerializer { error: PhantomData } + } + } + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl Serializer for ContentSerializer + where + E: ser::Error, + { + type Ok = Content; + type Error = E; + + type SerializeSeq = SerializeSeq; + type SerializeTuple = SerializeTuple; + type SerializeTupleStruct = SerializeTupleStruct; + type SerializeTupleVariant = SerializeTupleVariant; + type SerializeMap = SerializeMap; + type SerializeStruct = SerializeStruct; + type SerializeStructVariant = SerializeStructVariant; + + fn serialize_bool(self, v: bool) -> Result { + Ok(Content::Bool(v)) + } + + fn serialize_i8(self, v: i8) -> Result { + Ok(Content::I8(v)) + } + + fn serialize_i16(self, v: i16) -> Result { + Ok(Content::I16(v)) + } + + fn serialize_i32(self, v: i32) -> Result { + Ok(Content::I32(v)) + } + + fn serialize_i64(self, v: i64) -> Result { + Ok(Content::I64(v)) + } + + fn serialize_u8(self, v: u8) -> Result { + Ok(Content::U8(v)) + } + + fn serialize_u16(self, v: u16) -> Result { + Ok(Content::U16(v)) + } + + fn serialize_u32(self, v: u32) -> Result { + Ok(Content::U32(v)) + } + + fn serialize_u64(self, v: u64) -> Result { + Ok(Content::U64(v)) + } + + fn serialize_f32(self, v: f32) -> Result { + Ok(Content::F32(v)) + } + + fn serialize_f64(self, v: f64) -> Result { + Ok(Content::F64(v)) + } + + fn serialize_char(self, v: char) -> Result { + Ok(Content::Char(v)) + } + + fn serialize_str(self, value: &str) -> Result { + Ok(Content::String(value.to_owned())) + } + + fn serialize_bytes(self, value: &[u8]) -> Result { + Ok(Content::Bytes(value.to_owned())) + } + + fn serialize_none(self) -> Result { + Ok(Content::None) + } + + fn serialize_some(self, value: &T) -> Result + where + T: ?Sized + Serialize, + { + Ok(Content::Some(Box::new(tri!(value.serialize(self))))) + } + + fn serialize_unit(self) -> Result { + Ok(Content::Unit) + } + + fn serialize_unit_struct(self, name: &'static str) -> Result { + Ok(Content::UnitStruct(name)) + } + + fn serialize_unit_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + ) -> Result { + Ok(Content::UnitVariant(name, variant_index, variant)) + } + + fn serialize_newtype_struct(self, name: &'static str, value: &T) -> Result + where + T: ?Sized + Serialize, + { + Ok(Content::NewtypeStruct( + name, + Box::new(tri!(value.serialize(self))), + )) + } + + fn serialize_newtype_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result + where + T: ?Sized + Serialize, + { + Ok(Content::NewtypeVariant( + name, + variant_index, + variant, + Box::new(tri!(value.serialize(self))), + )) + } + + fn serialize_seq(self, len: Option) -> Result { + Ok(SerializeSeq { + elements: Vec::with_capacity(len.unwrap_or(0)), + error: PhantomData, + }) + } + + fn serialize_tuple(self, len: usize) -> Result { + Ok(SerializeTuple { + elements: Vec::with_capacity(len), + error: PhantomData, + }) + } + + fn serialize_tuple_struct( + self, + name: &'static str, + len: usize, + ) -> Result { + Ok(SerializeTupleStruct { + name, + fields: Vec::with_capacity(len), + error: PhantomData, + }) + } + + fn serialize_tuple_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + Ok(SerializeTupleVariant { + name, + variant_index, + variant, + fields: Vec::with_capacity(len), + error: PhantomData, + }) + } + + fn serialize_map(self, len: Option) -> Result { + Ok(SerializeMap { + entries: Vec::with_capacity(len.unwrap_or(0)), + key: None, + error: PhantomData, + }) + } + + fn serialize_struct( + self, + name: &'static str, + len: usize, + ) -> Result { + Ok(SerializeStruct { + name, + fields: Vec::with_capacity(len), + error: PhantomData, + }) + } + + fn serialize_struct_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + Ok(SerializeStructVariant { + name, + variant_index, + variant, + fields: Vec::with_capacity(len), + error: PhantomData, + }) + } + } + + pub struct SerializeSeq { + elements: Vec, + error: PhantomData, + } + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl ser::SerializeSeq for SerializeSeq + where + E: ser::Error, + { + type Ok = Content; + type Error = E; + + fn serialize_element(&mut self, value: &T) -> Result<(), E> + where + T: ?Sized + Serialize, + { + let value = tri!(value.serialize(ContentSerializer::::new())); + self.elements.push(value); + Ok(()) + } + + fn end(self) -> Result { + Ok(Content::Seq(self.elements)) + } + } + + pub struct SerializeTuple { + elements: Vec, + error: PhantomData, + } + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl ser::SerializeTuple for SerializeTuple + where + E: ser::Error, + { + type Ok = Content; + type Error = E; + + fn serialize_element(&mut self, value: &T) -> Result<(), E> + where + T: ?Sized + Serialize, + { + let value = tri!(value.serialize(ContentSerializer::::new())); + self.elements.push(value); + Ok(()) + } + + fn end(self) -> Result { + Ok(Content::Tuple(self.elements)) + } + } + + pub struct SerializeTupleStruct { + name: &'static str, + fields: Vec, + error: PhantomData, + } + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl ser::SerializeTupleStruct for SerializeTupleStruct + where + E: ser::Error, + { + type Ok = Content; + type Error = E; + + fn serialize_field(&mut self, value: &T) -> Result<(), E> + where + T: ?Sized + Serialize, + { + let value = tri!(value.serialize(ContentSerializer::::new())); + self.fields.push(value); + Ok(()) + } + + fn end(self) -> Result { + Ok(Content::TupleStruct(self.name, self.fields)) + } + } + + pub struct SerializeTupleVariant { + name: &'static str, + variant_index: u32, + variant: &'static str, + fields: Vec, + error: PhantomData, + } + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl ser::SerializeTupleVariant for SerializeTupleVariant + where + E: ser::Error, + { + type Ok = Content; + type Error = E; + + fn serialize_field(&mut self, value: &T) -> Result<(), E> + where + T: ?Sized + Serialize, + { + let value = tri!(value.serialize(ContentSerializer::::new())); + self.fields.push(value); + Ok(()) + } + + fn end(self) -> Result { + Ok(Content::TupleVariant( + self.name, + self.variant_index, + self.variant, + self.fields, + )) + } + } + + pub struct SerializeMap { + entries: Vec<(Content, Content)>, + key: Option, + error: PhantomData, + } + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl ser::SerializeMap for SerializeMap + where + E: ser::Error, + { + type Ok = Content; + type Error = E; + + fn serialize_key(&mut self, key: &T) -> Result<(), E> + where + T: ?Sized + Serialize, + { + let key = tri!(key.serialize(ContentSerializer::::new())); + self.key = Some(key); + Ok(()) + } + + fn serialize_value(&mut self, value: &T) -> Result<(), E> + where + T: ?Sized + Serialize, + { + let key = self + .key + .take() + .expect("serialize_value called before serialize_key"); + let value = tri!(value.serialize(ContentSerializer::::new())); + self.entries.push((key, value)); + Ok(()) + } + + fn end(self) -> Result { + Ok(Content::Map(self.entries)) + } + + fn serialize_entry(&mut self, key: &K, value: &V) -> Result<(), E> + where + K: ?Sized + Serialize, + V: ?Sized + Serialize, + { + let key = tri!(key.serialize(ContentSerializer::::new())); + let value = tri!(value.serialize(ContentSerializer::::new())); + self.entries.push((key, value)); + Ok(()) + } + } + + pub struct SerializeStruct { + name: &'static str, + fields: Vec<(&'static str, Content)>, + error: PhantomData, + } + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl ser::SerializeStruct for SerializeStruct + where + E: ser::Error, + { + type Ok = Content; + type Error = E; + + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), E> + where + T: ?Sized + Serialize, + { + let value = tri!(value.serialize(ContentSerializer::::new())); + self.fields.push((key, value)); + Ok(()) + } + + fn end(self) -> Result { + Ok(Content::Struct(self.name, self.fields)) + } + } + + pub struct SerializeStructVariant { + name: &'static str, + variant_index: u32, + variant: &'static str, + fields: Vec<(&'static str, Content)>, + error: PhantomData, + } + + #[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)] + impl ser::SerializeStructVariant for SerializeStructVariant + where + E: ser::Error, + { + type Ok = Content; + type Error = E; + + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), E> + where + T: ?Sized + Serialize, + { + let value = tri!(value.serialize(ContentSerializer::::new())); + self.fields.push((key, value)); + Ok(()) + } + + fn end(self) -> Result { + Ok(Content::StructVariant( + self.name, + self.variant_index, + self.variant, + self.fields, + )) + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +pub struct FlatMapSerializer<'a, M: 'a>(pub &'a mut M); + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, M> FlatMapSerializer<'a, M> +where + M: SerializeMap + 'a, +{ + fn bad_type(what: Unsupported) -> M::Error { + ser::Error::custom(format_args!( + "can only flatten structs and maps (got {})", + what + )) + } +} + +#[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, +{ + type Ok = (); + type Error = M::Error; + + type SerializeSeq = Impossible; + type SerializeTuple = Impossible; + type SerializeTupleStruct = Impossible; + type SerializeMap = FlatMapSerializeMap<'a, M>; + type SerializeStruct = FlatMapSerializeStruct<'a, M>; + type SerializeTupleVariant = FlatMapSerializeTupleVariantAsMapValue<'a, M>; + type SerializeStructVariant = FlatMapSerializeStructVariantAsMapValue<'a, M>; + + fn serialize_bool(self, _: bool) -> Result { + Err(Self::bad_type(Unsupported::Boolean)) + } + + fn serialize_i8(self, _: i8) -> Result { + Err(Self::bad_type(Unsupported::Integer)) + } + + fn serialize_i16(self, _: i16) -> Result { + Err(Self::bad_type(Unsupported::Integer)) + } + + fn serialize_i32(self, _: i32) -> Result { + Err(Self::bad_type(Unsupported::Integer)) + } + + fn serialize_i64(self, _: i64) -> Result { + Err(Self::bad_type(Unsupported::Integer)) + } + + fn serialize_u8(self, _: u8) -> Result { + Err(Self::bad_type(Unsupported::Integer)) + } + + fn serialize_u16(self, _: u16) -> Result { + Err(Self::bad_type(Unsupported::Integer)) + } + + fn serialize_u32(self, _: u32) -> Result { + Err(Self::bad_type(Unsupported::Integer)) + } + + fn serialize_u64(self, _: u64) -> Result { + Err(Self::bad_type(Unsupported::Integer)) + } + + fn serialize_f32(self, _: f32) -> Result { + Err(Self::bad_type(Unsupported::Float)) + } + + fn serialize_f64(self, _: f64) -> Result { + Err(Self::bad_type(Unsupported::Float)) + } + + fn serialize_char(self, _: char) -> Result { + Err(Self::bad_type(Unsupported::Char)) + } + + fn serialize_str(self, _: &str) -> Result { + Err(Self::bad_type(Unsupported::String)) + } + + fn serialize_bytes(self, _: &[u8]) -> Result { + Err(Self::bad_type(Unsupported::ByteArray)) + } + + fn serialize_none(self) -> Result { + Ok(()) + } + + fn serialize_some(self, value: &T) -> Result + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + fn serialize_unit(self) -> Result { + Ok(()) + } + + fn serialize_unit_struct(self, _: &'static str) -> Result { + Ok(()) + } + + fn serialize_unit_variant( + self, + _: &'static str, + _: u32, + variant: &'static str, + ) -> Result { + self.0.serialize_entry(variant, &()) + } + + fn serialize_newtype_struct( + self, + _: &'static str, + value: &T, + ) -> Result + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant( + self, + _: &'static str, + _: u32, + variant: &'static str, + value: &T, + ) -> Result + where + T: ?Sized + Serialize, + { + self.0.serialize_entry(variant, value) + } + + fn serialize_seq(self, _: Option) -> Result { + Err(Self::bad_type(Unsupported::Sequence)) + } + + fn serialize_tuple(self, _: usize) -> Result { + Err(Self::bad_type(Unsupported::Tuple)) + } + + fn serialize_tuple_struct( + self, + _: &'static str, + _: usize, + ) -> Result { + Err(Self::bad_type(Unsupported::TupleStruct)) + } + + fn serialize_tuple_variant( + self, + _: &'static str, + _: u32, + variant: &'static str, + _: usize, + ) -> Result { + tri!(self.0.serialize_key(variant)); + Ok(FlatMapSerializeTupleVariantAsMapValue::new(self.0)) + } + + fn serialize_map(self, _: Option) -> Result { + Ok(FlatMapSerializeMap(self.0)) + } + + fn serialize_struct( + self, + _: &'static str, + _: usize, + ) -> Result { + Ok(FlatMapSerializeStruct(self.0)) + } + + fn serialize_struct_variant( + self, + _: &'static str, + _: u32, + inner_variant: &'static str, + _: usize, + ) -> Result { + tri!(self.0.serialize_key(inner_variant)); + Ok(FlatMapSerializeStructVariantAsMapValue::new( + self.0, + inner_variant, + )) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +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, +{ + type Ok = (); + type Error = M::Error; + + fn serialize_key(&mut self, key: &T) -> Result<(), Self::Error> + where + T: ?Sized + Serialize, + { + self.0.serialize_key(key) + } + + fn serialize_value(&mut self, value: &T) -> Result<(), Self::Error> + where + T: ?Sized + Serialize, + { + self.0.serialize_value(value) + } + + fn serialize_entry(&mut self, key: &K, value: &V) -> Result<(), Self::Error> + where + K: ?Sized + Serialize, + V: ?Sized + Serialize, + { + self.0.serialize_entry(key, value) + } + + fn end(self) -> Result<(), Self::Error> { + Ok(()) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +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, +{ + type Ok = (); + type Error = M::Error; + + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> + where + T: ?Sized + Serialize, + { + self.0.serialize_entry(key, value) + } + + fn end(self) -> Result<(), Self::Error> { + Ok(()) + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +#[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, + name: &'static str, + fields: Vec<(&'static str, Content)>, +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, M> FlatMapSerializeStructVariantAsMapValue<'a, M> +where + M: SerializeMap + 'a, +{ + fn new(map: &'a mut M, name: &'static str) -> FlatMapSerializeStructVariantAsMapValue<'a, M> { + FlatMapSerializeStructVariantAsMapValue { + 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, +{ + type Ok = (); + type Error = M::Error; + + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> + where + T: ?Sized + Serialize, + { + let value = tri!(value.serialize(ContentSerializer::::new())); + self.fields.push((key, value)); + Ok(()) + } + + fn end(self) -> Result<(), Self::Error> { + 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/third_party/crates/serde_core-1.0.229/.cargo-checksum.json b/third_party/crates/serde_core-1.0.229/.cargo-checksum.json new file mode 100644 index 0000000..4c20351 --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/.cargo-checksum.json @@ -0,0 +1 @@ +{"$comment":"This file only protects against accidental modifications. It is not a security mechanism and does not protect against malicious changes.","files":{".cargo_vcs_info.json":"7ca00590d04aedf8f24c48a1d56f7201cc12fb884918496f43534e766d406ae6","Cargo.lock":"f40b34bbb302517161d24864b7792615547087146efa895ce811d27d8a30e363","Cargo.toml":"c6049e170e4f7c2b48749fefab59db583bfac4e466cde6d0c53e4f49bc5044f7","Cargo.toml.orig":"2f3b7354d4f734e80c0e01ea399fb43c87cb393a84666f43d597f66af5450409","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"d9ca174c5818d7885265f0242d3193dd2963c2ee1da84aed8b938ec6a6990e58","build.rs":"7bc6b1eec8913ff4cd8e4b9b92cd04a82a4f38beb30a0b73a64c1e6e49f07b5f","src/crate_root.rs":"157ca402e23c32f11a4f1797c81afb5e9f08df96768012cf3e3199153aafb2dd","src/de/ignored_any.rs":"6480f2b2a83dc4764d01b2eec7309729eef2492eede2e5ee98d23a60b05198eb","src/de/impls.rs":"2f8e2ef9d343875bb996319e69feae0dee2287e2548cedd8d3c752b64812331c","src/de/mod.rs":"5ec8602d593915e0cf480b0ce67b02f6ab066dac34725237d2c7b4a6ef12a845","src/de/value.rs":"fb6fef6d23d95d516c6e1d6b5cefd8b98ba3881214a82a8a7e0a8ffbb0a12083","src/format.rs":"c85071b016df643b161859682d21ce34fa0ebf2a3bdbeeea69859da48f5d934f","src/lib.rs":"4e5c396d38ff5d9abf45b826a67ec3444654ed0802d057f46400ebe26f5879f8","src/macros.rs":"a61c9d19b210697304328e6bb9380a1de713e21042256df90a2b4553f178b0be","src/private/content.rs":"5fdfb2bb95ecc80375507acb813a4c640496385e56fc99ab448f6b19e01fcc01","src/private/doc.rs":"abe656c015267555ca26ebbcf2f4dcc52c719a0b9ade3a5ed4635b2784699b8c","src/private/mod.rs":"3bb3427ec80077b9df1853aa17681de796de0179d74871a96b88b72469de6cfc","src/private/seed.rs":"3f6e098c5bd314788370dcaf3ab0152fcd7feb6bcf36a9c51808938cd58071eb","src/private/size_hint.rs":"350694a2abaad94ca5d33958710a5bb8973a2ea1a3dcc50a41405c943761b81f","src/private/string.rs":"c1500fd4b64c24a5e45fa5f48c85c802816d6954a2999a72fc5a8861687212d4","src/ser/fmt.rs":"bd129d9f085933b76dafef6eb43ffac893c1f6484a3064dcd82faeeebc3b203c","src/ser/impls.rs":"5ee7efc439345e8665da0bd79bc06c02a0506e5fd0f3a4cf11af0c7197eaa643","src/ser/impossible.rs":"283f628d5107aa030d2e96eeb1dee187f0ac18c24d517edeb51738ab15dfb871","src/ser/mod.rs":"ec097d92c8545356961e977a4c9650361cadd1d3a243d805ae7b0e0e589ae803","src/std_error.rs":"b36fd6a2b6898770b9f1c51517eb362af115767d0f7cb4a713e1b949530ffa8a"},"package":"67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"} \ No newline at end of file diff --git a/third_party/crates/serde_core-1.0.229/.cargo_vcs_info.json b/third_party/crates/serde_core-1.0.229/.cargo_vcs_info.json new file mode 100644 index 0000000..8f3af9f --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "7fc3b4c30c94f73a96ebd1553f2b090d928fc3a8" + }, + "path_in_vcs": "serde_core" +} \ No newline at end of file diff --git a/third_party/crates/serde_core-1.0.229/BUILD.bazel b/third_party/crates/serde_core-1.0.229/BUILD.bazel new file mode 100644 index 0000000..99d5b0e --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/BUILD.bazel @@ -0,0 +1,187 @@ +############################################################################### +# @generated +# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To +# regenerate this file, run the following: +# +# bazel run @@//third_party:vendor_crates +############################################################################### + +load( + "@rules_rust//cargo:defs.bzl", + "cargo_build_script", + "cargo_toml_env_vars", +) +load("@rules_rust//rust:defs.bzl", "rust_library") + +package(default_visibility = ["//visibility:public"]) + +cargo_toml_env_vars( + name = "cargo_toml_env_vars", + src = "Cargo.toml", +) + +rust_library( + name = "serde_core", + srcs = glob( + include = ["**/*.rs"], + allow_empty = False, + ), + compile_data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + crate_features = [ + "result", + "std", + ], + crate_root = "src/lib.rs", + edition = "2021", + rustc_env_files = [ + ":cargo_toml_env_vars", + ], + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=serde_core", + "manual", + "noclippy", + "norustfmt", + ], + target_compatible_with = select({ + "@rules_rust//rust/platform:aarch64-apple-darwin": [], + "@rules_rust//rust/platform:aarch64-apple-ios": [], + "@rules_rust//rust/platform:aarch64-apple-ios-macabi": [], + "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], + "@rules_rust//rust/platform:aarch64-linux-android": [], + "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], + "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], + "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-none": [], + "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], + "@rules_rust//rust/platform:aarch64-unknown-uefi": [], + "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], + "@rules_rust//rust/platform:armv7-linux-androideabi": [], + "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:i686-apple-darwin": [], + "@rules_rust//rust/platform:i686-linux-android": [], + "@rules_rust//rust/platform:i686-pc-windows-msvc": [], + "@rules_rust//rust/platform:i686-unknown-freebsd": [], + "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], + "@rules_rust//rust/platform:loongarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:mips-unknown-linux-gnu": [], + "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv32imac-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], + "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-netbsd": [], + "@rules_rust//rust/platform:sparc64-unknown-openbsd": [], + "@rules_rust//rust/platform:thumbv6m-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabihf": [], + "@rules_rust//rust/platform:thumbv7m-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabihf": [], + "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], + "@rules_rust//rust/platform:wasm32-unknown-unknown": [], + "@rules_rust//rust/platform:wasm32-wasip1": [], + "@rules_rust//rust/platform:wasm32-wasip1-threads": [], + "@rules_rust//rust/platform:wasm32-wasip2": [], + "@rules_rust//rust/platform:x86_64-apple-darwin": [], + "@rules_rust//rust/platform:x86_64-apple-ios": [], + "@rules_rust//rust/platform:x86_64-apple-ios-macabi": [], + "@rules_rust//rust/platform:x86_64-linux-android": [], + "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], + "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], + "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], + "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-none": [], + "@rules_rust//rust/platform:x86_64-unknown-uefi": [], + "//conditions:default": ["@platforms//:incompatible"], + }), + version = "1.0.229", + deps = [ + ":build_script_build", + ], +) + +cargo_build_script( + name = "_bs", + srcs = glob( + include = ["**/*.rs"], + allow_empty = False, + ), + build_script_env_files = [ + ":cargo_toml_env_vars", + ], + compile_data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + "**/*.rs", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + crate_features = [ + "result", + "std", + ], + crate_name = "build_script_build", + crate_root = "build.rs", + data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + edition = "2021", + emit_warnings = False, + pkg_name = "serde_core", + rustc_env_files = [ + ":cargo_toml_env_vars", + ], + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=serde_core", + "manual", + "noclippy", + "norustfmt", + ], + version = "1.0.229", + visibility = ["//visibility:private"], +) + +alias( + name = "build_script_build", + actual = ":_bs", + tags = ["manual"], +) diff --git a/third_party/crates/serde_core-1.0.229/Cargo.lock b/third_party/crates/serde_core-1.0.229/Cargo.lock new file mode 100644 index 0000000..92fd397 --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/Cargo.lock @@ -0,0 +1,63 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "serde" +version = "1.0.185" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be9b6f69f1dfd54c3b568ffa45c310d6973a5e5148fd40cf515acaf38cf5bc31" + +[[package]] +name = "serde_core" +version = "1.0.229" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fac314a64dc9a36e61a9eb4261a5e9bbfbc922b27e518af97bc32b926cf967" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" diff --git a/third_party/crates/serde_core-1.0.229/Cargo.toml b/third_party/crates/serde_core-1.0.229/Cargo.toml new file mode 100644 index 0000000..68d5fb1 --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/Cargo.toml @@ -0,0 +1,87 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.56" +name = "serde_core" +version = "1.0.229" +authors = [ + "Erick Tryzelaar ", + "David Tolnay ", +] +build = "build.rs" +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Serde traits only, with no support for derive -- use the `serde` crate instead" +homepage = "https://serde.rs" +documentation = "https://docs.rs/serde_core" +readme = "README.md" +keywords = [ + "serde", + "serialization", + "no_std", +] +categories = [ + "encoding", + "no-std", + "no-std::no-alloc", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/serde-rs/serde" + +[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", +] + +[features] +alloc = [] +default = [ + "std", + "result", +] +rc = [] +result = [] +std = [] +unstable = [] + +[lib] +name = "serde_core" +path = "src/lib.rs" + +[dev-dependencies.serde] +version = "1" + +[dev-dependencies.serde_derive] +version = "1" + +[target."cfg(any())".dependencies.serde_derive] +version = "=1.0.229" diff --git a/third_party/crates/serde_core-1.0.229/Cargo.toml.orig b/third_party/crates/serde_core-1.0.229/Cargo.toml.orig new file mode 100644 index 0000000..08f87df --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/Cargo.toml.orig @@ -0,0 +1,70 @@ +[package] +name = "serde_core" +version = "1.0.229" +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.229", 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/third_party/crates/serde_core-1.0.229/LICENSE-APACHE b/third_party/crates/serde_core-1.0.229/LICENSE-APACHE new file mode 100644 index 0000000..1b5ec8b --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/third_party/crates/serde_core-1.0.229/LICENSE-MIT b/third_party/crates/serde_core-1.0.229/LICENSE-MIT new file mode 100644 index 0000000..31aa793 --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/crates/serde_core-1.0.229/README.md b/third_party/crates/serde_core-1.0.229/README.md new file mode 100644 index 0000000..94a765e --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/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/third_party/crates/serde_core-1.0.229/build.rs b/third_party/crates/serde_core-1.0.229/build.rs new file mode 100644 index 0000000..e3b8228 --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/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.71. + if minor < 71 { + 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/third_party/crates/serde_core-1.0.229/src/crate_root.rs b/third_party/crates/serde_core-1.0.229/src/crate_root.rs new file mode 100644 index 0000000..2cf75a4 --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/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/third_party/crates/serde_core-1.0.229/src/de/ignored_any.rs b/third_party/crates/serde_core-1.0.229/src/de/ignored_any.rs new file mode 100644 index 0000000..2360a17 --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/src/de/ignored_any.rs @@ -0,0 +1,238 @@ +use crate::lib::*; + +use crate::de::{ + Deserialize, Deserializer, EnumAccess, Error, MapAccess, SeqAccess, VariantAccess, Visitor, +}; + +/// An efficient way of discarding data from a deserializer. +/// +/// Think of this like `serde_json::Value` in that it can be deserialized from +/// any type, except that it does not store any information about the data that +/// gets deserialized. +/// +/// ```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`. +/// /// +/// /// For example to deserialize only the element at index 3: +/// /// +/// /// ``` +/// /// NthElement::new(3).deserialize(deserializer) +/// /// ``` +/// pub struct NthElement { +/// n: usize, +/// marker: PhantomData, +/// } +/// +/// impl NthElement { +/// pub fn new(n: usize) -> Self { +/// NthElement { +/// n: n, +/// marker: PhantomData, +/// } +/// } +/// } +/// +/// impl<'de, T> Visitor<'de> for NthElement +/// where +/// T: Deserialize<'de>, +/// { +/// type Value = T; +/// +/// fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { +/// write!( +/// formatter, +/// "a sequence in which we care about element {}", +/// self.n +/// ) +/// } +/// +/// fn visit_seq
(self, mut seq: A) -> Result +/// where +/// A: SeqAccess<'de>, +/// { +/// // Skip over the first `n` elements. +/// for i in 0..self.n { +/// // It is an error if the sequence ends before we get to element `n`. +/// if seq.next_element::()?.is_none() { +/// return Err(de::Error::invalid_length(i, &self)); +/// } +/// } +/// +/// // Deserialize the one we care about. +/// let nth = match seq.next_element()? { +/// Some(nth) => nth, +/// None => { +/// return Err(de::Error::invalid_length(self.n, &self)); +/// } +/// }; +/// +/// // Skip over any remaining elements in the sequence after `n`. +/// while let Some(IgnoredAny) = seq.next_element()? { +/// // ignore +/// } +/// +/// Ok(nth) +/// } +/// } +/// +/// impl<'de, T> DeserializeSeed<'de> for NthElement +/// where +/// T: Deserialize<'de>, +/// { +/// type Value = T; +/// +/// fn deserialize(self, deserializer: D) -> Result +/// where +/// D: Deserializer<'de>, +/// { +/// deserializer.deserialize_seq(self) +/// } +/// } +/// +/// # fn example<'de, D>(deserializer: D) -> Result<(), D::Error> +/// # where +/// # D: Deserializer<'de>, +/// # { +/// // Deserialize only the sequence element at index 3 from this deserializer. +/// // The element at index 3 is required to be a string. Elements before and +/// // after index 3 are allowed to be of any type. +/// let s: String = NthElement::new(3).deserialize(deserializer)?; +/// # Ok(()) +/// # } +/// ``` +#[derive(Copy, Clone, Debug, Default, PartialEq)] +pub struct IgnoredAny; + +impl<'de> Visitor<'de> for IgnoredAny { + type Value = IgnoredAny; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("anything at all") + } + + #[inline] + fn visit_bool(self, x: bool) -> Result { + let _ = x; + Ok(IgnoredAny) + } + + #[inline] + fn visit_i64(self, x: i64) -> Result { + let _ = x; + 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; + Ok(IgnoredAny) + } + + #[inline] + fn visit_str(self, s: &str) -> Result + where + E: Error, + { + let _ = s; + Ok(IgnoredAny) + } + + #[inline] + fn visit_none(self) -> Result { + Ok(IgnoredAny) + } + + #[inline] + fn visit_some(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + IgnoredAny::deserialize(deserializer) + } + + #[inline] + fn visit_newtype_struct(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + IgnoredAny::deserialize(deserializer) + } + + #[inline] + fn visit_unit(self) -> Result { + Ok(IgnoredAny) + } + + #[inline] + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + while let Some(IgnoredAny) = tri!(seq.next_element()) { + // Gobble + } + Ok(IgnoredAny) + } + + #[inline] + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + while let Some((IgnoredAny, IgnoredAny)) = tri!(map.next_entry()) { + // Gobble + } + Ok(IgnoredAny) + } + + #[inline] + fn visit_bytes(self, bytes: &[u8]) -> Result + where + E: Error, + { + let _ = bytes; + Ok(IgnoredAny) + } + + fn visit_enum(self, data: A) -> Result + where + A: EnumAccess<'de>, + { + tri!(data.variant::()).1.newtype_variant() + } +} + +impl<'de> Deserialize<'de> for IgnoredAny { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_ignored_any(IgnoredAny) + } +} diff --git a/third_party/crates/serde_core-1.0.229/src/de/impls.rs b/third_party/crates/serde_core-1.0.229/src/de/impls.rs new file mode 100644 index 0000000..3a1458e --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/src/de/impls.rs @@ -0,0 +1,3173 @@ +use crate::lib::*; + +use crate::de::{ + Deserialize, Deserializer, EnumAccess, Error, MapAccess, SeqAccess, Unexpected, VariantAccess, + Visitor, +}; +use crate::private::{self, InPlaceSeed}; + +#[cfg(any(feature = "std", feature = "alloc"))] +use crate::private::size_hint; + +//////////////////////////////////////////////////////////////////////////////// + +struct UnitVisitor; + +impl<'de> Visitor<'de> for UnitVisitor { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("unit") + } + + fn visit_unit(self) -> Result + where + E: Error, + { + Ok(()) + } +} + +impl<'de> Deserialize<'de> for () { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_unit(UnitVisitor) + } +} + +#[cfg(feature = "unstable")] +#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] +impl<'de> Deserialize<'de> for ! { + fn deserialize(_deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Err(Error::custom("cannot deserialize `!`")) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +struct BoolVisitor; + +impl<'de> Visitor<'de> for BoolVisitor { + type Value = bool; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a boolean") + } + + fn visit_bool(self, v: bool) -> Result + where + E: Error, + { + Ok(v) + } +} + +impl<'de> Deserialize<'de> for bool { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_bool(BoolVisitor) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +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) + } + } + + #[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) + } + } + }; + + ($primitive:ident, $deserialize:ident $($method:ident!($($val:ident : $visit:ident)*);)*) => { + impl<'de> Deserialize<'de> for $primitive { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct PrimitiveVisitor; + + impl<'de> Visitor<'de> for PrimitiveVisitor { + type Value = $primitive; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(stringify!($primitive)) + } + + $($($method!($val : $visit);)*)* + } + + deserializer.$deserialize(PrimitiveVisitor) + } + } + }; +} + +macro_rules! num_self { + ($ty:ident : $visit:ident) => { + #[inline] + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + Ok(v) + } + }; + + (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)) + } + } + }; + + (saturating $primitive:ident $ty:ident : $visit:ident) => { + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + Ok(Saturating(v)) + } + }; +} + +macro_rules! num_as_self { + ($ty:ident : $visit:ident) => { + #[inline] + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + Ok(v as Self::Value) + } + }; + + (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)) + } + } + }; + + (saturating $primitive:ident $ty:ident : $visit:ident) => { + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + Ok(Saturating(v as $primitive)) + } + }; +} + +macro_rules! num_as_copysign_self { + ($ty:ident : $visit:ident) => { + #[inline] + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + #[cfg(not(feature = "std"))] + { + Ok(v as Self::Value) + } + + #[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)) + } + } + }; +} + +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)) + } + }; + + (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)) + } + } + }; +} + +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)) + } + }; + + (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)) + } + }; + + (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)) + } + } + }; +} + +macro_rules! uint_to_self { + ($ty:ident : $visit:ident) => { + #[inline] + fn $visit(self, v: $ty) -> Result + where + E: Error, + { + Self::Value::try_from(v as u64) + .map_err(|_| Error::invalid_value(Unexpected::Unsigned(v as u64), &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 u64) { + if let Some(nonzero) = Self::Value::new(v) { + return Ok(nonzero); + } + } + Err(Error::invalid_value(Unexpected::Unsigned(v as u64), &self)) + } + }; + + (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)) + } + } + }; +} + +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); +} + +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, + )) + } + } + }; + + (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); +} + +//////////////////////////////////////////////////////////////////////////////// + +struct CharVisitor; + +impl<'de> Visitor<'de> for CharVisitor { + type Value = char; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a character") + } + + #[inline] + fn visit_char(self, v: char) -> Result + where + E: Error, + { + Ok(v) + } + + #[inline] + fn visit_str(self, v: &str) -> Result + where + E: Error, + { + let mut iter = v.chars(); + match (iter.next(), iter.next()) { + (Some(c), None) => Ok(c), + _ => Err(Error::invalid_value(Unexpected::Str(v), &self)), + } + } +} + +impl<'de> Deserialize<'de> for char { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_char(CharVisitor) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(any(feature = "std", feature = "alloc"))] +struct StringVisitor; +#[cfg(any(feature = "std", feature = "alloc"))] +struct StringInPlaceVisitor<'a>(&'a mut String); + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'de> Visitor<'de> for StringVisitor { + type Value = String; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a string") + } + + fn visit_str(self, v: &str) -> Result + where + E: Error, + { + Ok(v.to_owned()) + } + + fn visit_string(self, v: String) -> Result + where + E: Error, + { + Ok(v) + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: Error, + { + match str::from_utf8(v) { + Ok(s) => Ok(s.to_owned()), + Err(_) => Err(Error::invalid_value(Unexpected::Bytes(v), &self)), + } + } + + fn visit_byte_buf(self, v: Vec) -> Result + where + E: Error, + { + match String::from_utf8(v) { + Ok(s) => Ok(s), + Err(e) => Err(Error::invalid_value( + Unexpected::Bytes(&e.into_bytes()), + &self, + )), + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, 'de> Visitor<'de> for StringInPlaceVisitor<'a> { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a string") + } + + fn visit_str(self, v: &str) -> Result + where + E: Error, + { + self.0.clear(); + self.0.push_str(v); + Ok(()) + } + + fn visit_string(self, v: String) -> Result + where + E: Error, + { + *self.0 = v; + Ok(()) + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: Error, + { + match str::from_utf8(v) { + Ok(s) => { + self.0.clear(); + self.0.push_str(s); + Ok(()) + } + Err(_) => Err(Error::invalid_value(Unexpected::Bytes(v), &self)), + } + } + + fn visit_byte_buf(self, v: Vec) -> Result + where + E: Error, + { + match String::from_utf8(v) { + Ok(s) => { + *self.0 = s; + Ok(()) + } + Err(e) => Err(Error::invalid_value( + Unexpected::Bytes(&e.into_bytes()), + &self, + )), + } + } +} + +#[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 + D: Deserializer<'de>, + { + deserializer.deserialize_string(StringVisitor) + } + + fn deserialize_in_place(deserializer: D, place: &mut Self) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_string(StringInPlaceVisitor(place)) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +struct StrVisitor; + +impl<'a> Visitor<'a> for StrVisitor { + type Value = &'a str; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a borrowed string") + } + + fn visit_borrowed_str(self, v: &'a str) -> Result + where + E: Error, + { + Ok(v) // so easy + } + + fn visit_borrowed_bytes(self, v: &'a [u8]) -> Result + where + E: Error, + { + str::from_utf8(v).map_err(|_| Error::invalid_value(Unexpected::Bytes(v), &self)) + } +} + +impl<'de: 'a, 'a> Deserialize<'de> for &'a str { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(StrVisitor) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +struct BytesVisitor; + +impl<'a> Visitor<'a> for BytesVisitor { + type Value = &'a [u8]; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a borrowed byte array") + } + + fn visit_borrowed_bytes(self, v: &'a [u8]) -> Result + where + E: Error, + { + Ok(v) + } + + fn visit_borrowed_str(self, v: &'a str) -> Result + where + E: Error, + { + Ok(v.as_bytes()) + } +} + +impl<'de: 'a, 'a> Deserialize<'de> for &'a [u8] { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_bytes(BytesVisitor) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(any(feature = "std", all(not(no_core_cstr), feature = "alloc")))] +struct CStringVisitor; + +#[cfg(any(feature = "std", all(not(no_core_cstr), feature = "alloc")))] +impl<'de> Visitor<'de> for CStringVisitor { + type Value = CString; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("byte array") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let capacity = size_hint::cautious::(seq.size_hint()); + let mut values = Vec::::with_capacity(capacity); + + while let Some(value) = tri!(seq.next_element()) { + values.push(value); + } + + CString::new(values).map_err(Error::custom) + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: Error, + { + CString::new(v).map_err(Error::custom) + } + + fn visit_byte_buf(self, v: Vec) -> Result + where + E: Error, + { + CString::new(v).map_err(Error::custom) + } + + fn visit_str(self, v: &str) -> Result + where + E: Error, + { + CString::new(v).map_err(Error::custom) + } + + fn visit_string(self, v: String) -> Result + where + E: Error, + { + CString::new(v).map_err(Error::custom) + } +} + +#[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 + D: Deserializer<'de>, + { + deserializer.deserialize_byte_buf(CStringVisitor) + } +} + +macro_rules! forwarded_impl { + ( + $(#[$attr:meta])* + ($($id:ident),*), $ty:ty, $func:expr + ) => { + $(#[$attr])* + impl<'de $(, $id : Deserialize<'de>,)*> Deserialize<'de> for $ty { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Deserialize::deserialize(deserializer).map($func) + } + } + } +} + +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 +} + +forwarded_impl! { + (T), Reverse, Reverse +} + +//////////////////////////////////////////////////////////////////////////////// + +struct OptionVisitor { + marker: PhantomData, +} + +impl<'de, T> Visitor<'de> for OptionVisitor +where + T: Deserialize<'de>, +{ + type Value = Option; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("option") + } + + #[inline] + fn visit_unit(self) -> Result + where + E: Error, + { + Ok(None) + } + + #[inline] + fn visit_none(self) -> Result + where + E: Error, + { + Ok(None) + } + + #[inline] + fn visit_some(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + T::deserialize(deserializer).map(Some) + } + + fn __private_visit_untagged_option(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Ok(T::deserialize(deserializer).ok()) + } +} + +impl<'de, T> Deserialize<'de> for Option +where + T: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_option(OptionVisitor { + marker: PhantomData, + }) + } + + // The Some variant's repr is opaque, so we can't play cute tricks with its + // tag to have deserialize_in_place build the content in place unconditionally. + // + // FIXME: investigate whether branching on the old value being Some to + // deserialize_in_place the value is profitable (probably data-dependent?) +} + +//////////////////////////////////////////////////////////////////////////////// + +struct PhantomDataVisitor { + marker: PhantomData, +} + +impl<'de, T> Visitor<'de> for PhantomDataVisitor +where + T: ?Sized, +{ + type Value = PhantomData; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("unit") + } + + #[inline] + fn visit_unit(self) -> Result + where + E: Error, + { + Ok(PhantomData) + } +} + +impl<'de, T> Deserialize<'de> for PhantomData +where + T: ?Sized, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let visitor = PhantomDataVisitor { + marker: PhantomData, + }; + deserializer.deserialize_unit_struct("PhantomData", visitor) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! seq_impl { + ( + $(#[$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)*)*, + $($typaram: $bound1 $(+ $bound2)*,)* + { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct SeqVisitor { + marker: PhantomData<$ty>, + } + + impl<'de, T $(, $typaram)*> Visitor<'de> for SeqVisitor + where + T: Deserialize<'de> $(+ $tbound1 $(+ $tbound2)*)*, + $($typaram: $bound1 $(+ $bound2)*,)* + { + type Value = $ty; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a sequence") + } + + #[inline] + fn visit_seq(self, mut $access: A) -> Result + where + A: SeqAccess<'de>, + { + let mut values = $with_capacity; + + while let Some(value) = tri!($access.next_element()) { + $insert(&mut values, value); + } + + Ok(values) + } + } + + let visitor = SeqVisitor { marker: PhantomData }; + deserializer.deserialize_seq(visitor) + } + + fn deserialize_in_place(deserializer: D, place: &mut Self) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + struct SeqInPlaceVisitor<'a, T: 'a $(, $typaram: 'a)*>(&'a mut $ty); + + impl<'a, 'de, T $(, $typaram)*> Visitor<'de> for SeqInPlaceVisitor<'a, T $(, $typaram)*> + where + T: Deserialize<'de> $(+ $tbound1 $(+ $tbound2)*)*, + $($typaram: $bound1 $(+ $bound2)*,)* + { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a sequence") + } + + #[inline] + fn visit_seq(self, mut $access: A) -> Result + where + A: SeqAccess<'de>, + { + $clear(&mut *self.0); + $reserve(&mut *self.0, size_hint::cautious::($access.size_hint())); + + // FIXME: try to overwrite old values here? (Vec, VecDeque, LinkedList) + while let Some(value) = tri!($access.next_element()) { + $insert(&mut *self.0, value); + } + + Ok(()) + } + } + + deserializer.deserialize_seq(SeqInPlaceVisitor(place)) + } + } + } +} + +// Dummy impl of reserve +#[cfg(any(feature = "std", feature = "alloc"))] +fn nop_reserve(_seq: T, _n: usize) {} + +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::reserve, + BinaryHeap::push +); + +seq_impl!( + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + BTreeSet, + seq, + BTreeSet::clear, + BTreeSet::new(), + nop_reserve, + BTreeSet::insert +); + +seq_impl!( + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + LinkedList, + seq, + LinkedList::clear, + LinkedList::new(), + nop_reserve, + LinkedList::push_back +); + +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::reserve, + HashSet::insert +); + +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::reserve, + VecDeque::push_back +); + +//////////////////////////////////////////////////////////////////////////////// + +#[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>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct VecVisitor { + marker: PhantomData, + } + + impl<'de, T> Visitor<'de> for VecVisitor + where + T: Deserialize<'de>, + { + type Value = Vec; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a sequence") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let capacity = size_hint::cautious::(seq.size_hint()); + let mut values = Vec::::with_capacity(capacity); + + while let Some(value) = tri!(seq.next_element()) { + values.push(value); + } + + Ok(values) + } + } + + let visitor = VecVisitor { + marker: PhantomData, + }; + deserializer.deserialize_seq(visitor) + } + + fn deserialize_in_place(deserializer: D, place: &mut Self) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + struct VecInPlaceVisitor<'a, T: 'a>(&'a mut Vec); + + impl<'a, 'de, T> Visitor<'de> for VecInPlaceVisitor<'a, T> + where + T: Deserialize<'de>, + { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a sequence") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let hint = size_hint::cautious::(seq.size_hint()); + if let Some(additional) = hint.checked_sub(self.0.len()) { + self.0.reserve(additional); + } + + for i in 0..self.0.len() { + let next = { + let next_place = InPlaceSeed(&mut self.0[i]); + tri!(seq.next_element_seed(next_place)) + }; + if next.is_none() { + self.0.truncate(i); + return Ok(()); + } + } + + while let Some(value) = tri!(seq.next_element()) { + self.0.push(value); + } + + Ok(()) + } + } + + deserializer.deserialize_seq(VecInPlaceVisitor(place)) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +struct ArrayVisitor { + marker: PhantomData, +} +struct ArrayInPlaceVisitor<'a, A: 'a>(&'a mut A); + +impl ArrayVisitor { + fn new() -> Self { + ArrayVisitor { + marker: PhantomData, + } + } +} + +impl<'de, T> Visitor<'de> for ArrayVisitor<[T; 0]> { + type Value = [T; 0]; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("an empty array") + } + + #[inline] + fn visit_seq(self, _: A) -> Result + where + A: SeqAccess<'de>, + { + Ok([]) + } +} + +// Does not require T: Deserialize<'de>. +impl<'de, T> Deserialize<'de> for [T; 0] { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_tuple(0, ArrayVisitor::<[T; 0]>::new()) + } +} + +macro_rules! array_impls { + ($($len:expr => ($($n:tt)+))+) => { + $( + impl<'de, T> Visitor<'de> for ArrayVisitor<[T; $len]> + where + T: Deserialize<'de>, + { + type Value = [T; $len]; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(concat!("an array of length ", $len)) + } + + #[inline] + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + Ok([$( + match tri!(seq.next_element()) { + Some(val) => val, + None => return Err(Error::invalid_length($n, &self)), + } + ),+]) + } + } + + impl<'a, 'de, T> Visitor<'de> for ArrayInPlaceVisitor<'a, [T; $len]> + where + T: Deserialize<'de>, + { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(concat!("an array of length ", $len)) + } + + #[inline] + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let mut fail_idx = None; + for (idx, dest) in self.0[..].iter_mut().enumerate() { + if tri!(seq.next_element_seed(InPlaceSeed(dest))).is_none() { + fail_idx = Some(idx); + break; + } + } + if let Some(idx) = fail_idx { + return Err(Error::invalid_length(idx, &self)); + } + Ok(()) + } + } + + impl<'de, T> Deserialize<'de> for [T; $len] + where + T: Deserialize<'de>, + { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_tuple($len, ArrayVisitor::<[T; $len]>::new()) + } + + fn deserialize_in_place(deserializer: D, place: &mut Self) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_tuple($len, ArrayInPlaceVisitor(place)) + } + } + )+ + } +} + +array_impls! { + 1 => (0) + 2 => (0 1) + 3 => (0 1 2) + 4 => (0 1 2 3) + 5 => (0 1 2 3 4) + 6 => (0 1 2 3 4 5) + 7 => (0 1 2 3 4 5 6) + 8 => (0 1 2 3 4 5 6 7) + 9 => (0 1 2 3 4 5 6 7 8) + 10 => (0 1 2 3 4 5 6 7 8 9) + 11 => (0 1 2 3 4 5 6 7 8 9 10) + 12 => (0 1 2 3 4 5 6 7 8 9 10 11) + 13 => (0 1 2 3 4 5 6 7 8 9 10 11 12) + 14 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13) + 15 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14) + 16 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) + 17 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16) + 18 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17) + 19 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18) + 20 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19) + 21 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20) + 22 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21) + 23 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22) + 24 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23) + 25 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24) + 26 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25) + 27 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26) + 28 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27) + 29 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28) + 30 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29) + 31 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30) + 32 => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31) +} + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! tuple_impls { + ($($len:tt => ($($n:tt $name:ident)+))+) => { + $( + #[cfg_attr(docsrs, doc(hidden))] + impl<'de, $($name),+> Deserialize<'de> for ($($name,)+) + where + $($name: Deserialize<'de>,)+ + { + tuple_impl_body!($len => ($($n $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,)+)>, + } + + impl<'de, $($name: Deserialize<'de>),+> Visitor<'de> for TupleVisitor<$($name,)+> { + type Value = ($($name,)+); + + 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>, + { + $( + let $name = match tri!(seq.next_element()) { + Some(value) => value, + None => return Err(Error::invalid_length($n, &self)), + }; + )+ + + Ok(($($name,)+)) + } + } + + deserializer.deserialize_tuple($len, TupleVisitor { marker: PhantomData }) + } + + #[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,)+)); + + 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)); + } + )+ + + 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! { + 2 => (0 T0 1 T1) + 3 => (0 T0 1 T1 2 T2) + 4 => (0 T0 1 T1 2 T2 3 T3) + 5 => (0 T0 1 T1 2 T2 3 T3 4 T4) + 6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5) + 7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6) + 8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7) + 9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8) + 10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9) + 11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10) + 12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11) + 13 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12) + 14 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13) + 15 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14) + 16 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15) +} + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! map_impl { + ( + $(#[$attr:meta])* + $ty:ident , + $access:ident, + $with_capacity:expr, + ) => { + $(#[$attr])* + impl<'de, K, V $(, $typaram)*> Deserialize<'de> for $ty + where + K: Deserialize<'de> $(+ $kbound1 $(+ $kbound2)*)*, + V: Deserialize<'de>, + $($typaram: $bound1 $(+ $bound2)*),* + { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct MapVisitor { + marker: PhantomData<$ty>, + } + + impl<'de, K, V $(, $typaram)*> Visitor<'de> for MapVisitor + where + K: Deserialize<'de> $(+ $kbound1 $(+ $kbound2)*)*, + V: Deserialize<'de>, + $($typaram: $bound1 $(+ $bound2)*),* + { + type Value = $ty; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a map") + } + + #[inline] + fn visit_map(self, mut $access: A) -> Result + where + A: MapAccess<'de>, + { + let mut values = $with_capacity; + + while let Some((key, value)) = tri!($access.next_entry()) { + values.insert(key, value); + } + + Ok(values) + } + } + + let visitor = MapVisitor { marker: PhantomData }; + deserializer.deserialize_map(visitor) + } + } + } +} + +map_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + BTreeMap, + map, + BTreeMap::new(), +} + +map_impl! { + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + HashMap, + map, + HashMap::with_capacity_and_hasher(size_hint::cautious::<(K, V)>(map.size_hint()), S::default()), +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(any(feature = "std", not(no_core_net)))] +macro_rules! parse_ip_impl { + ($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() { + deserializer.deserialize_str(FromStrVisitor::new($expecting)) + } else { + <[u8; $size]>::deserialize(deserializer).map(<$ty>::from) + } + } + } + }; +} + +#[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 + ) => { + enum $name_kind { + $($variant),* + } + + static $variants_name: &[&str] = &[$(stringify!($variant)),*]; + + impl<'de> Deserialize<'de> for $name_kind { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct KindVisitor; + + impl<'de> Visitor<'de> for KindVisitor { + type Value = $name_kind; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str($expecting_message) + } + + fn visit_u64(self, value: u64) -> Result + where + E: Error, + { + match value { + $( + $index => Ok($name_kind :: $variant), + )* + _ => Err(Error::invalid_value(Unexpected::Unsigned(value), &self),), + } + } + + fn visit_str(self, value: &str) -> Result + where + E: Error, + { + match value { + $( + stringify!($variant) => Ok($name_kind :: $variant), + )* + _ => Err(Error::unknown_variant(value, $variants_name)), + } + } + + fn visit_bytes(self, value: &[u8]) -> Result + where + E: Error, + { + match value { + $( + $bytes => Ok($name_kind :: $variant), + )* + _ => { + match str::from_utf8(value) { + Ok(value) => Err(Error::unknown_variant(value, $variants_name)), + Err(_) => Err(Error::invalid_value(Unexpected::Bytes(value), &self)), + } + } + } + } + } + + deserializer.deserialize_identifier(KindVisitor) + } + } + } +} + +#[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 + ) => { + variant_identifier! { + $name_kind ($($variant; $bytes; $index),*) + $expecting_message, + VARIANTS + } + + struct EnumVisitor; + impl<'de> Visitor<'de> for EnumVisitor { + type Value = $name; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(concat!("a ", stringify!($name))) + } + + + fn visit_enum(self, data: A) -> Result + where + A: EnumAccess<'de>, + { + match tri!(data.variant()) { + $( + ($name_kind :: $variant, v) => v.newtype_variant().map($name :: $variant), + )* + } + } + } + $deserializer.deserialize_enum(stringify!($name), VARIANTS, EnumVisitor) + } +} + +#[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() { + deserializer.deserialize_str(FromStrVisitor::new("IP address")) + } else { + use crate::lib::net::IpAddr; + deserialize_enum! { + IpAddr IpAddrKind (V4; b"V4"; 0, V6; b"V6"; 1) + "`V4` or `V6`", + deserializer + } + } + } +} + +#[cfg(any(feature = "std", not(no_core_net)))] +parse_ip_impl!(net::Ipv4Addr, "IPv4 address", 4); + +#[cfg(any(feature = "std", not(no_core_net)))] +parse_ip_impl!(net::Ipv6Addr, "IPv6 address", 16); + +#[cfg(any(feature = "std", not(no_core_net)))] +macro_rules! parse_socket_impl { + ( + $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() { + deserializer.deserialize_str(FromStrVisitor::new($expecting)) + } else { + <(_, u16)>::deserialize(deserializer).map($new) + } + } + } + }; +} + +#[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() { + deserializer.deserialize_str(FromStrVisitor::new("socket address")) + } else { + use crate::lib::net::SocketAddr; + deserialize_enum! { + SocketAddr SocketAddrKind (V4; b"V4"; 0, V6; b"V6"; 1) + "`V4` or `V6`", + deserializer + } + } + } +} + +#[cfg(any(feature = "std", not(no_core_net)))] +parse_socket_impl! { + net::SocketAddrV4, "IPv4 socket address", + |(ip, port)| net::SocketAddrV4::new(ip, port), +} + +#[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), +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "std")] +struct PathVisitor; + +#[cfg(feature = "std")] +impl<'a> Visitor<'a> for PathVisitor { + type Value = &'a Path; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a borrowed path") + } + + fn visit_borrowed_str(self, v: &'a str) -> Result + where + E: Error, + { + Ok(v.as_ref()) + } + + fn visit_borrowed_bytes(self, v: &'a [u8]) -> Result + where + E: Error, + { + str::from_utf8(v) + .map(AsRef::as_ref) + .map_err(|_| Error::invalid_value(Unexpected::Bytes(v), &self)) + } +} + +#[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 + D: Deserializer<'de>, + { + deserializer.deserialize_str(PathVisitor) + } +} + +#[cfg(feature = "std")] +struct PathBufVisitor; + +#[cfg(feature = "std")] +impl<'de> Visitor<'de> for PathBufVisitor { + type Value = PathBuf; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("path string") + } + + fn visit_str(self, v: &str) -> Result + where + E: Error, + { + Ok(From::from(v)) + } + + fn visit_string(self, v: String) -> Result + where + E: Error, + { + Ok(From::from(v)) + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: Error, + { + str::from_utf8(v) + .map(From::from) + .map_err(|_| Error::invalid_value(Unexpected::Bytes(v), &self)) + } + + fn visit_byte_buf(self, v: Vec) -> Result + where + E: Error, + { + String::from_utf8(v) + .map(From::from) + .map_err(|e| Error::invalid_value(Unexpected::Bytes(&e.into_bytes()), &self)) + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl<'de> Deserialize<'de> for PathBuf { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_string(PathBufVisitor) + } +} + +forwarded_impl! { + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + (), Box, PathBuf::into_boxed_path +} + +//////////////////////////////////////////////////////////////////////////////// + +// If this were outside of the serde crate, it would just use: +// +// #[derive(Deserialize)] +// #[serde(variant_identifier)] +#[cfg(all(feature = "std", any(unix, windows)))] +variant_identifier! { + OsStringKind (Unix; b"Unix"; 0, Windows; b"Windows"; 1) + "`Unix` or `Windows`", + OSSTR_VARIANTS +} + +#[cfg(all(feature = "std", any(unix, windows)))] +struct OsStringVisitor; + +#[cfg(all(feature = "std", any(unix, windows)))] +impl<'de> Visitor<'de> for OsStringVisitor { + type Value = OsString; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("os string") + } + + #[cfg(unix)] + fn visit_enum(self, data: A) -> Result + where + A: EnumAccess<'de>, + { + use std::os::unix::ffi::OsStringExt; + + 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", + )), + } + } + + #[cfg(windows)] + fn visit_enum(self, data: A) -> Result + where + A: EnumAccess<'de>, + { + use std::os::windows::ffi::OsStringExt; + + match tri!(data.variant()) { + (OsStringKind::Windows, v) => v + .newtype_variant::>() + .map(|vec| OsString::from_wide(&vec)), + (OsStringKind::Unix, _) => Err(Error::custom( + "cannot deserialize Unix OS string on Windows", + )), + } + } +} + +#[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 + D: Deserializer<'de>, + { + deserializer.deserialize_enum("OsString", OSSTR_VARIANTS, OsStringVisitor) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +forwarded_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + (T), Box, Box::new +} + +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 +} + +forwarded_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + (), Box, String::into_boxed_str +} + +forwarded_impl! { + #[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"))] +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] +impl<'de, 'a, T> Deserialize<'de> for Cow<'a, T> +where + T: ?Sized + ToOwned, + T::Owned: Deserialize<'de>, +{ + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + T::Owned::deserialize(deserializer).map(Cow::Owned) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// This impl requires the [`"rc"`] Cargo feature of Serde. The resulting +/// `Weak` has a reference count of 0 and cannot be upgraded. +/// +/// [`"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")))) +)] +impl<'de, T> Deserialize<'de> for RcWeak +where + T: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + tri!(Option::::deserialize(deserializer)); + Ok(RcWeak::new()) + } +} + +/// This impl requires the [`"rc"`] Cargo feature of Serde. The resulting +/// `Weak` has a reference count of 0 and cannot be upgraded. +/// +/// [`"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")))) +)] +impl<'de, T> Deserialize<'de> for ArcWeak +where + T: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + tri!(Option::::deserialize(deserializer)); + Ok(ArcWeak::new()) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! box_forwarded_impl { + ( + $(#[$attr:meta])* + $t:ident + ) => { + $(#[$attr])* + impl<'de, T> Deserialize<'de> for $t + where + T: ?Sized, + Box: Deserialize<'de>, + { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Box::deserialize(deserializer).map(Into::into) + } + } + }; +} + +box_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 + #[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))))] + Rc +} + +box_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 + #[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))))] + Arc +} + +//////////////////////////////////////////////////////////////////////////////// + +impl<'de, T> Deserialize<'de> for Cell +where + T: Deserialize<'de> + Copy, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + T::deserialize(deserializer).map(Cell::new) + } +} + +forwarded_impl! { + (T), RefCell, RefCell::new +} + +forwarded_impl! { + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + (T), Mutex, Mutex::new +} + +forwarded_impl! { + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + (T), RwLock, RwLock::new +} + +//////////////////////////////////////////////////////////////////////////////// + +// This is a cleaned-up version of the impl generated by: +// +// #[derive(Deserialize)] +// #[serde(deny_unknown_fields)] +// struct Duration { +// secs: u64, +// nanos: u32, +// } +impl<'de> Deserialize<'de> for Duration { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + // If this were outside of the serde crate, it would just use: + // + // #[derive(Deserialize)] + // #[serde(field_identifier, rename_all = "lowercase")] + enum Field { + Secs, + Nanos, + } + + 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("`secs` or `nanos`") + } + + fn visit_str(self, value: &str) -> Result + where + E: Error, + { + match value { + "secs" => Ok(Field::Secs), + "nanos" => Ok(Field::Nanos), + _ => Err(Error::unknown_field(value, FIELDS)), + } + } + + fn visit_bytes(self, value: &[u8]) -> Result + where + E: Error, + { + match value { + b"secs" => Ok(Field::Secs), + b"nanos" => Ok(Field::Nanos), + _ => { + let value = private::string::from_utf8_lossy(value); + Err(Error::unknown_field(&*value, FIELDS)) + } + } + } + } + + deserializer.deserialize_identifier(FieldVisitor) + } + } + + 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 { + type Value = Duration; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("struct Duration") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let secs: u64 = match tri!(seq.next_element()) { + Some(value) => value, + None => { + return Err(Error::invalid_length(0, &self)); + } + }; + 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)) + } + + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + let mut secs: Option = None; + let mut nanos: Option = None; + while let Some(key) = tri!(map.next_key()) { + match key { + Field::Secs => { + if secs.is_some() { + return Err(::duplicate_field("secs")); + } + secs = Some(tri!(map.next_value())); + } + Field::Nanos => { + if nanos.is_some() { + return Err(::duplicate_field("nanos")); + } + nanos = Some(tri!(map.next_value())); + } + } + } + let secs = match secs { + Some(secs) => secs, + None => return Err(::missing_field("secs")), + }; + let nanos = match nanos { + Some(nanos) => nanos, + None => return Err(::missing_field("nanos")), + }; + tri!(check_overflow(secs, nanos)); + Ok(Duration::new(secs, nanos)) + } + } + + const FIELDS: &[&str] = &["secs", "nanos"]; + deserializer.deserialize_struct("Duration", FIELDS, DurationVisitor) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl<'de> Deserialize<'de> for SystemTime { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + // Reuse duration + enum Field { + Secs, + Nanos, + } + + 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("`secs_since_epoch` or `nanos_since_epoch`") + } + + fn visit_str(self, value: &str) -> Result + where + E: Error, + { + match value { + "secs_since_epoch" => Ok(Field::Secs), + "nanos_since_epoch" => Ok(Field::Nanos), + _ => Err(Error::unknown_field(value, FIELDS)), + } + } + + fn visit_bytes(self, value: &[u8]) -> Result + where + E: Error, + { + match value { + b"secs_since_epoch" => Ok(Field::Secs), + b"nanos_since_epoch" => Ok(Field::Nanos), + _ => { + let value = String::from_utf8_lossy(value); + Err(Error::unknown_field(&value, FIELDS)) + } + } + } + } + + deserializer.deserialize_identifier(FieldVisitor) + } + } + + 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 { + type Value = Duration; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("struct SystemTime") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let secs: u64 = match tri!(seq.next_element()) { + Some(value) => value, + None => { + return Err(Error::invalid_length(0, &self)); + } + }; + 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)) + } + + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + let mut secs: Option = None; + let mut nanos: Option = None; + while let Some(key) = tri!(map.next_key()) { + match key { + Field::Secs => { + if secs.is_some() { + return Err(::duplicate_field( + "secs_since_epoch", + )); + } + secs = Some(tri!(map.next_value())); + } + Field::Nanos => { + if nanos.is_some() { + return Err(::duplicate_field( + "nanos_since_epoch", + )); + } + nanos = Some(tri!(map.next_value())); + } + } + } + let secs = match secs { + Some(secs) => secs, + None => return Err(::missing_field("secs_since_epoch")), + }; + let nanos = match nanos { + Some(nanos) => nanos, + None => return Err(::missing_field("nanos_since_epoch")), + }; + tri!(check_overflow(secs, nanos)); + Ok(Duration::new(secs, nanos)) + } + } + + 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")) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +// Similar to: +// +// #[derive(Deserialize)] +// #[serde(deny_unknown_fields)] +// struct Range { +// start: Idx, +// end: Idx, +// } +impl<'de, Idx> Deserialize<'de> for Range +where + Idx: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let (start, end) = tri!(deserializer.deserialize_struct( + "Range", + range::FIELDS, + range::RangeVisitor { + expecting: "struct Range", + phantom: PhantomData, + }, + )); + Ok(start..end) + } +} + +impl<'de, Idx> Deserialize<'de> for RangeInclusive +where + Idx: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + 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 crate::lib::*; + + use crate::de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor}; + use crate::private; + + pub const FIELDS: &[&str] = &["start", "end"]; + + // If this were outside of the serde crate, it would just use: + // + // #[derive(Deserialize)] + // #[serde(field_identifier, rename_all = "lowercase")] + enum Field { + Start, + 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("`start` or `end`") + } + + fn visit_str(self, value: &str) -> Result + where + E: Error, + { + match value { + "start" => Ok(Field::Start), + "end" => Ok(Field::End), + _ => Err(Error::unknown_field(value, FIELDS)), + } + } + + fn visit_bytes(self, value: &[u8]) -> Result + where + E: Error, + { + match value { + b"start" => Ok(Field::Start), + 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 RangeVisitor { + pub expecting: &'static str, + pub phantom: PhantomData, + } + + impl<'de, Idx> Visitor<'de> for RangeVisitor + where + Idx: Deserialize<'de>, + { + type Value = (Idx, 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)); + } + }; + let end: Idx = match tri!(seq.next_element()) { + Some(value) => value, + None => { + return Err(Error::invalid_length(1, &self)); + } + }; + Ok((start, end)) + } + + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + let mut start: Option = None; + let mut end: 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())); + } + Field::End => { + if end.is_some() { + return Err(::duplicate_field("end")); + } + end = Some(tri!(map.next_value())); + } + } + } + let start = match start { + Some(start) => start, + None => return Err(::missing_field("start")), + }; + let end = match end { + Some(end) => end, + None => return Err(::missing_field("end")), + }; + Ok((start, end)) + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +// 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>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + enum Field { + Unbounded, + Included, + Excluded, + } + + impl<'de> Deserialize<'de> for Field { + #[inline] + 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("`Unbounded`, `Included` or `Excluded`") + } + + fn visit_u64(self, value: u64) -> Result + where + E: Error, + { + match value { + 0 => Ok(Field::Unbounded), + 1 => Ok(Field::Included), + 2 => Ok(Field::Excluded), + _ => Err(Error::invalid_value(Unexpected::Unsigned(value), &self)), + } + } + + fn visit_str(self, value: &str) -> Result + where + E: Error, + { + match value { + "Unbounded" => Ok(Field::Unbounded), + "Included" => Ok(Field::Included), + "Excluded" => Ok(Field::Excluded), + _ => Err(Error::unknown_variant(value, VARIANTS)), + } + } + + fn visit_bytes(self, value: &[u8]) -> Result + where + E: Error, + { + match value { + b"Unbounded" => Ok(Field::Unbounded), + b"Included" => Ok(Field::Included), + b"Excluded" => Ok(Field::Excluded), + _ => match str::from_utf8(value) { + Ok(value) => Err(Error::unknown_variant(value, VARIANTS)), + Err(_) => { + Err(Error::invalid_value(Unexpected::Bytes(value), &self)) + } + }, + } + } + } + + deserializer.deserialize_identifier(FieldVisitor) + } + } + + struct BoundVisitor(PhantomData>); + + impl<'de, T> Visitor<'de> for BoundVisitor + where + T: Deserialize<'de>, + { + type Value = Bound; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("enum Bound") + } + + fn visit_enum(self, data: A) -> Result + where + A: EnumAccess<'de>, + { + 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), + } + } + } + + const VARIANTS: &[&str] = &["Unbounded", "Included", "Excluded"]; + + deserializer.deserialize_enum("Bound", VARIANTS, BoundVisitor(PhantomData)) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "result")] +#[cfg_attr(docsrs, doc(cfg(feature = "result")))] +impl<'de, T, E> Deserialize<'de> for Result +where + T: Deserialize<'de>, + E: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + // If this were outside of the serde crate, it would just use: + // + // #[derive(Deserialize)] + // #[serde(variant_identifier)] + enum Field { + Ok, + Err, + } + + impl<'de> Deserialize<'de> for Field { + #[inline] + 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("`Ok` or `Err`") + } + + fn visit_u64(self, value: u64) -> Result + where + E: Error, + { + match value { + 0 => Ok(Field::Ok), + 1 => Ok(Field::Err), + _ => Err(Error::invalid_value(Unexpected::Unsigned(value), &self)), + } + } + + fn visit_str(self, value: &str) -> Result + where + E: Error, + { + match value { + "Ok" => Ok(Field::Ok), + "Err" => Ok(Field::Err), + _ => Err(Error::unknown_variant(value, VARIANTS)), + } + } + + fn visit_bytes(self, value: &[u8]) -> Result + where + E: Error, + { + match value { + b"Ok" => Ok(Field::Ok), + b"Err" => Ok(Field::Err), + _ => match str::from_utf8(value) { + Ok(value) => Err(Error::unknown_variant(value, VARIANTS)), + Err(_) => { + Err(Error::invalid_value(Unexpected::Bytes(value), &self)) + } + }, + } + } + } + + deserializer.deserialize_identifier(FieldVisitor) + } + } + + struct ResultVisitor(PhantomData>); + + impl<'de, T, E> Visitor<'de> for ResultVisitor + where + T: Deserialize<'de>, + E: Deserialize<'de>, + { + type Value = Result; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("enum Result") + } + + fn visit_enum(self, data: A) -> Result + where + A: EnumAccess<'de>, + { + match tri!(data.variant()) { + (Field::Ok, v) => v.newtype_variant().map(Ok), + (Field::Err, v) => v.newtype_variant().map(Err), + } + } + } + + const VARIANTS: &[&str] = &["Ok", "Err"]; + + deserializer.deserialize_enum("Result", VARIANTS, ResultVisitor(PhantomData)) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl<'de, T> Deserialize<'de> for Wrapping +where + T: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Deserialize::deserialize(deserializer).map(Wrapping) + } +} + +#[cfg(all(feature = "std", not(no_std_atomic)))] +macro_rules! atomic_impl { + ($($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 + D: Deserializer<'de>, + { + Deserialize::deserialize(deserializer).map(Self::new) + } + } + )* + }; +} + +#[cfg(all(feature = "std", not(no_std_atomic)))] +atomic_impl! { + 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(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/third_party/crates/serde_core-1.0.229/src/de/mod.rs b/third_party/crates/serde_core-1.0.229/src/de/mod.rs new file mode 100644 index 0000000..2518ae6 --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/src/de/mod.rs @@ -0,0 +1,2392 @@ +//! Generic data structure deserialization framework. +//! +//! The two most important traits in this module are [`Deserialize`] and +//! [`Deserializer`]. +//! +//! - **A type that implements `Deserialize` is a data structure** that can be +//! deserialized from any data format supported by Serde, and conversely +//! - **A type that implements `Deserializer` is a data format** that can +//! deserialize any data structure supported by Serde. +//! +//! # The Deserialize trait +//! +//! Serde provides [`Deserialize`] implementations for many Rust primitive and +//! standard library types. The complete list is below. 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 +//! in your program. See the [derive section of the manual] for how to use this. +//! +//! In rare cases it may be necessary to implement [`Deserialize`] manually for +//! some type in your program. See the [Implementing `Deserialize`] section of +//! the manual for more about this. +//! +//! Third-party crates may provide [`Deserialize`] implementations for types +//! that they expose. For example the [`linked-hash-map`] crate provides a +//! [`LinkedHashMap`] type that is deserializable by Serde because the +//! crate provides an implementation of [`Deserialize`] for it. +//! +//! # The Deserializer trait +//! +//! [`Deserializer`] implementations are provided by third-party crates, for +//! example [`serde_json`], [`serde_yaml`] and [`postcard`]. +//! +//! A partial list of well-maintained formats is given on the [Serde +//! website][data formats]. +//! +//! # Implementations of Deserialize provided by Serde +//! +//! This is a slightly different set of types than what is supported for +//! serialization. Some types can be serialized by Serde but not deserialized. +//! One example is `OsStr`. +//! +//! - **Primitive types**: +//! - bool +//! - i8, i16, i32, i64, i128, isize +//! - u8, u16, u32, u64, u128, usize +//! - f32, f64 +//! - char +//! - **Compound types**: +//! - \[T; 0\] through \[T; 32\] +//! - tuples up to size 16 +//! - **Common standard library types**: +//! - String +//! - Option\ +//! - Result\ +//! - PhantomData\ +//! - **Wrapper types**: +//! - Box\ +//! - Box\<\[T\]\> +//! - Box\ +//! - Cow\<'a, T\> +//! - Cell\ +//! - RefCell\ +//! - Mutex\ +//! - RwLock\ +//! - Rc\ *(if* features = \["rc"\] *is enabled)* +//! - Arc\ *(if* features = \["rc"\] *is enabled)* +//! - **Collection types**: +//! - BTreeMap\ +//! - BTreeSet\ +//! - BinaryHeap\ +//! - HashMap\ +//! - HashSet\ +//! - LinkedList\ +//! - VecDeque\ +//! - Vec\ +//! - **Zero-copy types**: +//! - &str +//! - &\[u8\] +//! - **FFI types**: +//! - CString +//! - Box\ +//! - OsString +//! - **Miscellaneous standard library types**: +//! - Duration +//! - SystemTime +//! - Path +//! - PathBuf +//! - Range\ +//! - RangeInclusive\ +//! - Bound\ +//! - num::NonZero* +//! - `!` *(unstable)* +//! - **Net types**: +//! - IpAddr +//! - Ipv4Addr +//! - Ipv6Addr +//! - SocketAddr +//! - SocketAddrV4 +//! - SocketAddrV6 +//! +//! [Implementing `Deserialize`]: https://serde.rs/impl-deserialize.html +//! [`Deserialize`]: crate::Deserialize +//! [`Deserializer`]: crate::Deserializer +//! [`LinkedHashMap`]: https://docs.rs/linked-hash-map/*/linked_hash_map/struct.LinkedHashMap.html +//! [`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 +//! [`serde_yaml`]: https://github.com/dtolnay/serde-yaml +//! [derive section of the manual]: https://serde.rs/derive.html +//! [data formats]: https://serde.rs/#data-formats + +use crate::lib::*; + +//////////////////////////////////////////////////////////////////////////////// + +pub mod value; + +mod ignored_any; +mod impls; + +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; + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! declare_error_trait { + (Error: Sized $(+ $($supertrait:ident)::+)*) => { + /// The `Error` trait allows `Deserialize` implementations to create descriptive + /// error messages belonging to the `Deserializer` against which they are + /// currently running. + /// + /// Every `Deserializer` declares an `Error` type that encompasses both + /// general-purpose deserialization errors as well as errors specific to the + /// particular deserialization format. For example the `Error` type of + /// `serde_json` can represent errors like an invalid JSON escape sequence or an + /// unterminated string literal, in addition to the error cases that are part of + /// this trait. + /// + /// Most deserializers should only need to provide the `Error::custom` method + /// and inherit the default behavior for the other methods. + /// + /// # Example implementation + /// + /// The [example data format] presented on the website shows an error + /// 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. + /// + /// ```edition2021 + /// # use std::str::FromStr; + /// # + /// # struct IpAddr; + /// # + /// # impl FromStr for IpAddr { + /// # type Err = String; + /// # + /// # fn from_str(_: &str) -> Result { + /// # unimplemented!() + /// # } + /// # } + /// # + /// use serde::de::{self, Deserialize, Deserializer}; + /// + /// impl<'de> Deserialize<'de> for IpAddr { + /// fn deserialize(deserializer: D) -> Result + /// where + /// D: Deserializer<'de>, + /// { + /// let s = String::deserialize(deserializer)?; + /// s.parse().map_err(de::Error::custom) + /// } + /// } + /// ``` + fn custom(msg: T) -> Self + where + T: Display; + + /// Raised when a `Deserialize` receives a type different from what it was + /// expecting. + /// + /// The `unexp` argument provides information about what type was received. + /// This is the type that was present in the input file or other source data + /// of the Deserializer. + /// + /// The `exp` argument provides information about what type was being + /// expected. This is the type that is written in the program. + /// + /// For example if we try to deserialize a String out of a JSON file + /// containing an integer, the unexpected type is the integer and the + /// expected type is the string. + #[cold] + fn invalid_type(unexp: Unexpected, exp: &dyn Expected) -> Self { + Error::custom(format_args!("invalid type: {}, expected {}", unexp, exp)) + } + + /// Raised when a `Deserialize` receives a value of the right type but that + /// is wrong for some other reason. + /// + /// The `unexp` argument provides information about what value was received. + /// This is the value that was present in the input file or other source + /// data of the Deserializer. + /// + /// The `exp` argument provides information about what value was being + /// expected. This is the type that is written in the program. + /// + /// For example if we try to deserialize a String out of some binary data + /// 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: &dyn Expected) -> Self { + Error::custom(format_args!("invalid value: {}, expected {}", unexp, exp)) + } + + /// Raised when deserializing a sequence or map and the input data contains + /// too many or too few elements. + /// + /// The `len` argument is the number of elements encountered. The sequence + /// or map may have expected more arguments or fewer arguments. + /// + /// The `exp` argument provides information about what data was being + /// expected. For example `exp` might say that a tuple of size 6 was + /// expected. + #[cold] + fn invalid_length(len: usize, exp: &dyn Expected) -> Self { + Error::custom(format_args!("invalid length {}, expected {}", len, exp)) + } + + /// Raised when a `Deserialize` enum type received a variant with an + /// unrecognized name. + #[cold] + fn unknown_variant(variant: &str, expected: &'static [&'static str]) -> Self { + if expected.is_empty() { + Error::custom(format_args!( + "unknown variant `{}`, there are no variants", + variant + )) + } else { + Error::custom(format_args!( + "unknown variant `{}`, expected {}", + variant, + OneOf { names: expected } + )) + } + } + + /// Raised when a `Deserialize` struct type received a field with an + /// unrecognized name. + #[cold] + fn unknown_field(field: &str, expected: &'static [&'static str]) -> Self { + if expected.is_empty() { + Error::custom(format_args!( + "unknown field `{}`, there are no fields", + field + )) + } else { + Error::custom(format_args!( + "unknown field `{}`, expected {}", + field, + OneOf { names: expected } + )) + } + } + + /// Raised when a `Deserialize` struct type expected to receive a required + /// field with a particular name but that field was not present in the + /// input. + #[cold] + fn missing_field(field: &'static str) -> Self { + Error::custom(format_args!("missing field `{}`", field)) + } + + /// Raised when a `Deserialize` struct type received more than one of the + /// same field. + #[cold] + fn duplicate_field(field: &'static str) -> Self { + Error::custom(format_args!("duplicate field `{}`", field)) + } + } + } +} + +#[cfg(feature = "std")] +declare_error_trait!(Error: Sized + StdError); + +#[cfg(not(feature = "std"))] +declare_error_trait!(Error: Sized + Debug + Display); + +/// `Unexpected` represents an unexpected invocation of any one of the `Visitor` +/// trait methods. +/// +/// This is used as an argument to the `invalid_type`, `invalid_value`, and +/// `invalid_length` methods of the `Error` trait to build error messages. +/// +/// ```edition2021 +/// # use std::fmt; +/// # +/// # use serde::de::{self, Unexpected, Visitor}; +/// # +/// # struct Example; +/// # +/// # impl<'de> Visitor<'de> for Example { +/// # type Value = (); +/// # +/// # fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { +/// # write!(formatter, "definitely not a boolean") +/// # } +/// # +/// fn visit_bool(self, v: bool) -> Result +/// where +/// E: de::Error, +/// { +/// Err(de::Error::invalid_type(Unexpected::Bool(v), &self)) +/// } +/// # } +/// ``` +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum Unexpected<'a> { + /// The input contained a boolean value that was not expected. + Bool(bool), + + /// The input contained an unsigned integer `u8`, `u16`, `u32` or `u64` that + /// was not expected. + Unsigned(u64), + + /// The input contained a signed integer `i8`, `i16`, `i32` or `i64` that + /// was not expected. + Signed(i64), + + /// The input contained a floating point `f32` or `f64` that was not + /// expected. + Float(f64), + + /// The input contained a `char` that was not expected. + Char(char), + + /// The input contained a `&str` or `String` that was not expected. + Str(&'a str), + + /// The input contained a `&[u8]` or `Vec` that was not expected. + Bytes(&'a [u8]), + + /// The input contained a unit `()` that was not expected. + Unit, + + /// The input contained an `Option` that was not expected. + Option, + + /// The input contained a newtype struct that was not expected. + NewtypeStruct, + + /// The input contained a sequence that was not expected. + Seq, + + /// The input contained a map that was not expected. + Map, + + /// The input contained an enum that was not expected. + Enum, + + /// The input contained a unit variant that was not expected. + UnitVariant, + + /// The input contained a newtype variant that was not expected. + NewtypeVariant, + + /// The input contained a tuple variant that was not expected. + TupleVariant, + + /// The input contained a struct variant that was not expected. + StructVariant, + + /// A message stating what uncategorized thing the input contained that was + /// not expected. + /// + /// The message should be a noun or noun phrase, not capitalized and without + /// a period. An example message is "unoriginal superhero". + Other(&'a str), +} + +impl<'a> fmt::Display for Unexpected<'a> { + 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 `{}`", WithDecimalPoint(f)), + Char(c) => write!(formatter, "character `{}`", c), + Str(s) => write!(formatter, "string {:?}", s), + 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), + } + } +} + +/// `Expected` represents an explanation of what data a `Visitor` was expecting +/// to receive. +/// +/// This is used as an argument to the `invalid_type`, `invalid_value`, and +/// `invalid_length` methods of the `Error` trait to build error messages. The +/// message should be a noun or noun phrase that completes the sentence "This +/// Visitor expects to receive ...", for example the message could be "an +/// integer between 0 and 64". The message should not be capitalized and should +/// not end with a period. +/// +/// Within the context of a `Visitor` implementation, the `Visitor` itself +/// (`&self`) is an implementation of this trait. +/// +/// ```edition2021 +/// # use serde::de::{self, Unexpected, Visitor}; +/// # use std::fmt; +/// # +/// # struct Example; +/// # +/// # impl<'de> Visitor<'de> for Example { +/// # type Value = (); +/// # +/// # fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { +/// # write!(formatter, "definitely not a boolean") +/// # } +/// # +/// fn visit_bool(self, v: bool) -> Result +/// where +/// E: de::Error, +/// { +/// Err(de::Error::invalid_type(Unexpected::Bool(v), &self)) +/// } +/// # } +/// ``` +/// +/// Outside of a `Visitor`, `&"..."` can be used. +/// +/// ```edition2021 +/// # use serde::de::{self, Unexpected}; +/// # +/// # fn example() -> Result<(), E> +/// # where +/// # E: de::Error, +/// # { +/// # let v = true; +/// 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. + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result; +} + +impl<'de, T> Expected for T +where + T: Visitor<'de>, +{ + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + self.expecting(formatter) + } +} + +impl Expected for &str { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(self) + } +} + +impl Display for dyn Expected + '_ { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Expected::fmt(self, formatter) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A **data structure** that can be deserialized from any data format supported +/// by Serde. +/// +/// Serde provides `Deserialize` implementations for many Rust primitive and +/// 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 +/// in your program. See the [derive section of the manual][derive] for how to +/// use this. +/// +/// In rare cases it may be necessary to implement `Deserialize` manually for +/// some type in your program. See the [Implementing +/// `Deserialize`][impl-deserialize] section of the manual for more about this. +/// +/// Third-party crates may provide `Deserialize` implementations for types that +/// they expose. For example the `linked-hash-map` crate provides a +/// `LinkedHashMap` type that is deserializable by Serde because the crate +/// provides an implementation of `Deserialize` for it. +/// +/// [derive]: https://serde.rs/derive.html +/// [impl-deserialize]: https://serde.rs/impl-deserialize.html +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the lifetime of data that may be +/// borrowed by `Self` when deserialized. See the page [Understanding +/// 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. + /// + /// See the [Implementing `Deserialize`][impl-deserialize] section of the + /// manual for more information about how to implement this method. + /// + /// [impl-deserialize]: https://serde.rs/impl-deserialize.html + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>; + + /// Deserializes a value into `self` from the given Deserializer. + /// + /// The purpose of this method is to allow the deserializer to reuse + /// resources and avoid copies. As such, if this method returns an error, + /// `self` will be in an indeterminate state where some parts of the struct + /// have been overwritten. Although whatever state that is will be + /// memory-safe. + /// + /// This is generally useful when repeatedly deserializing values that + /// are processed one at a time, where the value of `self` doesn't matter + /// when the next deserialization occurs. + /// + /// If you manually implement this, your recursive deserializations should + /// use `deserialize_in_place`. + /// + /// This method is stable and an official public API, but hidden from the + /// documentation because it is almost never what newbies are looking for. + /// Showing it in rustdoc would cause it to be featured more prominently + /// than it deserves. + #[doc(hidden)] + fn deserialize_in_place(deserializer: D, place: &mut Self) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + // Default implementation just delegates to `deserialize` impl. + *place = tri!(Deserialize::deserialize(deserializer)); + Ok(()) + } +} + +/// A data structure that can be deserialized without borrowing any data from +/// the deserializer. +/// +/// This is primarily useful for trait bounds on functions. For example a +/// `from_str` function may be able to deserialize a data structure that borrows +/// from the input string, but a `from_reader` function may only deserialize +/// owned data. +/// +/// ```edition2021 +/// # use serde::de::{Deserialize, DeserializeOwned}; +/// # use std::io::{Read, Result}; +/// # +/// # trait Ignore { +/// fn from_str<'a, T>(s: &'a str) -> Result +/// where +/// T: Deserialize<'a>; +/// +/// fn from_reader(rdr: R) -> Result +/// where +/// R: Read, +/// T: DeserializeOwned; +/// # } +/// ``` +/// +/// # Lifetime +/// +/// The relationship between `Deserialize` and `DeserializeOwned` in trait +/// bounds is explained in more detail on the page [Understanding deserializer +/// 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> {} + +/// `DeserializeSeed` is the stateful form of the `Deserialize` trait. If you +/// ever find yourself looking for a way to pass data into a `Deserialize` impl, +/// this trait is the way to do it. +/// +/// As one example of stateful deserialization consider deserializing a JSON +/// array into an existing buffer. Using the `Deserialize` trait we could +/// deserialize a JSON array into a `Vec` but it would be a freshly allocated +/// `Vec`; there is no way for `Deserialize` to reuse a previously allocated +/// buffer. Using `DeserializeSeed` instead makes this possible as in the +/// example code below. +/// +/// The canonical API for stateless deserialization looks like this: +/// +/// ```edition2021 +/// # use serde::Deserialize; +/// # +/// # enum Error {} +/// # +/// fn func<'de, T: Deserialize<'de>>() -> Result +/// # { +/// # unimplemented!() +/// # } +/// ``` +/// +/// Adjusting an API like this to support stateful deserialization is a matter +/// of accepting a seed as input: +/// +/// ```edition2021 +/// # use serde::de::DeserializeSeed; +/// # +/// # enum Error {} +/// # +/// fn func_seed<'de, T: DeserializeSeed<'de>>(seed: T) -> Result +/// # { +/// # let _ = seed; +/// # unimplemented!() +/// # } +/// ``` +/// +/// In practice the majority of deserialization is stateless. An API expecting a +/// seed can be appeased by passing `std::marker::PhantomData` as a seed in the +/// case of stateless deserialization. +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the lifetime of data that may be +/// borrowed by `Self::Value` when deserialized. See the page [Understanding +/// deserializer lifetimes] for a more detailed explanation of these lifetimes. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +/// +/// # Example +/// +/// Suppose we have JSON that looks like `[[1, 2], [3, 4, 5], [6]]` and we need +/// to deserialize it into a flat representation like `vec![1, 2, 3, 4, 5, 6]`. +/// Allocating a brand new `Vec` for each subarray would be slow. Instead we +/// would like to allocate a single `Vec` and then deserialize each subarray +/// into it. This requires stateful deserialization using the `DeserializeSeed` +/// trait. +/// +/// ```edition2021 +/// use serde::de::{Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor}; +/// use std::fmt; +/// use std::marker::PhantomData; +/// +/// // 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 +/// // `ExtendVec` will be traversing the inner arrays of the JSON input and +/// // appending each integer into the existing Vec. +/// struct ExtendVec<'a, T: 'a>(&'a mut Vec); +/// +/// impl<'de, 'a, T> DeserializeSeed<'de> for ExtendVec<'a, T> +/// where +/// T: Deserialize<'de>, +/// { +/// // The return type of the `deserialize` method. This implementation +/// // appends onto an existing vector but does not create any new data +/// // structure, so the return type is (). +/// type Value = (); +/// +/// fn deserialize(self, deserializer: D) -> Result +/// where +/// D: Deserializer<'de>, +/// { +/// // Visitor implementation that will walk an inner array of the JSON +/// // input. +/// struct ExtendVecVisitor<'a, T: 'a>(&'a mut Vec); +/// +/// impl<'de, 'a, T> Visitor<'de> for ExtendVecVisitor<'a, T> +/// where +/// T: Deserialize<'de>, +/// { +/// type Value = (); +/// +/// fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { +/// write!(formatter, "an array of integers") +/// } +/// +/// fn visit_seq(self, mut seq: A) -> Result<(), A::Error> +/// 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()? { +/// self.0.push(elem); +/// } +/// Ok(()) +/// } +/// } +/// +/// deserializer.deserialize_seq(ExtendVecVisitor(self.0)) +/// } +/// } +/// +/// // Visitor implementation that will walk the outer array of the JSON input. +/// struct FlattenedVecVisitor(PhantomData); +/// +/// impl<'de, T> Visitor<'de> for FlattenedVecVisitor +/// where +/// T: Deserialize<'de>, +/// { +/// // This Visitor constructs a single Vec to hold the flattened +/// // contents of the inner arrays. +/// type Value = Vec; +/// +/// fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { +/// write!(formatter, "an array of arrays") +/// } +/// +/// fn visit_seq(self, mut seq: A) -> Result, A::Error> +/// where +/// A: SeqAccess<'de>, +/// { +/// // Create a single Vec to hold the flattened contents. +/// let mut vec = Vec::new(); +/// +/// // Each iteration through this loop is one inner array. +/// while let Some(()) = seq.next_element_seed(ExtendVec(&mut vec))? { +/// // Nothing to do; inner array has been appended into `vec`. +/// } +/// +/// // Return the finished vec. +/// Ok(vec) +/// } +/// } +/// +/// # fn example<'de, D>(deserializer: D) -> Result<(), D::Error> +/// # where +/// # D: Deserializer<'de>, +/// # { +/// let visitor = FlattenedVecVisitor(PhantomData); +/// let flattened: Vec = deserializer.deserialize_seq(visitor)?; +/// # 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; + + /// Equivalent to the more common `Deserialize::deserialize` method, except + /// with some initial piece of data (the seed) passed in. + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>; +} + +impl<'de, T> DeserializeSeed<'de> for PhantomData +where + T: Deserialize<'de>, +{ + type Value = T; + + #[inline] + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + T::deserialize(deserializer) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A **data format** that can deserialize any data structure supported by +/// Serde. +/// +/// The role of this trait is to define the deserialization half of the [Serde +/// data model], which is a way to categorize every Rust data type into one of +/// 29 possible types. Each method of the `Deserializer` trait corresponds to one +/// of the types of the data model. +/// +/// Implementations of `Deserialize` map themselves into this data model by +/// passing to the `Deserializer` a `Visitor` implementation that can receive +/// these various types. +/// +/// The types that make up the Serde data model are: +/// +/// - **14 primitive types** +/// - bool +/// - i8, i16, i32, i64, i128 +/// - u8, u16, u32, u64, u128 +/// - f32, f64 +/// - char +/// - **string** +/// - UTF-8 bytes with a length and no null terminator. +/// - When serializing, all strings are handled equally. When deserializing, +/// there are three flavors of strings: transient, owned, and borrowed. +/// - **byte array** - \[u8\] +/// - Similar to strings, during deserialization byte arrays can be +/// transient, owned, or borrowed. +/// - **option** +/// - Either none or some value. +/// - **unit** +/// - The type of `()` in Rust. It represents an anonymous value containing +/// no data. +/// - **unit_struct** +/// - For example `struct Unit` or `PhantomData`. It represents a named +/// value containing no data. +/// - **unit_variant** +/// - For example the `E::A` and `E::B` in `enum E { A, B }`. +/// - **newtype_struct** +/// - For example `struct Millimeters(u8)`. +/// - **newtype_variant** +/// - For example the `E::N` in `enum E { N(u8) }`. +/// - **seq** +/// - A variably sized heterogeneous sequence of values, for example `Vec` +/// or `HashSet`. When serializing, the length may or may not be known +/// before iterating through all the data. When deserializing, the length +/// is determined by looking at the serialized data. +/// - **tuple** +/// - A statically sized heterogeneous sequence of values for which the +/// length will be known at deserialization time without looking at the +/// serialized data, for example `(u8,)` or `(String, u64, Vec)` or +/// `[u64; 10]`. +/// - **tuple_struct** +/// - A named tuple, for example `struct Rgb(u8, u8, u8)`. +/// - **tuple_variant** +/// - For example the `E::T` in `enum E { T(u8, u8) }`. +/// - **map** +/// - A heterogeneous key-value pairing, for example `BTreeMap`. +/// - **struct** +/// - A heterogeneous key-value pairing in which the keys are strings and +/// will be known at deserialization time without looking at the serialized +/// data, for example `struct S { r: u8, g: u8, b: u8 }`. +/// - **struct_variant** +/// - For example the `E::S` in `enum E { S { r: u8, g: u8, b: u8 } }`. +/// +/// The `Deserializer` trait supports two entry point styles which enables +/// different kinds of deserialization. +/// +/// 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 +/// document. Without knowing what is in a JSON document, we can deserialize +/// it to `serde_json::Value` by going through +/// `Deserializer::deserialize_any`. +/// +/// 2. The various `deserialize_*` methods. Non-self-describing formats like +/// 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 +/// `Deserializer::deserialize_any`. +/// +/// When implementing `Deserialize`, you should avoid relying on +/// `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 Postcard and many +/// others. +/// +/// [Serde data model]: https://serde.rs/data-model.html +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the lifetime of data that may be +/// borrowed from the input when deserializing. See the page [Understanding +/// deserializer lifetimes] for a more detailed explanation of these lifetimes. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +/// +/// # Example implementation +/// +/// The [example data format] presented on the website contains example code for +/// 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. + type Error: Error; + + /// Require the `Deserializer` to figure out how to drive the visitor based + /// on what data type is in the input. + /// + /// When implementing `Deserialize`, you should avoid relying on + /// `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 Postcard and + /// many others. + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a `bool` value. + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting an `i8` value. + fn deserialize_i8(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting an `i16` value. + fn deserialize_i16(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting an `i32` value. + fn deserialize_i32(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting an `i64` value. + fn deserialize_i64(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// 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. + fn deserialize_u8(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a `u16` value. + fn deserialize_u16(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a `u32` value. + fn deserialize_u32(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a `u64` value. + fn deserialize_u64(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// 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. + fn deserialize_f32(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a `f64` value. + fn deserialize_f64(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a `char` value. + fn deserialize_char(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a string value and does + /// not benefit from taking ownership of buffered data owned by the + /// `Deserializer`. + /// + /// If the `Visitor` would benefit from taking ownership of `String` data, + /// indicate this to the `Deserializer` by using `deserialize_string` + /// instead. + fn deserialize_str(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a string value and would + /// benefit from taking ownership of buffered data owned by the + /// `Deserializer`. + /// + /// If the `Visitor` would not benefit from taking ownership of `String` + /// data, indicate that to the `Deserializer` by using `deserialize_str` + /// instead. + fn deserialize_string(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a byte array and does not + /// benefit from taking ownership of buffered data owned by the + /// `Deserializer`. + /// + /// If the `Visitor` would benefit from taking ownership of `Vec` data, + /// indicate this to the `Deserializer` by using `deserialize_byte_buf` + /// instead. + fn deserialize_bytes(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a byte array and would + /// benefit from taking ownership of buffered data owned by the + /// `Deserializer`. + /// + /// If the `Visitor` would not benefit from taking ownership of `Vec` + /// data, indicate that to the `Deserializer` by using `deserialize_bytes` + /// instead. + fn deserialize_byte_buf(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting an optional value. + /// + /// This allows deserializers that encode an optional value as a nullable + /// value to convert the null value into `None` and a regular value into + /// `Some(value)`. + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a unit value. + fn deserialize_unit(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a unit struct with a + /// particular name. + fn deserialize_unit_struct( + self, + name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a newtype struct with a + /// particular name. + fn deserialize_newtype_struct( + self, + name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a sequence of values. + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a sequence of values and + /// knows how many values there are without looking at the serialized data. + fn deserialize_tuple(self, len: usize, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a tuple struct with a + /// particular name and number of fields. + fn deserialize_tuple_struct( + self, + name: &'static str, + len: usize, + visitor: V, + ) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a map of key-value pairs. + fn deserialize_map(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a struct with a particular + /// name and fields. + fn deserialize_struct( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting an enum value with a + /// particular name and possible variants. + fn deserialize_enum( + self, + name: &'static str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting the name of a struct + /// field or the discriminant of an enum variant. + fn deserialize_identifier(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type needs to deserialize a value whose type + /// doesn't matter because it is ignored. + /// + /// Deserializers for non-self-describing formats may not support this mode. + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Determine whether `Deserialize` implementations should expect to + /// deserialize their human-readable form. + /// + /// 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 Postcard will prefer the + /// compact one. + /// + /// ```edition2021 + /// # use std::ops::Add; + /// # use std::str::FromStr; + /// # + /// # struct Timestamp; + /// # + /// # impl Timestamp { + /// # const EPOCH: Timestamp = Timestamp; + /// # } + /// # + /// # impl FromStr for Timestamp { + /// # type Err = String; + /// # fn from_str(_: &str) -> Result { + /// # unimplemented!() + /// # } + /// # } + /// # + /// # struct Duration; + /// # + /// # impl Duration { + /// # fn seconds(_: u64) -> Self { unimplemented!() } + /// # } + /// # + /// # impl Add for Timestamp { + /// # type Output = Timestamp; + /// # fn add(self, _: Duration) -> Self::Output { + /// # unimplemented!() + /// # } + /// # } + /// # + /// use serde::de::{self, Deserialize, Deserializer}; + /// + /// impl<'de> Deserialize<'de> for Timestamp { + /// fn deserialize(deserializer: D) -> Result + /// where + /// D: Deserializer<'de>, + /// { + /// if deserializer.is_human_readable() { + /// // Deserialize from a human-readable string like "2015-05-15T17:01:00Z". + /// let s = String::deserialize(deserializer)?; + /// Timestamp::from_str(&s).map_err(de::Error::custom) + /// } else { + /// // Deserialize from a compact binary representation, seconds since + /// // the Unix epoch. + /// let n = u64::deserialize(deserializer)?; + /// Ok(Timestamp::EPOCH + Duration::seconds(n)) + /// } + /// } + /// } + /// ``` + /// + /// The default implementation of this method returns `true`. Data formats + /// may override this to `false` to request a compact form for types that + /// support one. Note that modifying this method to change a format from + /// human-readable to compact or vice versa should be regarded as a breaking + /// change, as a value serialized in human-readable mode is not required to + /// deserialize from the same data in compact mode. + #[inline] + 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) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// This trait represents a visitor that walks through a deserializer. +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the requirement for lifetime of data +/// that may be borrowed by `Self::Value`. See the page [Understanding +/// deserializer lifetimes] for a more detailed explanation of these lifetimes. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +/// +/// # Example +/// +/// ```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. +/// struct LongString { +/// min: usize, +/// } +/// +/// impl<'de> Visitor<'de> for LongString { +/// type Value = String; +/// +/// fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { +/// write!(formatter, "a string containing at least {} bytes", self.min) +/// } +/// +/// fn visit_str(self, s: &str) -> Result +/// where +/// E: de::Error, +/// { +/// if s.len() >= self.min { +/// Ok(s.to_owned()) +/// } else { +/// Err(de::Error::invalid_value(Unexpected::Str(s), &self)) +/// } +/// } +/// } +/// ``` +#[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; + + /// Format a message stating what data this Visitor expects to receive. + /// + /// This is used in error messages. The message should complete the sentence + /// "This Visitor expects to receive ...", for example the message could be + /// "an integer between 0 and 64". The message should not be capitalized and + /// should not end with a period. + /// + /// ```edition2021 + /// # use std::fmt; + /// # + /// # struct S { + /// # max: usize, + /// # } + /// # + /// # impl<'de> serde::de::Visitor<'de> for S { + /// # type Value = (); + /// # + /// fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// write!(formatter, "an integer between 0 and {}", self.max) + /// } + /// # } + /// ``` + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result; + + /// The input contains a boolean. + /// + /// The default implementation fails with a type error. + fn visit_bool(self, v: bool) -> Result + where + E: Error, + { + Err(Error::invalid_type(Unexpected::Bool(v), &self)) + } + + /// The input contains an `i8`. + /// + /// The default implementation forwards to [`visit_i64`]. + /// + /// [`visit_i64`]: #method.visit_i64 + fn visit_i8(self, v: i8) -> Result + where + E: Error, + { + self.visit_i64(v as i64) + } + + /// The input contains an `i16`. + /// + /// The default implementation forwards to [`visit_i64`]. + /// + /// [`visit_i64`]: #method.visit_i64 + fn visit_i16(self, v: i16) -> Result + where + E: Error, + { + self.visit_i64(v as i64) + } + + /// The input contains an `i32`. + /// + /// The default implementation forwards to [`visit_i64`]. + /// + /// [`visit_i64`]: #method.visit_i64 + fn visit_i32(self, v: i32) -> Result + where + E: Error, + { + self.visit_i64(v as i64) + } + + /// The input contains an `i64`. + /// + /// The default implementation fails with a type error. + fn visit_i64(self, v: i64) -> Result + where + E: Error, + { + Err(Error::invalid_type(Unexpected::Signed(v), &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`. + /// + /// The default implementation forwards to [`visit_u64`]. + /// + /// [`visit_u64`]: #method.visit_u64 + fn visit_u8(self, v: u8) -> Result + where + E: Error, + { + self.visit_u64(v as u64) + } + + /// The input contains a `u16`. + /// + /// The default implementation forwards to [`visit_u64`]. + /// + /// [`visit_u64`]: #method.visit_u64 + fn visit_u16(self, v: u16) -> Result + where + E: Error, + { + self.visit_u64(v as u64) + } + + /// The input contains a `u32`. + /// + /// The default implementation forwards to [`visit_u64`]. + /// + /// [`visit_u64`]: #method.visit_u64 + fn visit_u32(self, v: u32) -> Result + where + E: Error, + { + self.visit_u64(v as u64) + } + + /// The input contains a `u64`. + /// + /// The default implementation fails with a type error. + fn visit_u64(self, v: u64) -> Result + where + E: Error, + { + Err(Error::invalid_type(Unexpected::Unsigned(v), &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`. + /// + /// The default implementation forwards to [`visit_f64`]. + /// + /// [`visit_f64`]: #method.visit_f64 + fn visit_f32(self, v: f32) -> Result + where + E: Error, + { + self.visit_f64(v as f64) + } + + /// The input contains an `f64`. + /// + /// The default implementation fails with a type error. + fn visit_f64(self, v: f64) -> Result + where + E: Error, + { + Err(Error::invalid_type(Unexpected::Float(v), &self)) + } + + /// The input contains a `char`. + /// + /// The default implementation forwards to [`visit_str`] as a one-character + /// string. + /// + /// [`visit_str`]: #method.visit_str + #[inline] + fn visit_char(self, v: char) -> Result + where + E: Error, + { + self.visit_str(v.encode_utf8(&mut [0u8; 4])) + } + + /// The input contains a string. The lifetime of the string is ephemeral and + /// it may be destroyed after this method returns. + /// + /// This method allows the `Deserializer` to avoid a copy by retaining + /// ownership of any buffered data. `Deserialize` implementations that do + /// not benefit from taking ownership of `String` data should indicate that + /// to the deserializer by using `Deserializer::deserialize_str` rather than + /// `Deserializer::deserialize_string`. + /// + /// It is never correct to implement `visit_string` without implementing + /// `visit_str`. Implement neither, both, or just `visit_str`. + fn visit_str(self, v: &str) -> Result + where + E: Error, + { + Err(Error::invalid_type(Unexpected::Str(v), &self)) + } + + /// The input contains a string that lives at least as long as the + /// `Deserializer`. + /// + /// This enables zero-copy deserialization of strings in some formats. For + /// example JSON input containing the JSON string `"borrowed"` can be + /// deserialized with zero copying into a `&'a str` as long as the input + /// data outlives `'a`. + /// + /// The default implementation forwards to `visit_str`. + #[inline] + fn visit_borrowed_str(self, v: &'de str) -> Result + where + E: Error, + { + self.visit_str(v) + } + + /// The input contains a string and ownership of the string is being given + /// to the `Visitor`. + /// + /// This method allows the `Visitor` to avoid a copy by taking ownership of + /// a string created by the `Deserializer`. `Deserialize` implementations + /// that benefit from taking ownership of `String` data should indicate that + /// to the deserializer by using `Deserializer::deserialize_string` rather + /// than `Deserializer::deserialize_str`, although not every deserializer + /// will honor such a request. + /// + /// It is never correct to implement `visit_string` without implementing + /// `visit_str`. Implement neither, both, or just `visit_str`. + /// + /// The default implementation forwards to `visit_str` and then drops the + /// `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, + { + self.visit_str(&v) + } + + /// The input contains a byte array. The lifetime of the byte array is + /// ephemeral and it may be destroyed after this method returns. + /// + /// This method allows the `Deserializer` to avoid a copy by retaining + /// ownership of any buffered data. `Deserialize` implementations that do + /// not benefit from taking ownership of `Vec` data should indicate that + /// to the deserializer by using `Deserializer::deserialize_bytes` rather + /// than `Deserializer::deserialize_byte_buf`. + /// + /// It is never correct to implement `visit_byte_buf` without implementing + /// `visit_bytes`. Implement neither, both, or just `visit_bytes`. + fn visit_bytes(self, v: &[u8]) -> Result + where + E: Error, + { + Err(Error::invalid_type(Unexpected::Bytes(v), &self)) + } + + /// The input contains a byte array that lives at least as long as the + /// `Deserializer`. + /// + /// This enables zero-copy deserialization of bytes in some formats. For + /// 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`. + #[inline] + fn visit_borrowed_bytes(self, v: &'de [u8]) -> Result + where + E: Error, + { + self.visit_bytes(v) + } + + /// The input contains a byte array and ownership of the byte array is being + /// given to the `Visitor`. + /// + /// This method allows the `Visitor` to avoid a copy by taking ownership of + /// a byte buffer created by the `Deserializer`. `Deserialize` + /// implementations that benefit from taking ownership of `Vec` data + /// should indicate that to the deserializer by using + /// `Deserializer::deserialize_byte_buf` rather than + /// `Deserializer::deserialize_bytes`, although not every deserializer will + /// honor such a request. + /// + /// It is never correct to implement `visit_byte_buf` without implementing + /// `visit_bytes`. Implement neither, both, or just `visit_bytes`. + /// + /// 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, + { + self.visit_bytes(&v) + } + + /// The input contains an optional that is absent. + /// + /// The default implementation fails with a type error. + fn visit_none(self) -> Result + where + E: Error, + { + Err(Error::invalid_type(Unexpected::Option, &self)) + } + + /// The input contains an optional that is present. + /// + /// The default implementation fails with a type error. + fn visit_some(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let _ = deserializer; + Err(Error::invalid_type(Unexpected::Option, &self)) + } + + /// The input contains a unit `()`. + /// + /// The default implementation fails with a type error. + fn visit_unit(self) -> Result + where + E: Error, + { + Err(Error::invalid_type(Unexpected::Unit, &self)) + } + + /// The input contains a newtype struct. + /// + /// The content of the newtype struct may be read from the given + /// `Deserializer`. + /// + /// The default implementation fails with a type error. + fn visit_newtype_struct(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let _ = deserializer; + Err(Error::invalid_type(Unexpected::NewtypeStruct, &self)) + } + + /// The input contains a sequence of elements. + /// + /// The default implementation fails with a type error. + fn visit_seq(self, seq: A) -> Result + where + A: SeqAccess<'de>, + { + let _ = seq; + Err(Error::invalid_type(Unexpected::Seq, &self)) + } + + /// The input contains a key-value map. + /// + /// The default implementation fails with a type error. + fn visit_map(self, map: A) -> Result + where + A: MapAccess<'de>, + { + let _ = map; + Err(Error::invalid_type(Unexpected::Map, &self)) + } + + /// The input contains an enum. + /// + /// The default implementation fails with a type error. + fn visit_enum(self, data: A) -> Result + where + A: EnumAccess<'de>, + { + let _ = data; + Err(Error::invalid_type(Unexpected::Enum, &self)) + } + + // Used when deserializing a flattened Option field. Not public API. + #[doc(hidden)] + fn __private_visit_untagged_option(self, _: D) -> Result + where + D: Deserializer<'de>, + { + Err(()) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// Provides a `Visitor` access to each element of a sequence in the input. +/// +/// This is a trait that a `Deserializer` passes to a `Visitor` implementation, +/// which deserializes each item in a sequence. +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the lifetime of data that may be +/// borrowed by deserialized sequence elements. See the page [Understanding +/// deserializer lifetimes] for a more detailed explanation of these lifetimes. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// 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. + type Error: Error; + + /// This returns `Ok(Some(value))` for the next value in the sequence, or + /// `Ok(None)` if there are no more remaining items. + /// + /// `Deserialize` implementations should typically use + /// `SeqAccess::next_element` instead. + fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> + where + T: DeserializeSeed<'de>; + + /// This returns `Ok(Some(value))` for the next value in the sequence, or + /// `Ok(None)` if there are no more remaining items. + /// + /// This method exists as a convenience for `Deserialize` implementations. + /// `SeqAccess` implementations should not override the default behavior. + #[inline] + fn next_element(&mut self) -> Result, Self::Error> + where + T: Deserialize<'de>, + { + self.next_element_seed(PhantomData) + } + + /// Returns the number of elements remaining in the sequence, if known. + #[inline] + fn size_hint(&self) -> Option { + None + } +} + +impl<'de, A> SeqAccess<'de> for &mut A +where + A: ?Sized + SeqAccess<'de>, +{ + type Error = A::Error; + + #[inline] + fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> + where + T: DeserializeSeed<'de>, + { + (**self).next_element_seed(seed) + } + + #[inline] + fn next_element(&mut self) -> Result, Self::Error> + where + T: Deserialize<'de>, + { + (**self).next_element() + } + + #[inline] + fn size_hint(&self) -> Option { + (**self).size_hint() + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// Provides a `Visitor` access to each entry of a map in the input. +/// +/// This is a trait that a `Deserializer` passes to a `Visitor` implementation. +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the lifetime of data that may be +/// borrowed by deserialized map entries. See the page [Understanding +/// deserializer lifetimes] for a more detailed explanation of these lifetimes. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// 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. + type Error: Error; + + /// This returns `Ok(Some(key))` for the next key in the map, or `Ok(None)` + /// if there are no more remaining entries. + /// + /// `Deserialize` implementations should typically use + /// `MapAccess::next_key` or `MapAccess::next_entry` instead. + fn next_key_seed(&mut self, seed: K) -> Result, Self::Error> + where + K: DeserializeSeed<'de>; + + /// This returns a `Ok(value)` for the next value in the map. + /// + /// `Deserialize` implementations should typically use + /// `MapAccess::next_value` instead. + /// + /// # Panics + /// + /// Calling `next_value_seed` before `next_key_seed` is incorrect and is + /// allowed to panic or return bogus results. + fn next_value_seed(&mut self, seed: V) -> Result + where + V: DeserializeSeed<'de>; + + /// This returns `Ok(Some((key, value)))` for the next (key-value) pair in + /// the map, or `Ok(None)` if there are no more remaining items. + /// + /// `MapAccess` implementations should override the default behavior if a + /// more efficient implementation is possible. + /// + /// `Deserialize` implementations should typically use + /// `MapAccess::next_entry` instead. + #[inline] + fn next_entry_seed( + &mut self, + kseed: K, + vseed: V, + ) -> Result, Self::Error> + where + K: DeserializeSeed<'de>, + V: DeserializeSeed<'de>, + { + match tri!(self.next_key_seed(kseed)) { + Some(key) => { + let value = tri!(self.next_value_seed(vseed)); + Ok(Some((key, value))) + } + None => Ok(None), + } + } + + /// This returns `Ok(Some(key))` for the next key in the map, or `Ok(None)` + /// if there are no more remaining entries. + /// + /// This method exists as a convenience for `Deserialize` implementations. + /// `MapAccess` implementations should not override the default behavior. + #[inline] + fn next_key(&mut self) -> Result, Self::Error> + where + K: Deserialize<'de>, + { + self.next_key_seed(PhantomData) + } + + /// This returns a `Ok(value)` for the next value in the map. + /// + /// This method exists as a convenience for `Deserialize` implementations. + /// `MapAccess` implementations should not override the default behavior. + /// + /// # Panics + /// + /// Calling `next_value` before `next_key` is incorrect and is allowed to + /// panic or return bogus results. + #[inline] + fn next_value(&mut self) -> Result + where + V: Deserialize<'de>, + { + self.next_value_seed(PhantomData) + } + + /// This returns `Ok(Some((key, value)))` for the next (key-value) pair in + /// the map, or `Ok(None)` if there are no more remaining items. + /// + /// This method exists as a convenience for `Deserialize` implementations. + /// `MapAccess` implementations should not override the default behavior. + #[inline] + fn next_entry(&mut self) -> Result, Self::Error> + where + K: Deserialize<'de>, + V: Deserialize<'de>, + { + self.next_entry_seed(PhantomData, PhantomData) + } + + /// Returns the number of entries remaining in the map, if known. + #[inline] + fn size_hint(&self) -> Option { + None + } +} + +impl<'de, A> MapAccess<'de> for &mut A +where + A: ?Sized + MapAccess<'de>, +{ + type Error = A::Error; + + #[inline] + fn next_key_seed(&mut self, seed: K) -> Result, Self::Error> + where + K: DeserializeSeed<'de>, + { + (**self).next_key_seed(seed) + } + + #[inline] + fn next_value_seed(&mut self, seed: V) -> Result + where + V: DeserializeSeed<'de>, + { + (**self).next_value_seed(seed) + } + + #[inline] + fn next_entry_seed( + &mut self, + kseed: K, + vseed: V, + ) -> Result, Self::Error> + where + K: DeserializeSeed<'de>, + V: DeserializeSeed<'de>, + { + (**self).next_entry_seed(kseed, vseed) + } + + #[inline] + fn next_entry(&mut self) -> Result, Self::Error> + where + K: Deserialize<'de>, + V: Deserialize<'de>, + { + (**self).next_entry() + } + + #[inline] + fn next_key(&mut self) -> Result, Self::Error> + where + K: Deserialize<'de>, + { + (**self).next_key() + } + + #[inline] + fn next_value(&mut self) -> Result + where + V: Deserialize<'de>, + { + (**self).next_value() + } + + #[inline] + fn size_hint(&self) -> Option { + (**self).size_hint() + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// Provides a `Visitor` access to the data of an enum in the input. +/// +/// `EnumAccess` is created by the `Deserializer` and passed to the +/// `Visitor` in order to identify which variant of an enum to deserialize. +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the lifetime of data that may be +/// borrowed by the deserialized enum variant. See the page [Understanding +/// deserializer lifetimes] for a more detailed explanation of these lifetimes. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// 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. + type Error: Error; + /// The `Visitor` that will be used to deserialize the content of the enum + /// variant. + type Variant: VariantAccess<'de, Error = Self::Error>; + + /// `variant` is called to identify which variant to deserialize. + /// + /// `Deserialize` implementations should typically use `EnumAccess::variant` + /// instead. + fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> + where + V: DeserializeSeed<'de>; + + /// `variant` is called to identify which variant to deserialize. + /// + /// This method exists as a convenience for `Deserialize` implementations. + /// `EnumAccess` implementations should not override the default behavior. + #[inline] + fn variant(self) -> Result<(V, Self::Variant), Self::Error> + where + V: Deserialize<'de>, + { + self.variant_seed(PhantomData) + } +} + +/// `VariantAccess` is a visitor that is created by the `Deserializer` and +/// passed to the `Deserialize` to deserialize the content of a particular enum +/// variant. +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the lifetime of data that may be +/// borrowed by the deserialized enum variant. See the page [Understanding +/// deserializer lifetimes] for a more detailed explanation of these lifetimes. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// 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`. + type Error: Error; + + /// Called when deserializing a variant with no values. + /// + /// If the data contains a different type of variant, the following + /// `invalid_type` error should be constructed: + /// + /// ```edition2021 + /// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected}; + /// # + /// # struct X; + /// # + /// # impl<'de> VariantAccess<'de> for X { + /// # type Error = value::Error; + /// # + /// fn unit_variant(self) -> Result<(), Self::Error> { + /// // What the data actually contained; suppose it is a tuple variant. + /// let unexp = Unexpected::TupleVariant; + /// Err(de::Error::invalid_type(unexp, &"unit variant")) + /// } + /// # + /// # fn newtype_variant_seed(self, _: T) -> Result + /// # where + /// # T: DeserializeSeed<'de>, + /// # { unimplemented!() } + /// # + /// # fn tuple_variant(self, _: usize, _: V) -> Result + /// # where + /// # V: Visitor<'de>, + /// # { unimplemented!() } + /// # + /// # fn struct_variant(self, _: &[&str], _: V) -> Result + /// # where + /// # V: Visitor<'de>, + /// # { unimplemented!() } + /// # } + /// ``` + fn unit_variant(self) -> Result<(), Self::Error>; + + /// Called when deserializing a variant with a single value. + /// + /// `Deserialize` implementations should typically use + /// `VariantAccess::newtype_variant` instead. + /// + /// If the data contains a different type of variant, the following + /// `invalid_type` error should be constructed: + /// + /// ```edition2021 + /// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected}; + /// # + /// # struct X; + /// # + /// # impl<'de> VariantAccess<'de> for X { + /// # type Error = value::Error; + /// # + /// # fn unit_variant(self) -> Result<(), Self::Error> { + /// # unimplemented!() + /// # } + /// # + /// fn newtype_variant_seed(self, _seed: T) -> Result + /// where + /// T: DeserializeSeed<'de>, + /// { + /// // What the data actually contained; suppose it is a unit variant. + /// let unexp = Unexpected::UnitVariant; + /// Err(de::Error::invalid_type(unexp, &"newtype variant")) + /// } + /// # + /// # fn tuple_variant(self, _: usize, _: V) -> Result + /// # where + /// # V: Visitor<'de>, + /// # { unimplemented!() } + /// # + /// # fn struct_variant(self, _: &[&str], _: V) -> Result + /// # where + /// # V: Visitor<'de>, + /// # { unimplemented!() } + /// # } + /// ``` + fn newtype_variant_seed(self, seed: T) -> Result + where + T: DeserializeSeed<'de>; + + /// Called when deserializing a variant with a single value. + /// + /// This method exists as a convenience for `Deserialize` implementations. + /// `VariantAccess` implementations should not override the default + /// behavior. + #[inline] + fn newtype_variant(self) -> Result + where + T: Deserialize<'de>, + { + self.newtype_variant_seed(PhantomData) + } + + /// Called when deserializing a tuple-like variant. + /// + /// The `len` is the number of fields expected in the tuple variant. + /// + /// If the data contains a different type of variant, the following + /// `invalid_type` error should be constructed: + /// + /// ```edition2021 + /// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected}; + /// # + /// # struct X; + /// # + /// # impl<'de> VariantAccess<'de> for X { + /// # type Error = value::Error; + /// # + /// # fn unit_variant(self) -> Result<(), Self::Error> { + /// # unimplemented!() + /// # } + /// # + /// # fn newtype_variant_seed(self, _: T) -> Result + /// # where + /// # T: DeserializeSeed<'de>, + /// # { unimplemented!() } + /// # + /// fn tuple_variant(self, _len: usize, _visitor: V) -> Result + /// where + /// V: Visitor<'de>, + /// { + /// // What the data actually contained; suppose it is a unit variant. + /// let unexp = Unexpected::UnitVariant; + /// Err(de::Error::invalid_type(unexp, &"tuple variant")) + /// } + /// # + /// # fn struct_variant(self, _: &[&str], _: V) -> Result + /// # where + /// # V: Visitor<'de>, + /// # { unimplemented!() } + /// # } + /// ``` + fn tuple_variant(self, len: usize, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Called when deserializing a struct-like variant. + /// + /// The `fields` are the names of the fields of the struct variant. + /// + /// If the data contains a different type of variant, the following + /// `invalid_type` error should be constructed: + /// + /// ```edition2021 + /// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected}; + /// # + /// # struct X; + /// # + /// # impl<'de> VariantAccess<'de> for X { + /// # type Error = value::Error; + /// # + /// # fn unit_variant(self) -> Result<(), Self::Error> { + /// # unimplemented!() + /// # } + /// # + /// # fn newtype_variant_seed(self, _: T) -> Result + /// # where + /// # T: DeserializeSeed<'de>, + /// # { unimplemented!() } + /// # + /// # fn tuple_variant(self, _: usize, _: V) -> Result + /// # where + /// # V: Visitor<'de>, + /// # { unimplemented!() } + /// # + /// fn struct_variant( + /// self, + /// _fields: &'static [&'static str], + /// _visitor: V, + /// ) -> Result + /// where + /// V: Visitor<'de>, + /// { + /// // What the data actually contained; suppose it is a unit variant. + /// let unexp = Unexpected::UnitVariant; + /// Err(de::Error::invalid_type(unexp, &"struct variant")) + /// } + /// # } + /// ``` + fn struct_variant( + self, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>; +} + +//////////////////////////////////////////////////////////////////////////////// + +/// Converts an existing value into a `Deserializer` from which other values can +/// be deserialized. +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the lifetime of data that may be +/// borrowed from the resulting `Deserializer`. See the page [Understanding +/// deserializer lifetimes] for a more detailed explanation of these lifetimes. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +/// +/// # Example +/// +/// ```edition2021 +/// use serde::de::{value, Deserialize, IntoDeserializer}; +/// use serde_derive::Deserialize; +/// use std::str::FromStr; +/// +/// #[derive(Deserialize)] +/// enum Setting { +/// On, +/// Off, +/// } +/// +/// impl FromStr for Setting { +/// type Err = value::Error; +/// +/// fn from_str(s: &str) -> Result { +/// Self::deserialize(s.into_deserializer()) +/// } +/// } +/// ``` +pub trait IntoDeserializer<'de, E: Error = value::Error> { + /// The type of the deserializer being converted into. + type Deserializer: Deserializer<'de, Error = E>; + + /// Convert this value into a deserializer. + fn into_deserializer(self) -> Self::Deserializer; +} + +//////////////////////////////////////////////////////////////////////////////// + +/// Used in error messages. +/// +/// - expected `a` +/// - expected `a` or `b` +/// - expected one of `a`, `b`, `c` +/// +/// The slice of names must not be empty. +struct OneOf { + names: &'static [&'static str], +} + +impl Display for OneOf { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self.names.len() { + 0 => panic!(), // special case elsewhere + 1 => write!(formatter, "`{}`", self.names[0]), + 2 => write!(formatter, "`{}` or `{}`", self.names[0], self.names[1]), + _ => { + tri!(formatter.write_str("one of ")); + for (i, alt) in self.names.iter().enumerate() { + if i > 0 { + tri!(formatter.write_str(", ")); + } + 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/third_party/crates/serde_core-1.0.229/src/de/value.rs b/third_party/crates/serde_core-1.0.229/src/de/value.rs new file mode 100644 index 0000000..3d5475d --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/src/de/value.rs @@ -0,0 +1,1895 @@ +//! Building blocks for deserializing basic values using the `IntoDeserializer` +//! trait. +//! +//! ```edition2021 +//! use serde::de::{value, Deserialize, IntoDeserializer}; +//! use serde_derive::Deserialize; +//! use std::str::FromStr; +//! +//! #[derive(Deserialize)] +//! enum Setting { +//! On, +//! Off, +//! } +//! +//! impl FromStr for Setting { +//! type Err = value::Error; +//! +//! fn from_str(s: &str) -> Result { +//! Self::deserialize(s.into_deserializer()) +//! } +//! } +//! ``` + +use crate::lib::*; + +use self::private::{First, Second}; +use crate::de::{self, Deserializer, Expected, IntoDeserializer, SeqAccess, Visitor}; +use crate::private::size_hint; +use crate::ser; + +//////////////////////////////////////////////////////////////////////////////// + +// For structs that contain a PhantomData. We do not want the trait +// bound `E: Clone` inferred by derive(Clone). +macro_rules! impl_copy_clone { + ($ty:ident $(<$lifetime:tt>)*) => { + impl<$($lifetime,)* E> Copy for $ty<$($lifetime,)* E> {} + + impl<$($lifetime,)* E> Clone for $ty<$($lifetime,)* E> { + fn clone(&self) -> Self { + *self + } + } + }; +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A minimal representation of all possible errors that can occur using the +/// `IntoDeserializer` trait. +#[derive(Clone, PartialEq)] +pub struct Error { + err: ErrorImpl, +} + +#[cfg(any(feature = "std", feature = "alloc"))] +type ErrorImpl = Box; +#[cfg(not(any(feature = "std", feature = "alloc")))] +type ErrorImpl = (); + +impl de::Error for Error { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cold] + fn custom(msg: T) -> Self + where + T: Display, + { + Error { + err: msg.to_string().into_boxed_str(), + } + } + + #[cfg(not(any(feature = "std", feature = "alloc")))] + #[cold] + fn custom(msg: T) -> Self + where + T: Display, + { + let _ = msg; + Error { err: () } + } +} + +impl ser::Error for Error { + #[cold] + fn custom(msg: T) -> Self + where + T: Display, + { + de::Error::custom(msg) + } +} + +impl Display for Error { + #[cfg(any(feature = "std", feature = "alloc"))] + 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) -> 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 + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl<'de, E> IntoDeserializer<'de, E> for () +where + E: de::Error, +{ + type Deserializer = UnitDeserializer; + + fn into_deserializer(self) -> UnitDeserializer { + UnitDeserializer::new() + } +} + +/// A deserializer holding a `()`. +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, +{ + type Error = E; + + 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 + } + + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_unit() + } + + fn deserialize_option(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_none() + } +} + +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, +{ + type Deserializer = NeverDeserializer; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} + +#[cfg(feature = "unstable")] +impl<'de, E> de::Deserializer<'de> for NeverDeserializer +where + E: de::Error, +{ + type Error = E; + + fn deserialize_any(self, _visitor: V) -> Result + where + V: de::Visitor<'de>, + { + self.never + } + + 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(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] + pub struct $name { + value: $ty, + marker: PhantomData + } + + impl_copy_clone!($name); + + impl<'de, E> IntoDeserializer<'de, E> for $ty + where + E: de::Error, + { + type Deserializer = $name; + + fn into_deserializer(self) -> $name { + $name::new(self) + } + } + + impl $name { + #[allow(missing_docs)] + pub fn new(value: $ty) -> Self { + $name { + value, + marker: PhantomData, + } + } + } + + impl<'de, E> de::Deserializer<'de> for $name + where + E: de::Error, + { + type Error = E; + + 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 deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + 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() + } + } + } +} + +primitive_deserializer!(bool, "a `bool`.", BoolDeserializer, visit_bool); +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); + +/// A deserializer holding a `u32`. +pub struct U32Deserializer { + value: u32, + marker: PhantomData, +} + +impl_copy_clone!(U32Deserializer); + +impl<'de, E> IntoDeserializer<'de, E> for u32 +where + E: de::Error, +{ + type Deserializer = U32Deserializer; + + fn into_deserializer(self) -> U32Deserializer { + U32Deserializer::new(self) + } +} + +impl U32Deserializer { + #[allow(missing_docs)] + pub fn new(value: u32) -> Self { + U32Deserializer { + value, + marker: PhantomData, + } + } +} + +impl<'de, E> de::Deserializer<'de> for U32Deserializer +where + E: de::Error, +{ + type Error = E; + + 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 + } + + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_u32(self.value) + } + + fn deserialize_enum( + self, + name: &str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + let _ = name; + let _ = variants; + visitor.visit_enum(self) + } +} + +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, +{ + type Error = E; + type Variant = private::UnitOnly; + + fn variant_seed(self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error> + where + T: de::DeserializeSeed<'de>, + { + seed.deserialize(self).map(private::unit_only) + } +} + +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`. +pub struct StrDeserializer<'a, E> { + value: &'a str, + marker: PhantomData, +} + +impl_copy_clone!(StrDeserializer<'de>); + +impl<'de, 'a, E> IntoDeserializer<'de, E> for &'a str +where + E: de::Error, +{ + 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, + marker: PhantomData, + } + } +} + +impl<'de, 'a, E> de::Deserializer<'de> for StrDeserializer<'a, E> +where + E: de::Error, +{ + type Error = E; + + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_str(self.value) + } + + fn deserialize_enum( + self, + name: &str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + let _ = name; + let _ = variants; + visitor.visit_enum(self) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct identifier ignored_any + } +} + +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, +{ + type Error = E; + type Variant = private::UnitOnly; + + fn variant_seed(self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error> + where + T: de::DeserializeSeed<'de>, + { + seed.deserialize(self).map(private::unit_only) + } +} + +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. +pub struct BorrowedStrDeserializer<'de, E> { + value: &'de str, + marker: PhantomData, +} + +impl_copy_clone!(BorrowedStrDeserializer<'de>); + +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, + marker: PhantomData, + } + } +} + +impl<'de, E> de::Deserializer<'de> for BorrowedStrDeserializer<'de, E> +where + E: de::Error, +{ + type Error = E; + + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_borrowed_str(self.value) + } + + fn deserialize_enum( + self, + name: &str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + let _ = name; + let _ = variants; + visitor.visit_enum(self) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct identifier ignored_any + } +} + +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, +{ + type Error = E; + type Variant = private::UnitOnly; + + fn variant_seed(self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error> + where + T: de::DeserializeSeed<'de>, + { + seed.deserialize(self).map(private::unit_only) + } +} + +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"))] +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] +pub struct StringDeserializer { + value: String, + marker: PhantomData, +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl Clone for StringDeserializer { + fn clone(&self) -> Self { + StringDeserializer { + value: self.value.clone(), + marker: PhantomData, + } + } +} + +#[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, +{ + 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, + marker: PhantomData, + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'de, E> de::Deserializer<'de> for StringDeserializer +where + E: de::Error, +{ + type Error = E; + + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_string(self.value) + } + + fn deserialize_enum( + self, + name: &str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + let _ = name; + let _ = variants; + visitor.visit_enum(self) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct identifier ignored_any + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +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, +{ + type Error = E; + type Variant = private::UnitOnly; + + fn variant_seed(self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error> + where + T: de::DeserializeSeed<'de>, + { + seed.deserialize(self).map(private::unit_only) + } +} + +#[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"))] +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] +pub struct CowStrDeserializer<'a, E> { + value: Cow<'a, str>, + marker: PhantomData, +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, E> Clone for CowStrDeserializer<'a, E> { + fn clone(&self) -> Self { + CowStrDeserializer { + value: self.value.clone(), + marker: PhantomData, + } + } +} + +#[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, +{ + 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, + marker: PhantomData, + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'de, 'a, E> de::Deserializer<'de> for CowStrDeserializer<'a, E> +where + E: de::Error, +{ + type Error = E; + + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + match self.value { + Cow::Borrowed(string) => visitor.visit_str(string), + Cow::Owned(string) => visitor.visit_string(string), + } + } + + fn deserialize_enum( + self, + name: &str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + let _ = name; + let _ = variants; + visitor.visit_enum(self) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct identifier ignored_any + } +} + +#[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 + E: de::Error, +{ + type Error = E; + type Variant = private::UnitOnly; + + fn variant_seed(self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error> + where + T: de::DeserializeSeed<'de>, + { + seed.deserialize(self).map(private::unit_only) + } +} + +#[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. Always calls [`Visitor::visit_borrowed_bytes`]. +pub struct BorrowedBytesDeserializer<'de, E> { + value: &'de [u8], + marker: PhantomData, +} + +impl<'de, E> BorrowedBytesDeserializer<'de, E> { + /// Create a new borrowed deserializer from the given borrowed bytes. + pub fn new(value: &'de [u8]) -> Self { + BorrowedBytesDeserializer { + value, + marker: PhantomData, + } + } +} + +impl_copy_clone!(BorrowedBytesDeserializer<'de>); + +impl<'de, E> Deserializer<'de> for BorrowedBytesDeserializer<'de, E> +where + E: de::Error, +{ + type Error = E; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_borrowed_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, 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)] +pub struct SeqDeserializer { + iter: iter::Fuse, + count: usize, + marker: PhantomData, +} + +impl SeqDeserializer +where + I: Iterator, +{ + /// Construct a new `SeqDeserializer`. + pub fn new(iter: I) -> Self { + SeqDeserializer { + iter: iter.fuse(), + count: 0, + marker: PhantomData, + } + } +} + +impl SeqDeserializer +where + I: Iterator, + E: de::Error, +{ + /// Check for remaining elements after passing a `SeqDeserializer` to + /// `Visitor::visit_seq`. + pub 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, I, T, E> de::Deserializer<'de> for SeqDeserializer +where + I: Iterator, + T: IntoDeserializer<'de, E>, + E: de::Error, +{ + type Error = E; + + fn deserialize_any(mut self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + let v = tri!(visitor.visit_seq(&mut self)); + tri!(self.end()); + Ok(v) + } + + 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, 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, + T: IntoDeserializer<'de, E>, + E: de::Error, +{ + type Error = E; + + fn next_element_seed(&mut self, seed: V) -> Result, Self::Error> + where + V: de::DeserializeSeed<'de>, + { + match self.iter.next() { + Some(value) => { + self.count += 1; + seed.deserialize(value.into_deserializer()).map(Some) + } + None => Ok(None), + } + } + + fn size_hint(&self) -> Option { + size_hint::from_bounds(&self.iter) + } +} + +struct ExpectedInSeq(usize); + +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) + } + } +} + +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>, + E: de::Error, +{ + type Deserializer = SeqDeserializer<::IntoIter, E>; + + fn into_deserializer(self) -> Self::Deserializer { + SeqDeserializer::new(self.into_iter()) + } +} + +#[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, + E: de::Error, +{ + type Deserializer = SeqDeserializer<::IntoIter, E>; + + fn into_deserializer(self) -> Self::Deserializer { + SeqDeserializer::new(self.into_iter()) + } +} + +#[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, + S: BuildHasher, + E: de::Error, +{ + type Deserializer = SeqDeserializer<::IntoIter, E>; + + fn into_deserializer(self) -> Self::Deserializer { + SeqDeserializer::new(self.into_iter()) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A deserializer holding a `SeqAccess`. +#[derive(Clone, Debug)] +pub struct SeqAccessDeserializer { + seq: A, +} + +impl SeqAccessDeserializer { + /// Construct a new `SeqAccessDeserializer`. + pub fn new(seq: A) -> Self { + SeqAccessDeserializer { seq } + } +} + +impl<'de, A> de::Deserializer<'de> for SeqAccessDeserializer +where + A: de::SeqAccess<'de>, +{ + type Error = A::Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_seq(self.seq) + } + + 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 SeqAccessDeserializer +where + A: de::SeqAccess<'de>, +{ + type Deserializer = Self; + + fn into_deserializer(self) -> Self { + self + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A deserializer that iterates over a map. +pub struct MapDeserializer<'de, I, E> +where + I: Iterator, + I::Item: private::Pair, +{ + iter: iter::Fuse, + value: Option>, + count: usize, + lifetime: PhantomData<&'de ()>, + error: PhantomData, +} + +impl<'de, I, E> MapDeserializer<'de, I, E> +where + I: Iterator, + I::Item: private::Pair, +{ + /// Construct a new `MapDeserializer`. + pub fn new(iter: I) -> Self { + MapDeserializer { + iter: iter.fuse(), + value: None, + count: 0, + lifetime: PhantomData, + error: PhantomData, + } + } +} + +impl<'de, I, E> MapDeserializer<'de, I, E> +where + I: Iterator, + I::Item: private::Pair, + E: de::Error, +{ + /// Check for remaining elements after passing a `MapDeserializer` to + /// `Visitor::visit_map`. + pub 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), + )) + } + } +} + +impl<'de, I, E> MapDeserializer<'de, I, E> +where + I: Iterator, + I::Item: private::Pair, +{ + fn next_pair(&mut self) -> Option<(First, Second)> { + match self.iter.next() { + Some(kv) => { + self.count += 1; + Some(private::Pair::split(kv)) + } + None => None, + } + } +} + +impl<'de, I, E> de::Deserializer<'de> for MapDeserializer<'de, I, E> +where + I: Iterator, + I::Item: private::Pair, + First: IntoDeserializer<'de, E>, + Second: IntoDeserializer<'de, E>, + E: de::Error, +{ + type Error = E; + + fn deserialize_any(mut self, visitor: V) -> Result + where + V: de::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: de::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: de::Visitor<'de>, + { + let _ = len; + self.deserialize_seq(visitor) + } + + 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 + } +} + +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, + I::Item: private::Pair, + First: IntoDeserializer<'de, E>, + Second: IntoDeserializer<'de, E>, + E: de::Error, +{ + type Error = E; + + fn next_key_seed(&mut self, seed: T) -> Result, Self::Error> + where + T: de::DeserializeSeed<'de>, + { + match self.next_pair() { + Some((key, value)) => { + self.value = Some(value); + seed.deserialize(key.into_deserializer()).map(Some) + } + None => Ok(None), + } + } + + fn next_value_seed(&mut self, seed: T) -> Result + where + T: de::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(value.into_deserializer()) + } + + fn next_entry_seed( + &mut self, + kseed: TK, + vseed: TV, + ) -> Result, Self::Error> + where + TK: de::DeserializeSeed<'de>, + TV: de::DeserializeSeed<'de>, + { + match self.next_pair() { + Some((key, value)) => { + let key = tri!(kseed.deserialize(key.into_deserializer())); + let value = tri!(vseed.deserialize(value.into_deserializer())); + Ok(Some((key, value))) + } + None => Ok(None), + } + } + + fn size_hint(&self) -> Option { + size_hint::from_bounds(&self.iter) + } +} + +impl<'de, I, E> de::SeqAccess<'de> for MapDeserializer<'de, I, E> +where + I: Iterator, + I::Item: private::Pair, + First: IntoDeserializer<'de, E>, + Second: IntoDeserializer<'de, E>, + E: de::Error, +{ + 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 = PairDeserializer(k, v, PhantomData); + seed.deserialize(de).map(Some) + } + None => Ok(None), + } + } + + fn size_hint(&self) -> Option { + size_hint::from_bounds(&self.iter) + } +} + +// Cannot #[derive(Clone)] because of the bound `Second: Clone`. +impl<'de, I, E> Clone for MapDeserializer<'de, I, E> +where + I: Iterator + Clone, + I::Item: private::Pair, + Second: Clone, +{ + fn clone(&self) -> Self { + MapDeserializer { + iter: self.iter.clone(), + value: self.value.clone(), + count: self.count, + lifetime: self.lifetime, + error: self.error, + } + } +} + +impl<'de, I, E> Debug for MapDeserializer<'de, I, E> +where + I: Iterator + Debug, + I::Item: private::Pair, + Second: Debug, +{ + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_struct("MapDeserializer") + .field("iter", &self.iter) + .field("value", &self.value) + .field("count", &self.count) + .finish() + } +} + +// Used in the `impl SeqAccess for MapDeserializer` to visit the map as a +// sequence of pairs. +struct PairDeserializer(A, B, PhantomData); + +impl<'de, A, B, E> de::Deserializer<'de> for PairDeserializer +where + A: IntoDeserializer<'de, E>, + B: IntoDeserializer<'de, E>, + E: de::Error, +{ + type Error = E; + + 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: de::Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: de::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(Option, Option, PhantomData); + +impl<'de, A, B, E> de::SeqAccess<'de> for PairVisitor +where + A: IntoDeserializer<'de, E>, + B: IntoDeserializer<'de, E>, + E: de::Error, +{ + type Error = E; + + fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> + where + T: de::DeserializeSeed<'de>, + { + if let Some(k) = self.0.take() { + seed.deserialize(k.into_deserializer()).map(Some) + } else if let Some(v) = self.1.take() { + seed.deserialize(v.into_deserializer()).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); + +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) + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[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, + V: IntoDeserializer<'de, E>, + E: de::Error, +{ + type Deserializer = MapDeserializer<'de, ::IntoIter, E>; + + fn into_deserializer(self) -> Self::Deserializer { + MapDeserializer::new(self.into_iter()) + } +} + +#[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, + V: IntoDeserializer<'de, E>, + S: BuildHasher, + E: de::Error, +{ + type Deserializer = MapDeserializer<'de, ::IntoIter, E>; + + fn into_deserializer(self) -> Self::Deserializer { + MapDeserializer::new(self.into_iter()) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A deserializer holding a `MapAccess`. +#[derive(Clone, Debug)] +pub struct MapAccessDeserializer { + map: A, +} + +impl MapAccessDeserializer { + /// Construct a new `MapAccessDeserializer`. + pub fn new(map: A) -> Self { + MapAccessDeserializer { map } + } +} + +impl<'de, A> de::Deserializer<'de> for MapAccessDeserializer +where + A: de::MapAccess<'de>, +{ + type Error = A::Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_map(self.map) + } + + fn deserialize_enum( + self, + _name: &str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_enum(self) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct identifier ignored_any + } +} + +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>, +{ + type Error = A::Error; + type Variant = private::MapAsEnum; + + fn variant_seed(mut self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error> + where + T: de::DeserializeSeed<'de>, + { + 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")), + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// 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 crate::lib::*; + + use crate::de::{ + self, DeserializeSeed, Deserializer, MapAccess, Unexpected, VariantAccess, Visitor, + }; + + pub struct UnitOnly { + marker: PhantomData, + } + + pub fn unit_only(t: T) -> (T, UnitOnly) { + ( + t, + UnitOnly { + marker: PhantomData, + }, + ) + } + + impl<'de, E> de::VariantAccess<'de> for UnitOnly + where + E: de::Error, + { + type Error = E; + + fn unit_variant(self) -> Result<(), Self::Error> { + Ok(()) + } + + fn newtype_variant_seed(self, _seed: T) -> Result + where + T: de::DeserializeSeed<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"newtype variant", + )) + } + + fn tuple_variant(self, _len: usize, _visitor: V) -> Result + where + V: de::Visitor<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"tuple variant", + )) + } + + fn struct_variant( + self, + _fields: &'static [&'static str], + _visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"struct variant", + )) + } + } + + pub struct MapAsEnum { + map: A, + } + + pub fn map_as_enum(map: A) -> MapAsEnum { + MapAsEnum { map } + } + + impl<'de, A> VariantAccess<'de> for MapAsEnum + where + A: MapAccess<'de>, + { + type Error = A::Error; + + fn unit_variant(mut self) -> Result<(), Self::Error> { + self.map.next_value() + } + + fn newtype_variant_seed(mut self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + self.map.next_value_seed(seed) + } + + fn tuple_variant(mut self, len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.map.next_value_seed(SeedTupleVariant { len, visitor }) + } + + fn struct_variant( + mut self, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.map.next_value_seed(SeedStructVariant { visitor }) + } + } + + struct SeedTupleVariant { + len: usize, + visitor: V, + } + + impl<'de, V> DeserializeSeed<'de> for SeedTupleVariant + where + V: Visitor<'de>, + { + type Value = V::Value; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_tuple(self.len, self.visitor) + } + } + + struct SeedStructVariant { + visitor: V, + } + + impl<'de, V> DeserializeSeed<'de> for SeedStructVariant + where + V: Visitor<'de>, + { + type Value = V::Value; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_map(self.visitor) + } + } + + /// Avoid having to restate the generic types on `MapDeserializer`. The + /// `Iterator::Item` contains enough information to figure out K and V. + pub trait Pair { + type First; + type Second; + fn split(self) -> (Self::First, Self::Second); + } + + impl Pair for (A, B) { + type First = A; + type Second = B; + fn split(self) -> (A, B) { + self + } + } + + pub type First = ::First; + pub type Second = ::Second; +} diff --git a/third_party/crates/serde_core-1.0.229/src/format.rs b/third_party/crates/serde_core-1.0.229/src/format.rs new file mode 100644 index 0000000..9053cc0 --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/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/third_party/crates/serde_core-1.0.229/src/lib.rs b/third_party/crates/serde_core-1.0.229/src/lib.rs new file mode 100644 index 0000000..4420e50 --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/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.229")] +// 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/third_party/crates/serde_core-1.0.229/src/macros.rs b/third_party/crates/serde_core-1.0.229/src/macros.rs new file mode 100644 index 0000000..b956730 --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/src/macros.rs @@ -0,0 +1,230 @@ +// 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. +/// +/// Some [`Deserializer`] implementations for self-describing formats do not +/// care what hint the [`Visitor`] gives them, they just want to blindly call +/// the [`Visitor`] method corresponding to the data they can tell is in the +/// input. This requires repetitive implementations of all the [`Deserializer`] +/// trait methods. +/// +/// ```edition2021 +/// # use serde::forward_to_deserialize_any; +/// # use serde::de::{value, Deserializer, Visitor}; +/// # +/// # struct MyDeserializer; +/// # +/// # impl<'de> Deserializer<'de> for MyDeserializer { +/// # type Error = value::Error; +/// # +/// # fn deserialize_any(self, _: V) -> Result +/// # where +/// # V: Visitor<'de>, +/// # { +/// # unimplemented!() +/// # } +/// # +/// #[inline] +/// fn deserialize_bool(self, visitor: V) -> Result +/// where +/// V: Visitor<'de>, +/// { +/// self.deserialize_any(visitor) +/// } +/// # +/// # forward_to_deserialize_any! { +/// # 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 +/// # } +/// # } +/// ``` +/// +/// The `forward_to_deserialize_any!` macro implements these simple forwarding +/// methods so that they forward directly to [`Deserializer::deserialize_any`]. +/// You can choose which methods to forward. +/// +/// ```edition2021 +/// # use serde::forward_to_deserialize_any; +/// # use serde::de::{value, Deserializer, Visitor}; +/// # +/// # struct MyDeserializer; +/// # +/// impl<'de> Deserializer<'de> for MyDeserializer { +/// # type Error = value::Error; +/// # +/// fn deserialize_any(self, visitor: V) -> Result +/// where +/// V: Visitor<'de>, +/// { +/// /* ... */ +/// # let _ = visitor; +/// # unimplemented!() +/// } +/// +/// 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 +/// } +/// } +/// ``` +/// +/// The macro assumes the convention that your `Deserializer` lifetime parameter +/// is called `'de` and that the `Visitor` type parameters on each method are +/// called `V`. A different type parameter and a different lifetime can be +/// specified explicitly if necessary. +/// +/// ```edition2021 +/// # use serde::forward_to_deserialize_any; +/// # use serde::de::{value, Deserializer, Visitor}; +/// # use std::marker::PhantomData; +/// # +/// # struct MyDeserializer(PhantomData); +/// # +/// # impl<'q, V> Deserializer<'q> for MyDeserializer { +/// # type Error = value::Error; +/// # +/// # fn deserialize_any(self, visitor: W) -> Result +/// # where +/// # W: Visitor<'q>, +/// # { +/// # unimplemented!() +/// # } +/// # +/// 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 +/// } +/// # } +/// ``` +/// +/// [`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)*) => { + $(forward_to_deserialize_any_helper!{$func<$lifetime, $visitor>})* + }; + // This case must be after the previous one. + ($($func:ident)*) => { + $(forward_to_deserialize_any_helper!{$func<'de, V>})* + }; +} + +#[doc(hidden)] +#[macro_export] +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::__private::Result<$v::Value, >::Error> + where + $v: $crate::de::Visitor<$l>, + { + $( + let _ = $arg; + )* + self.deserialize_any(visitor) + } + }; +} + +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! forward_to_deserialize_any_helper { + (bool<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_bool<$l, $v>()} + }; + (i8<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_i8<$l, $v>()} + }; + (i16<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_i16<$l, $v>()} + }; + (i32<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_i32<$l, $v>()} + }; + (i64<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_i64<$l, $v>()} + }; + (i128<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_i128<$l, $v>()} + }; + (u8<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_u8<$l, $v>()} + }; + (u16<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_u16<$l, $v>()} + }; + (u32<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_u32<$l, $v>()} + }; + (u64<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_u64<$l, $v>()} + }; + (u128<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_u128<$l, $v>()} + }; + (f32<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_f32<$l, $v>()} + }; + (f64<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_f64<$l, $v>()} + }; + (char<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_char<$l, $v>()} + }; + (str<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_str<$l, $v>()} + }; + (string<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_string<$l, $v>()} + }; + (bytes<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_bytes<$l, $v>()} + }; + (byte_buf<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_byte_buf<$l, $v>()} + }; + (option<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_option<$l, $v>()} + }; + (unit<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_unit<$l, $v>()} + }; + (unit_struct<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_unit_struct<$l, $v>(name: &'static str)} + }; + (newtype_struct<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_newtype_struct<$l, $v>(name: &'static str)} + }; + (seq<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_seq<$l, $v>()} + }; + (tuple<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_tuple<$l, $v>(len: usize)} + }; + (tuple_struct<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_tuple_struct<$l, $v>(name: &'static str, len: usize)} + }; + (map<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_map<$l, $v>()} + }; + (struct<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_struct<$l, $v>(name: &'static str, fields: &'static [&'static str])} + }; + (enum<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_enum<$l, $v>(name: &'static str, variants: &'static [&'static str])} + }; + (identifier<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_identifier<$l, $v>()} + }; + (ignored_any<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_ignored_any<$l, $v>()} + }; +} diff --git a/third_party/crates/serde_core-1.0.229/src/private/content.rs b/third_party/crates/serde_core-1.0.229/src/private/content.rs new file mode 100644 index 0000000..f29a9b5 --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/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/third_party/crates/serde_core-1.0.229/src/private/doc.rs b/third_party/crates/serde_core-1.0.229/src/private/doc.rs new file mode 100644 index 0000000..2cc07f0 --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/src/private/doc.rs @@ -0,0 +1,165 @@ +// 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 { + () => { + trait Serialize { + fn serialize(&self, serializer: S) -> Result + where + S: $crate::Serializer; + } + }; +} + +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! __serialize_unimplemented { + ($($func:ident)*) => { + $( + __serialize_unimplemented_helper!($func); + )* + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __serialize_unimplemented_method { + ($func:ident $(<$t:ident>)* ($($arg:ty),*) -> $ret:ident) => { + fn $func $(<$t>)* (self $(, _: $arg)*) -> $crate::__private::Result + where + $($t: ?Sized + $crate::Serialize,)* + { + unimplemented!() + } + }; +} + +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! __serialize_unimplemented_helper { + (bool) => { + __serialize_unimplemented_method!(serialize_bool(bool) -> Ok); + }; + (i8) => { + __serialize_unimplemented_method!(serialize_i8(i8) -> Ok); + }; + (i16) => { + __serialize_unimplemented_method!(serialize_i16(i16) -> Ok); + }; + (i32) => { + __serialize_unimplemented_method!(serialize_i32(i32) -> Ok); + }; + (i64) => { + __serialize_unimplemented_method!(serialize_i64(i64) -> Ok); + }; + (u8) => { + __serialize_unimplemented_method!(serialize_u8(u8) -> Ok); + }; + (u16) => { + __serialize_unimplemented_method!(serialize_u16(u16) -> Ok); + }; + (u32) => { + __serialize_unimplemented_method!(serialize_u32(u32) -> Ok); + }; + (u64) => { + __serialize_unimplemented_method!(serialize_u64(u64) -> Ok); + }; + (f32) => { + __serialize_unimplemented_method!(serialize_f32(f32) -> Ok); + }; + (f64) => { + __serialize_unimplemented_method!(serialize_f64(f64) -> Ok); + }; + (char) => { + __serialize_unimplemented_method!(serialize_char(char) -> Ok); + }; + (str) => { + __serialize_unimplemented_method!(serialize_str(&str) -> Ok); + }; + (bytes) => { + __serialize_unimplemented_method!(serialize_bytes(&[u8]) -> Ok); + }; + (none) => { + __serialize_unimplemented_method!(serialize_none() -> Ok); + }; + (some) => { + __serialize_unimplemented_method!(serialize_some(&T) -> Ok); + }; + (unit) => { + __serialize_unimplemented_method!(serialize_unit() -> Ok); + }; + (unit_struct) => { + __serialize_unimplemented_method!(serialize_unit_struct(&str) -> Ok); + }; + (unit_variant) => { + __serialize_unimplemented_method!(serialize_unit_variant(&str, u32, &str) -> Ok); + }; + (newtype_struct) => { + __serialize_unimplemented_method!(serialize_newtype_struct(&str, &T) -> Ok); + }; + (newtype_variant) => { + __serialize_unimplemented_method!(serialize_newtype_variant(&str, u32, &str, &T) -> Ok); + }; + (seq) => { + type SerializeSeq = $crate::ser::Impossible; + __serialize_unimplemented_method!(serialize_seq(Option) -> SerializeSeq); + }; + (tuple) => { + type SerializeTuple = $crate::ser::Impossible; + __serialize_unimplemented_method!(serialize_tuple(usize) -> SerializeTuple); + }; + (tuple_struct) => { + type SerializeTupleStruct = $crate::ser::Impossible; + __serialize_unimplemented_method!(serialize_tuple_struct(&str, usize) -> SerializeTupleStruct); + }; + (tuple_variant) => { + type SerializeTupleVariant = $crate::ser::Impossible; + __serialize_unimplemented_method!(serialize_tuple_variant(&str, u32, &str, usize) -> SerializeTupleVariant); + }; + (map) => { + type SerializeMap = $crate::ser::Impossible; + __serialize_unimplemented_method!(serialize_map(Option) -> SerializeMap); + }; + (struct) => { + type SerializeStruct = $crate::ser::Impossible; + __serialize_unimplemented_method!(serialize_struct(&str, usize) -> SerializeStruct); + }; + (struct_variant) => { + type SerializeStructVariant = $crate::ser::Impossible; + __serialize_unimplemented_method!(serialize_struct_variant(&str, u32, &str, usize) -> SerializeStructVariant); + }; +} diff --git a/third_party/crates/serde_core-1.0.229/src/private/mod.rs b/third_party/crates/serde_core-1.0.229/src/private/mod.rs new file mode 100644 index 0000000..dd5f93f --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/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/third_party/crates/serde_core-1.0.229/src/private/seed.rs b/third_party/crates/serde_core-1.0.229/src/private/seed.rs new file mode 100644 index 0000000..bcf267c --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/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/third_party/crates/serde_core-1.0.229/src/private/size_hint.rs b/third_party/crates/serde_core-1.0.229/src/private/size_hint.rs new file mode 100644 index 0000000..783281b --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/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/third_party/crates/serde_core-1.0.229/src/private/string.rs b/third_party/crates/serde_core-1.0.229/src/private/string.rs new file mode 100644 index 0000000..c8121a0 --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/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/third_party/crates/serde_core-1.0.229/src/ser/fmt.rs b/third_party/crates/serde_core-1.0.229/src/ser/fmt.rs new file mode 100644 index 0000000..4b1549f --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/src/ser/fmt.rs @@ -0,0 +1,170 @@ +use crate::lib::*; +use crate::ser::{Error, Impossible, Serialize, Serializer}; + +impl Error for fmt::Error { + fn custom(_msg: T) -> Self { + fmt::Error + } +} + +macro_rules! fmt_primitives { + ($($f:ident: $t:ty,)*) => { + $( + fn $f(self, v: $t) -> fmt::Result { + Display::fmt(&v, self) + } + )* + }; +} + +/// ```edition2021 +/// use serde::ser::Serialize; +/// use serde_derive::Serialize; +/// use std::fmt::{self, Display}; +/// +/// #[derive(Serialize)] +/// #[serde(rename_all = "kebab-case")] +/// pub enum MessageType { +/// StartRequest, +/// EndRequest, +/// } +/// +/// impl Display for MessageType { +/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// self.serialize(f) +/// } +/// } +/// ``` +impl<'a> Serializer for &mut fmt::Formatter<'a> { + type Ok = (); + type Error = fmt::Error; + type SerializeSeq = Impossible<(), fmt::Error>; + type SerializeTuple = Impossible<(), fmt::Error>; + type SerializeTupleStruct = Impossible<(), fmt::Error>; + type SerializeTupleVariant = Impossible<(), fmt::Error>; + type SerializeMap = Impossible<(), fmt::Error>; + type SerializeStruct = Impossible<(), fmt::Error>; + type SerializeStructVariant = Impossible<(), fmt::Error>; + + fmt_primitives! { + serialize_bool: bool, + serialize_i8: i8, + 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, + serialize_str: &str, + serialize_unit_struct: &'static str, + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> fmt::Result { + Display::fmt(variant, self) + } + + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> fmt::Result + where + T: ?Sized + Serialize, + { + Serialize::serialize(value, self) + } + + fn serialize_bytes(self, _v: &[u8]) -> fmt::Result { + Err(fmt::Error) + } + + fn serialize_none(self) -> fmt::Result { + Err(fmt::Error) + } + + fn serialize_some(self, _value: &T) -> fmt::Result + where + T: ?Sized + Serialize, + { + Err(fmt::Error) + } + + fn serialize_unit(self) -> fmt::Result { + Err(fmt::Error) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> fmt::Result + where + T: ?Sized + Serialize, + { + Err(fmt::Error) + } + + fn serialize_seq(self, _len: Option) -> Result { + Err(fmt::Error) + } + + fn serialize_tuple(self, _len: usize) -> Result { + Err(fmt::Error) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + Err(fmt::Error) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(fmt::Error) + } + + fn serialize_map(self, _len: Option) -> Result { + Err(fmt::Error) + } + + fn serialize_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + Err(fmt::Error) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(fmt::Error) + } + + fn collect_str(self, value: &T) -> fmt::Result + where + T: ?Sized + Display, + { + Display::fmt(value, self) + } +} diff --git a/third_party/crates/serde_core-1.0.229/src/ser/impls.rs b/third_party/crates/serde_core-1.0.229/src/ser/impls.rs new file mode 100644 index 0000000..a7a175d --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/src/ser/impls.rs @@ -0,0 +1,1045 @@ +use crate::lib::*; + +use crate::ser::{Error, Serialize, SerializeTuple, Serializer}; + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! primitive_impl { + ($ty:ident, $method:ident $($cast:tt)*) => { + impl Serialize for $ty { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.$method(*self $($cast)*) + } + } + } +} + +primitive_impl!(bool, serialize_bool); +primitive_impl!(isize, serialize_i64 as i64); +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); + +//////////////////////////////////////////////////////////////////////////////// + +impl Serialize for str { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(self) + } +} + +#[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 + where + S: Serializer, + { + serializer.serialize_str(self) + } +} + +impl<'a> Serialize for fmt::Arguments<'a> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_str(self) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[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 + where + S: Serializer, + { + serializer.serialize_bytes(self.to_bytes()) + } +} + +#[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 + where + S: Serializer, + { + serializer.serialize_bytes(self.to_bytes()) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl Serialize for Option +where + T: Serialize, +{ + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match *self { + Some(ref value) => serializer.serialize_some(value), + None => serializer.serialize_none(), + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl Serialize for PhantomData +where + T: ?Sized, +{ + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_unit_struct("PhantomData") + } +} + +//////////////////////////////////////////////////////////////////////////////// + +// Does not require T: Serialize. +impl Serialize for [T; 0] { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + tri!(serializer.serialize_tuple(0)).end() + } +} + +macro_rules! array_impls { + ($($len:tt)+) => { + $( + impl Serialize for [T; $len] + where + T: Serialize, + { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut seq = tri!(serializer.serialize_tuple($len)); + for e in self { + tri!(seq.serialize_element(e)); + } + seq.end() + } + } + )+ + } +} + +array_impls! { + 01 02 03 04 05 06 07 08 09 10 + 11 12 13 14 15 16 17 18 19 20 + 21 22 23 24 25 26 27 28 29 30 + 31 32 +} + +//////////////////////////////////////////////////////////////////////////////// + +impl Serialize for [T] +where + T: Serialize, +{ + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_seq(self) + } +} + +macro_rules! seq_impl { + ( + $(#[$attr:meta])* + $ty:ident + ) => { + $(#[$attr])* + impl Serialize for $ty + where + T: Serialize, + { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_seq(self) + } + } + } +} + +seq_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + BinaryHeap +} + +seq_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + BTreeSet +} + +seq_impl! { + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + HashSet +} + +seq_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + LinkedList +} + +seq_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + Vec +} + +seq_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + VecDeque +} + +//////////////////////////////////////////////////////////////////////////////// + +impl Serialize for Range +where + Idx: Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use super::SerializeStruct; + 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() + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl Serialize for RangeInclusive +where + Idx: Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use super::SerializeStruct; + 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() + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl Serialize for Bound +where + T: Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match *self { + Bound::Unbounded => serializer.serialize_unit_variant("Bound", 0, "Unbounded"), + Bound::Included(ref value) => { + serializer.serialize_newtype_variant("Bound", 1, "Included", value) + } + Bound::Excluded(ref value) => { + serializer.serialize_newtype_variant("Bound", 2, "Excluded", value) + } + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl Serialize for () { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_unit() + } +} + +#[cfg(feature = "unstable")] +#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] +impl Serialize for ! { + fn serialize(&self, _serializer: S) -> Result + where + S: Serializer, + { + *self + } +} + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! tuple_impls { + ($($len:expr => ($($n:tt $name:ident)+))+) => { + $( + #[cfg_attr(docsrs, doc(hidden))] + impl<$($name),+> Serialize for ($($name,)+) + where + $($name: Serialize,)+ + { + 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! { + 2 => (0 T0 1 T1) + 3 => (0 T0 1 T1 2 T2) + 4 => (0 T0 1 T1 2 T2 3 T3) + 5 => (0 T0 1 T1 2 T2 3 T3 4 T4) + 6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5) + 7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6) + 8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7) + 9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8) + 10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9) + 11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10) + 12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11) + 13 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12) + 14 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13) + 15 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14) + 16 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15) +} + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! map_impl { + ( + $(#[$attr:meta])* + $ty:ident + ) => { + $(#[$attr])* + impl Serialize for $ty + where + K: Serialize, + V: Serialize, + { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_map(self) + } + } + } +} + +map_impl! { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] + BTreeMap +} + +map_impl! { + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + HashMap +} + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! deref_impl { + ( + $(#[$attr:meta])* + <$($desc:tt)+ + ) => { + $(#[$attr])* + impl <$($desc)+ { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + (**self).serialize(serializer) + } + } + }; +} + +deref_impl! { + <'a, T> Serialize for &'a T where T: ?Sized + 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 +} + +deref_impl! { + /// This impl requires the [`"rc"`] Cargo feature of Serde. + /// + /// Serializing a data structure containing `Rc` will serialize a copy of + /// the contents of the `Rc` each time the `Rc` is referenced within the + /// data structure. Serialization will not attempt to deduplicate these + /// repeated data. + /// + /// [`"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")))))] + Serialize for Rc where T: ?Sized + Serialize +} + +deref_impl! { + /// This impl requires the [`"rc"`] Cargo feature of Serde. + /// + /// Serializing a data structure containing `Arc` will serialize a copy of + /// the contents of the `Arc` each time the `Arc` is referenced within the + /// data structure. Serialization will not attempt to deduplicate these + /// repeated data. + /// + /// [`"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")))))] + Serialize for Arc where T: ?Sized + Serialize +} + +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 +} + +//////////////////////////////////////////////////////////////////////////////// + +/// This impl requires the [`"rc"`] Cargo feature of Serde. +/// +/// [`"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")))) +)] +impl Serialize for RcWeak +where + T: ?Sized + Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.upgrade().serialize(serializer) + } +} + +/// This impl requires the [`"rc"`] Cargo feature of Serde. +/// +/// [`"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")))) +)] +impl Serialize for ArcWeak +where + T: ?Sized + Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.upgrade().serialize(serializer) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! nonzero_integers { + ($($T:ident,)+) => { + $( + impl Serialize for num::$T { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.get().serialize(serializer) + } + } + )+ + } +} + +nonzero_integers! { + NonZeroI8, + NonZeroI16, + NonZeroI32, + NonZeroI64, + NonZeroI128, + NonZeroIsize, + NonZeroU8, + NonZeroU16, + NonZeroU32, + NonZeroU64, + NonZeroU128, + NonZeroUsize, +} + +impl Serialize for Cell +where + T: Serialize + Copy, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.get().serialize(serializer) + } +} + +impl Serialize for RefCell +where + T: ?Sized + Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self.try_borrow() { + Ok(value) => value.serialize(serializer), + Err(_) => Err(S::Error::custom("already mutably borrowed")), + } + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl Serialize for Mutex +where + T: ?Sized + Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self.lock() { + Ok(locked) => locked.serialize(serializer), + Err(_) => Err(S::Error::custom("lock poison error while serializing")), + } + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl Serialize for RwLock +where + T: ?Sized + Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self.read() { + Ok(locked) => locked.serialize(serializer), + Err(_) => Err(S::Error::custom("lock poison error while serializing")), + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "result")] +#[cfg_attr(docsrs, doc(cfg(feature = "result")))] +impl Serialize for Result +where + T: Serialize, + E: Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match *self { + Result::Ok(ref value) => serializer.serialize_newtype_variant("Result", 0, "Ok", value), + Result::Err(ref value) => { + serializer.serialize_newtype_variant("Result", 1, "Err", value) + } + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl Serialize for Duration { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use super::SerializeStruct; + 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() + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[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 = 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() + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// Serialize a value that implements `Display` as a string, when that string is +/// 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(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 mut writer = crate::format::Buf::new(&mut buffer); + write!(&mut writer, "{}", $value).unwrap(); + $serializer.serialize_str(writer.as_str()) + }}; +} + +#[cfg(any(feature = "std", not(no_core_net)))] +impl Serialize for net::IpAddr { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + if serializer.is_human_readable() { + match *self { + net::IpAddr::V4(ref a) => a.serialize(serializer), + net::IpAddr::V6(ref a) => a.serialize(serializer), + } + } else { + match *self { + net::IpAddr::V4(ref a) => { + serializer.serialize_newtype_variant("IpAddr", 0, "V4", a) + } + net::IpAddr::V6(ref a) => { + serializer.serialize_newtype_variant("IpAddr", 1, "V6", a) + } + } + } + } +} + +#[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 + S: Serializer, + { + if serializer.is_human_readable() { + const MAX_LEN: usize = 15; + debug_assert_eq!(MAX_LEN, "101.102.103.104".len()); + 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(any(feature = "std", not(no_core_net)))] +impl Serialize for net::Ipv6Addr { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + if serializer.is_human_readable() { + const MAX_LEN: usize = 39; + debug_assert_eq!(MAX_LEN, "1001:1002:1003:1004:1005:1006:1007:1008".len()); + serialize_display_bounded_length!(self, MAX_LEN, serializer) + } else { + self.octets().serialize(serializer) + } + } +} + +#[cfg(any(feature = "std", not(no_core_net)))] +impl Serialize for net::SocketAddr { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + if serializer.is_human_readable() { + match *self { + net::SocketAddr::V4(ref addr) => addr.serialize(serializer), + net::SocketAddr::V6(ref addr) => addr.serialize(serializer), + } + } else { + match *self { + net::SocketAddr::V4(ref addr) => { + serializer.serialize_newtype_variant("SocketAddr", 0, "V4", addr) + } + net::SocketAddr::V6(ref addr) => { + serializer.serialize_newtype_variant("SocketAddr", 1, "V6", addr) + } + } + } + } +} + +#[cfg(any(feature = "std", not(no_core_net)))] +impl Serialize for net::SocketAddrV4 { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + if serializer.is_human_readable() { + const MAX_LEN: usize = 21; + debug_assert_eq!(MAX_LEN, "101.102.103.104:65000".len()); + serialize_display_bounded_length!(self, MAX_LEN, serializer) + } else { + (self.ip(), self.port()).serialize(serializer) + } + } +} + +#[cfg(any(feature = "std", not(no_core_net)))] +impl Serialize for net::SocketAddrV6 { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + if serializer.is_human_readable() { + const MAX_LEN: usize = 58; + debug_assert_eq!( + MAX_LEN, + "[1001:1002:1003:1004:1005:1006:1007:1008%4294967295]:65000".len() + ); + serialize_display_bounded_length!(self, MAX_LEN, serializer) + } else { + (self.ip(), self.port()).serialize(serializer) + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl Serialize for Path { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self.to_str() { + Some(s) => s.serialize(serializer), + None => Err(Error::custom("path contains invalid UTF-8 characters")), + } + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl Serialize for PathBuf { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_path().serialize(serializer) + } +} + +#[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 + where + S: Serializer, + { + use std::os::unix::ffi::OsStrExt; + serializer.serialize_newtype_variant("OsString", 0, "Unix", self.as_bytes()) + } + + #[cfg(windows)] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use std::os::windows::ffi::OsStrExt; + let val = self.encode_wide().collect::>(); + serializer.serialize_newtype_variant("OsString", 1, "Windows", &val) + } +} + +#[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 + S: Serializer, + { + self.as_os_str().serialize(serializer) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl Serialize for Wrapping +where + T: Serialize, +{ + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.0.serialize(serializer) + } +} + +#[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, +{ + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.0.serialize(serializer) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(all(feature = "std", not(no_std_atomic)))] +macro_rules! atomic_impl { + ($($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, + { + // Matches the atomic ordering used in libcore for the Debug impl + self.load(Ordering::Relaxed).serialize(serializer) + } + } + )* + } +} + +#[cfg(all(feature = "std", not(no_std_atomic)))] +atomic_impl! { + 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" +} diff --git a/third_party/crates/serde_core-1.0.229/src/ser/impossible.rs b/third_party/crates/serde_core-1.0.229/src/ser/impossible.rs new file mode 100644 index 0000000..fe69ae2 --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/src/ser/impossible.rs @@ -0,0 +1,216 @@ +//! This module contains `Impossible` serializer and its implementations. + +use crate::lib::*; + +use crate::ser::{ + self, Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, + SerializeTuple, SerializeTupleStruct, SerializeTupleVariant, +}; + +/// Helper type for implementing a `Serializer` that does not support +/// serializing one of the compound types. +/// +/// This type cannot be instantiated, but implements every one of the traits +/// corresponding to the [`Serializer`] compound types: [`SerializeSeq`], +/// [`SerializeTuple`], [`SerializeTupleStruct`], [`SerializeTupleVariant`], +/// [`SerializeMap`], [`SerializeStruct`], and [`SerializeStructVariant`]. +/// +/// ```edition2021 +/// # use serde::ser::{Serializer, Impossible}; +/// # use serde_core::__private::doc::Error; +/// # +/// # struct MySerializer; +/// # +/// impl Serializer for MySerializer { +/// type Ok = (); +/// type Error = Error; +/// +/// type SerializeSeq = Impossible<(), Error>; +/// /* other associated types */ +/// +/// /// This data format does not support serializing sequences. +/// fn serialize_seq(self, +/// len: Option) +/// -> Result { +/// // Given Impossible cannot be instantiated, the only +/// // thing we can do here is to return an error. +/// # stringify! { +/// Err(...) +/// # }; +/// # unimplemented!() +/// } +/// +/// /* other Serializer methods */ +/// # 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 +/// # } +/// } +/// ``` +/// +/// [`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, + error: PhantomData, +} + +enum Void {} + +impl SerializeSeq for Impossible +where + Error: ser::Error, +{ + type Ok = Ok; + type Error = Error; + + fn serialize_element(&mut self, value: &T) -> Result<(), Error> + where + T: ?Sized + Serialize, + { + let _ = value; + match self.void {} + } + + fn end(self) -> Result { + match self.void {} + } +} + +impl SerializeTuple for Impossible +where + Error: ser::Error, +{ + type Ok = Ok; + type Error = Error; + + fn serialize_element(&mut self, value: &T) -> Result<(), Error> + where + T: ?Sized + Serialize, + { + let _ = value; + match self.void {} + } + + fn end(self) -> Result { + match self.void {} + } +} + +impl SerializeTupleStruct for Impossible +where + Error: ser::Error, +{ + type Ok = Ok; + type Error = Error; + + fn serialize_field(&mut self, value: &T) -> Result<(), Error> + where + T: ?Sized + Serialize, + { + let _ = value; + match self.void {} + } + + fn end(self) -> Result { + match self.void {} + } +} + +impl SerializeTupleVariant for Impossible +where + Error: ser::Error, +{ + type Ok = Ok; + type Error = Error; + + fn serialize_field(&mut self, value: &T) -> Result<(), Error> + where + T: ?Sized + Serialize, + { + let _ = value; + match self.void {} + } + + fn end(self) -> Result { + match self.void {} + } +} + +impl SerializeMap for Impossible +where + Error: ser::Error, +{ + type Ok = Ok; + type Error = Error; + + fn serialize_key(&mut self, key: &T) -> Result<(), Error> + where + T: ?Sized + Serialize, + { + let _ = key; + match self.void {} + } + + fn serialize_value(&mut self, value: &T) -> Result<(), Error> + where + T: ?Sized + Serialize, + { + let _ = value; + match self.void {} + } + + fn end(self) -> Result { + match self.void {} + } +} + +impl SerializeStruct for Impossible +where + Error: ser::Error, +{ + type Ok = Ok; + type Error = Error; + + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> + where + T: ?Sized + Serialize, + { + let _ = key; + let _ = value; + match self.void {} + } + + fn end(self) -> Result { + match self.void {} + } +} + +impl SerializeStructVariant for Impossible +where + Error: ser::Error, +{ + type Ok = Ok; + type Error = Error; + + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Error> + where + T: ?Sized + Serialize, + { + let _ = key; + let _ = value; + match self.void {} + } + + fn end(self) -> Result { + match self.void {} + } +} diff --git a/third_party/crates/serde_core-1.0.229/src/ser/mod.rs b/third_party/crates/serde_core-1.0.229/src/ser/mod.rs new file mode 100644 index 0000000..62e59d9 --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/src/ser/mod.rs @@ -0,0 +1,2010 @@ +//! Generic data structure serialization framework. +//! +//! The two most important traits in this module are [`Serialize`] and +//! [`Serializer`]. +//! +//! - **A type that implements `Serialize` is a data structure** that can be +//! serialized to any data format supported by Serde, and conversely +//! - **A type that implements `Serializer` is a data format** that can +//! serialize any data structure supported by Serde. +//! +//! # The Serialize trait +//! +//! Serde provides [`Serialize`] implementations for many Rust primitive and +//! standard library types. The complete list is below. 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 your program. See the [derive section of the manual] for how to use this. +//! +//! In rare cases it may be necessary to implement [`Serialize`] manually for +//! some type in your program. See the [Implementing `Serialize`] section of the +//! manual for more about this. +//! +//! Third-party crates may provide [`Serialize`] implementations for types that +//! they expose. For example the [`linked-hash-map`] crate provides a +//! [`LinkedHashMap`] type that is serializable by Serde because the crate +//! provides an implementation of [`Serialize`] for it. +//! +//! # The Serializer trait +//! +//! [`Serializer`] implementations are provided by third-party crates, for +//! example [`serde_json`], [`serde_yaml`] and [`postcard`]. +//! +//! A partial list of well-maintained formats is given on the [Serde +//! website][data formats]. +//! +//! # Implementations of Serialize provided by Serde +//! +//! - **Primitive types**: +//! - bool +//! - i8, i16, i32, i64, i128, isize +//! - u8, u16, u32, u64, u128, usize +//! - f32, f64 +//! - char +//! - str +//! - &T and &mut T +//! - **Compound types**: +//! - \[T\] +//! - \[T; 0\] through \[T; 32\] +//! - tuples up to size 16 +//! - **Common standard library types**: +//! - String +//! - Option\ +//! - Result\ +//! - PhantomData\ +//! - **Wrapper types**: +//! - Box\ +//! - Cow\<'a, T\> +//! - Cell\ +//! - RefCell\ +//! - Mutex\ +//! - RwLock\ +//! - Rc\ *(if* features = \["rc"\] *is enabled)* +//! - Arc\ *(if* features = \["rc"\] *is enabled)* +//! - **Collection types**: +//! - BTreeMap\ +//! - BTreeSet\ +//! - BinaryHeap\ +//! - HashMap\ +//! - HashSet\ +//! - LinkedList\ +//! - VecDeque\ +//! - Vec\ +//! - **FFI types**: +//! - CStr +//! - CString +//! - OsStr +//! - OsString +//! - **Miscellaneous standard library types**: +//! - Duration +//! - SystemTime +//! - Path +//! - PathBuf +//! - Range\ +//! - RangeInclusive\ +//! - Bound\ +//! - num::NonZero* +//! - `!` *(unstable)* +//! - **Net types**: +//! - IpAddr +//! - Ipv4Addr +//! - Ipv6Addr +//! - SocketAddr +//! - SocketAddrV4 +//! - SocketAddrV6 +//! +//! [Implementing `Serialize`]: https://serde.rs/impl-serialize.html +//! [`LinkedHashMap`]: https://docs.rs/linked-hash-map/*/linked_hash_map/struct.LinkedHashMap.html +//! [`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 +//! [`serde_yaml`]: https://github.com/dtolnay/serde-yaml +//! [derive section of the manual]: https://serde.rs/derive.html +//! [data formats]: https://serde.rs/#data-formats + +use crate::lib::*; + +mod fmt; +mod impls; +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; + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! declare_error_trait { + (Error: Sized $(+ $($supertrait:ident)::+)*) => { + /// Trait used by `Serialize` implementations to generically construct + /// errors belonging to the `Serializer` against which they are + /// currently running. + /// + /// # Example implementation + /// + /// The [example data format] presented on the website shows an error + /// 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. + /// + /// The message should not be capitalized and should not end with a + /// period. + /// + /// For example, a filesystem [`Path`] may refuse to serialize + /// itself if it contains invalid UTF-8 data. + /// + /// ```edition2021 + /// # struct Path; + /// # + /// # impl Path { + /// # fn to_str(&self) -> Option<&str> { + /// # unimplemented!() + /// # } + /// # } + /// # + /// use serde::ser::{self, Serialize, Serializer}; + /// + /// impl Serialize for Path { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// match self.to_str() { + /// Some(s) => serializer.serialize_str(s), + /// None => Err(ser::Error::custom("path contains invalid UTF-8 characters")), + /// } + /// } + /// } + /// ``` + /// + /// [`Path`]: std::path::Path + /// [`Serialize`]: crate::Serialize + fn custom(msg: T) -> Self + where + T: Display; + } + } +} + +#[cfg(feature = "std")] +declare_error_trait!(Error: Sized + StdError); + +#[cfg(not(feature = "std"))] +declare_error_trait!(Error: Sized + Debug + Display); + +//////////////////////////////////////////////////////////////////////////////// + +/// A **data structure** that can be serialized into any data format supported +/// by Serde. +/// +/// Serde provides `Serialize` implementations for many Rust primitive and +/// 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 +/// your program. See the [derive section of the manual] for how to use this. +/// +/// In rare cases it may be necessary to implement `Serialize` manually for some +/// type in your program. See the [Implementing `Serialize`] section of the +/// manual for more about this. +/// +/// Third-party crates may provide `Serialize` implementations for types that +/// they expose. For example the [`linked-hash-map`] crate provides a +/// [`LinkedHashMap`] type that is serializable by Serde because the crate +/// provides an implementation of `Serialize` for it. +/// +/// [Implementing `Serialize`]: https://serde.rs/impl-serialize.html +/// [`LinkedHashMap`]: https://docs.rs/linked-hash-map/*/linked_hash_map/struct.LinkedHashMap.html +/// [`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 +#[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. + /// + /// ```edition2021 + /// use serde::ser::{Serialize, SerializeStruct, Serializer}; + /// + /// struct Person { + /// name: String, + /// age: u8, + /// phones: Vec, + /// } + /// + /// // This is what #[derive(Serialize)] would generate. + /// impl Serialize for Person { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// let mut s = serializer.serialize_struct("Person", 3)?; + /// s.serialize_field("name", &self.name)?; + /// s.serialize_field("age", &self.age)?; + /// s.serialize_field("phones", &self.phones)?; + /// s.end() + /// } + /// } + /// ``` + /// + /// [Implementing `Serialize`]: https://serde.rs/impl-serialize.html + fn serialize(&self, serializer: S) -> Result + where + S: Serializer; +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A **data format** that can serialize any data structure supported by Serde. +/// +/// The role of this trait is to define the serialization half of the [Serde +/// data model], which is a way to categorize every Rust data structure into one +/// of 29 possible types. Each method of the `Serializer` trait corresponds to +/// one of the types of the data model. +/// +/// Implementations of `Serialize` map themselves into this data model by +/// invoking exactly one of the `Serializer` methods. +/// +/// The types that make up the Serde data model are: +/// +/// - **14 primitive types** +/// - bool +/// - i8, i16, i32, i64, i128 +/// - u8, u16, u32, u64, u128 +/// - f32, f64 +/// - char +/// - **string** +/// - UTF-8 bytes with a length and no null terminator. +/// - When serializing, all strings are handled equally. When deserializing, +/// there are three flavors of strings: transient, owned, and borrowed. +/// - **byte array** - \[u8\] +/// - Similar to strings, during deserialization byte arrays can be +/// transient, owned, or borrowed. +/// - **option** +/// - Either none or some value. +/// - **unit** +/// - The type of `()` in Rust. It represents an anonymous value containing +/// no data. +/// - **unit_struct** +/// - For example `struct Unit` or `PhantomData`. It represents a named +/// value containing no data. +/// - **unit_variant** +/// - For example the `E::A` and `E::B` in `enum E { A, B }`. +/// - **newtype_struct** +/// - For example `struct Millimeters(u8)`. +/// - **newtype_variant** +/// - For example the `E::N` in `enum E { N(u8) }`. +/// - **seq** +/// - A variably sized heterogeneous sequence of values, for example +/// `Vec` or `HashSet`. When serializing, the length may or may not +/// be known before iterating through all the data. When deserializing, +/// the length is determined by looking at the serialized data. +/// - **tuple** +/// - A statically sized heterogeneous sequence of values for which the +/// length will be known at deserialization time without looking at the +/// serialized data, for example `(u8,)` or `(String, u64, Vec)` or +/// `[u64; 10]`. +/// - **tuple_struct** +/// - A named tuple, for example `struct Rgb(u8, u8, u8)`. +/// - **tuple_variant** +/// - For example the `E::T` in `enum E { T(u8, u8) }`. +/// - **map** +/// - A heterogeneous key-value pairing, for example `BTreeMap`. +/// - **struct** +/// - A heterogeneous key-value pairing in which the keys are strings and +/// will be known at deserialization time without looking at the +/// serialized data, for example `struct S { r: u8, g: u8, b: u8 }`. +/// - **struct_variant** +/// - 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 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 +/// output. +/// +/// [Serde data model]: https://serde.rs/data-model.html +/// +/// # Example implementation +/// +/// The [example data format] presented on the website contains example code for +/// 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 + /// should set `Ok = ()` and serialize into an [`io::Write`] or buffer + /// contained within the `Serializer` instance. Serializers that build + /// in-memory data structures may be simplified by using `Ok` to propagate + /// the data structure around. + /// + /// [`io::Write`]: std::io::Write + type Ok; + + /// The error type when some error occurs during serialization. + type Error: Error; + + /// Type returned from [`serialize_seq`] for serializing the content of the + /// sequence. + /// + /// [`serialize_seq`]: #tymethod.serialize_seq + type SerializeSeq: SerializeSeq; + + /// Type returned from [`serialize_tuple`] for serializing the content of + /// the tuple. + /// + /// [`serialize_tuple`]: #tymethod.serialize_tuple + type SerializeTuple: SerializeTuple; + + /// Type returned from [`serialize_tuple_struct`] for serializing the + /// content of the tuple struct. + /// + /// [`serialize_tuple_struct`]: #tymethod.serialize_tuple_struct + type SerializeTupleStruct: SerializeTupleStruct; + + /// Type returned from [`serialize_tuple_variant`] for serializing the + /// content of the tuple variant. + /// + /// [`serialize_tuple_variant`]: #tymethod.serialize_tuple_variant + type SerializeTupleVariant: SerializeTupleVariant; + + /// Type returned from [`serialize_map`] for serializing the content of the + /// map. + /// + /// [`serialize_map`]: #tymethod.serialize_map + type SerializeMap: SerializeMap; + + /// Type returned from [`serialize_struct`] for serializing the content of + /// the struct. + /// + /// [`serialize_struct`]: #tymethod.serialize_struct + type SerializeStruct: SerializeStruct; + + /// Type returned from [`serialize_struct_variant`] for serializing the + /// content of the struct variant. + /// + /// [`serialize_struct_variant`]: #tymethod.serialize_struct_variant + type SerializeStructVariant: SerializeStructVariant; + + /// Serialize a `bool` value. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for bool { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_bool(*self) + /// } + /// } + /// ``` + fn serialize_bool(self, v: bool) -> Result; + + /// Serialize an `i8` value. + /// + /// If the format does not differentiate between `i8` and `i64`, a + /// reasonable implementation would be to cast the value to `i64` and + /// forward to `serialize_i64`. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for i8 { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_i8(*self) + /// } + /// } + /// ``` + fn serialize_i8(self, v: i8) -> Result; + + /// Serialize an `i16` value. + /// + /// If the format does not differentiate between `i16` and `i64`, a + /// reasonable implementation would be to cast the value to `i64` and + /// forward to `serialize_i64`. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for i16 { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_i16(*self) + /// } + /// } + /// ``` + fn serialize_i16(self, v: i16) -> Result; + + /// Serialize an `i32` value. + /// + /// If the format does not differentiate between `i32` and `i64`, a + /// reasonable implementation would be to cast the value to `i64` and + /// forward to `serialize_i64`. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for i32 { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_i32(*self) + /// } + /// } + /// ``` + fn serialize_i32(self, v: i32) -> Result; + + /// Serialize an `i64` value. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for i64 { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_i64(*self) + /// } + /// } + /// ``` + fn serialize_i64(self, v: i64) -> Result; + + /// 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. + /// + /// If the format does not differentiate between `u8` and `u64`, a + /// reasonable implementation would be to cast the value to `u64` and + /// forward to `serialize_u64`. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for u8 { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_u8(*self) + /// } + /// } + /// ``` + fn serialize_u8(self, v: u8) -> Result; + + /// Serialize a `u16` value. + /// + /// If the format does not differentiate between `u16` and `u64`, a + /// reasonable implementation would be to cast the value to `u64` and + /// forward to `serialize_u64`. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for u16 { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_u16(*self) + /// } + /// } + /// ``` + fn serialize_u16(self, v: u16) -> Result; + + /// Serialize a `u32` value. + /// + /// If the format does not differentiate between `u32` and `u64`, a + /// reasonable implementation would be to cast the value to `u64` and + /// forward to `serialize_u64`. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for u32 { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_u32(*self) + /// } + /// } + /// ``` + fn serialize_u32(self, v: u32) -> Result; + + /// Serialize a `u64` value. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for u64 { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_u64(*self) + /// } + /// } + /// ``` + fn serialize_u64(self, v: u64) -> Result; + + /// 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. + /// + /// If the format does not differentiate between `f32` and `f64`, a + /// reasonable implementation would be to cast the value to `f64` and + /// forward to `serialize_f64`. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for f32 { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_f32(*self) + /// } + /// } + /// ``` + fn serialize_f32(self, v: f32) -> Result; + + /// Serialize an `f64` value. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for f64 { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_f64(*self) + /// } + /// } + /// ``` + fn serialize_f64(self, v: f64) -> Result; + + /// Serialize a character. + /// + /// If the format does not support characters, it is reasonable to serialize + /// it as a single element `str` or a `u32`. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for char { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_char(*self) + /// } + /// } + /// ``` + fn serialize_char(self, v: char) -> Result; + + /// Serialize a `&str`. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for str { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_str(self) + /// } + /// } + /// ``` + fn serialize_str(self, v: &str) -> Result; + + /// Serialize a chunk of raw byte data. + /// + /// Enables serializers to serialize byte slices more compactly or more + /// efficiently than other types of slices. If no efficient implementation + /// is available, a reasonable implementation would be to forward to + /// `serialize_seq`. If forwarded, the implementation looks usually just + /// like this: + /// + /// ```edition2021 + /// # use serde::ser::{Serializer, SerializeSeq}; + /// # use serde_core::__private::doc::Error; + /// # + /// # struct MySerializer; + /// # + /// # impl Serializer for MySerializer { + /// # type Ok = (); + /// # type Error = Error; + /// # + /// fn serialize_bytes(self, v: &[u8]) -> Result { + /// let mut seq = self.serialize_seq(Some(v.len()))?; + /// for b in v { + /// seq.serialize_element(b)?; + /// } + /// seq.end() + /// } + /// # + /// # 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 + /// # } + /// # } + /// ``` + fn serialize_bytes(self, v: &[u8]) -> Result; + + /// Serialize a [`None`] value. + /// + /// ```edition2021 + /// # use serde::{Serialize, Serializer}; + /// # + /// # enum Option { + /// # Some(T), + /// # None, + /// # } + /// # + /// # use self::Option::{Some, None}; + /// # + /// impl Serialize for Option + /// where + /// T: Serialize, + /// { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// match *self { + /// Some(ref value) => serializer.serialize_some(value), + /// None => serializer.serialize_none(), + /// } + /// } + /// } + /// # + /// # fn main() {} + /// ``` + /// + /// [`None`]: core::option::Option::None + fn serialize_none(self) -> Result; + + /// Serialize a [`Some(T)`] value. + /// + /// ```edition2021 + /// # use serde::{Serialize, Serializer}; + /// # + /// # enum Option { + /// # Some(T), + /// # None, + /// # } + /// # + /// # use self::Option::{Some, None}; + /// # + /// impl Serialize for Option + /// where + /// T: Serialize, + /// { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// match *self { + /// Some(ref value) => serializer.serialize_some(value), + /// None => serializer.serialize_none(), + /// } + /// } + /// } + /// # + /// # fn main() {} + /// ``` + /// + /// [`Some(T)`]: core::option::Option::Some + fn serialize_some(self, value: &T) -> Result + where + T: ?Sized + Serialize; + + /// Serialize a `()` value. + /// + /// ```edition2021 + /// # use serde::Serializer; + /// # + /// # serde_core::__private_serialize!(); + /// # + /// impl Serialize for () { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_unit() + /// } + /// } + /// ``` + fn serialize_unit(self) -> Result; + + /// Serialize a unit struct like `struct Unit` or `PhantomData`. + /// + /// A reasonable implementation would be to forward to `serialize_unit`. + /// + /// ```edition2021 + /// use serde::{Serialize, Serializer}; + /// + /// struct Nothing; + /// + /// impl Serialize for Nothing { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_unit_struct("Nothing") + /// } + /// } + /// ``` + fn serialize_unit_struct(self, name: &'static str) -> Result; + + /// Serialize a unit variant like `E::A` in `enum E { A, B }`. + /// + /// The `name` is the name of the enum, the `variant_index` is the index of + /// this variant within the enum, and the `variant` is the name of the + /// variant. + /// + /// ```edition2021 + /// use serde::{Serialize, Serializer}; + /// + /// enum E { + /// A, + /// B, + /// } + /// + /// impl Serialize for E { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// match *self { + /// E::A => serializer.serialize_unit_variant("E", 0, "A"), + /// E::B => serializer.serialize_unit_variant("E", 1, "B"), + /// } + /// } + /// } + /// ``` + fn serialize_unit_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + ) -> Result; + + /// Serialize a newtype struct like `struct Millimeters(u8)`. + /// + /// Serializers are encouraged to treat newtype structs as insignificant + /// wrappers around the data they contain. A reasonable implementation would + /// be to forward to `value.serialize(self)`. + /// + /// ```edition2021 + /// use serde::{Serialize, Serializer}; + /// + /// struct Millimeters(u8); + /// + /// impl Serialize for Millimeters { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.serialize_newtype_struct("Millimeters", &self.0) + /// } + /// } + /// ``` + fn serialize_newtype_struct( + self, + name: &'static str, + value: &T, + ) -> Result + where + T: ?Sized + Serialize; + + /// Serialize a newtype variant like `E::N` in `enum E { N(u8) }`. + /// + /// The `name` is the name of the enum, the `variant_index` is the index of + /// this variant within the enum, and the `variant` is the name of the + /// variant. The `value` is the data contained within this newtype variant. + /// + /// ```edition2021 + /// use serde::{Serialize, Serializer}; + /// + /// enum E { + /// M(String), + /// N(u8), + /// } + /// + /// impl Serialize for E { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// match *self { + /// E::M(ref s) => serializer.serialize_newtype_variant("E", 0, "M", s), + /// E::N(n) => serializer.serialize_newtype_variant("E", 1, "N", &n), + /// } + /// } + /// } + /// ``` + fn serialize_newtype_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result + where + 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 + /// `end`. + /// + /// The argument is the number of elements in the sequence, which may or may + /// not be computable before the sequence is iterated. Some serializers only + /// support sequences whose length is known up front. + /// + /// ```edition2021 + /// # use std::marker::PhantomData; + /// # + /// # struct Vec(PhantomData); + /// # + /// # impl Vec { + /// # fn len(&self) -> usize { + /// # unimplemented!() + /// # } + /// # } + /// # + /// # impl<'a, T> IntoIterator for &'a Vec { + /// # type Item = &'a T; + /// # type IntoIter = Box>; + /// # + /// # fn into_iter(self) -> Self::IntoIter { + /// # unimplemented!() + /// # } + /// # } + /// # + /// use serde::ser::{Serialize, SerializeSeq, Serializer}; + /// + /// impl Serialize for Vec + /// where + /// T: Serialize, + /// { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// let mut seq = serializer.serialize_seq(Some(self.len()))?; + /// for element in self { + /// seq.serialize_element(element)?; + /// } + /// seq.end() + /// } + /// } + /// ``` + fn serialize_seq(self, len: Option) -> Result; + + /// Begin to serialize a statically sized sequence whose length will be + /// known at deserialization time without looking at the serialized data. + /// This call must be followed by zero or more calls to `serialize_element`, + /// then a call to `end`. + /// + /// ```edition2021 + /// use serde::ser::{Serialize, SerializeTuple, Serializer}; + /// + /// # mod fool { + /// # trait Serialize {} + /// impl Serialize for (A, B, C) + /// # {} + /// # } + /// # + /// # struct Tuple3(A, B, C); + /// # + /// # impl Serialize for Tuple3 + /// where + /// A: Serialize, + /// B: Serialize, + /// C: Serialize, + /// { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// let mut tup = serializer.serialize_tuple(3)?; + /// tup.serialize_element(&self.0)?; + /// tup.serialize_element(&self.1)?; + /// tup.serialize_element(&self.2)?; + /// tup.end() + /// } + /// } + /// ``` + /// + /// ```edition2021 + /// use serde::ser::{Serialize, SerializeTuple, Serializer}; + /// + /// const VRAM_SIZE: usize = 386; + /// struct Vram([u16; VRAM_SIZE]); + /// + /// impl Serialize for Vram { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// let mut seq = serializer.serialize_tuple(VRAM_SIZE)?; + /// for element in &self.0[..] { + /// seq.serialize_element(element)?; + /// } + /// seq.end() + /// } + /// } + /// ``` + fn serialize_tuple(self, len: usize) -> Result; + + /// Begin to serialize a tuple struct like `struct Rgb(u8, u8, u8)`. This + /// call must be followed by zero or more calls to `serialize_field`, then a + /// call to `end`. + /// + /// The `name` is the name of the tuple struct and the `len` is the number + /// of data fields that will be serialized. + /// + /// ```edition2021 + /// use serde::ser::{Serialize, SerializeTupleStruct, Serializer}; + /// + /// struct Rgb(u8, u8, u8); + /// + /// impl Serialize for Rgb { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// let mut ts = serializer.serialize_tuple_struct("Rgb", 3)?; + /// ts.serialize_field(&self.0)?; + /// ts.serialize_field(&self.1)?; + /// ts.serialize_field(&self.2)?; + /// ts.end() + /// } + /// } + /// ``` + fn serialize_tuple_struct( + self, + name: &'static str, + len: usize, + ) -> Result; + + /// Begin to serialize a tuple variant like `E::T` in `enum E { T(u8, u8) + /// }`. This call must be followed by zero or more calls to + /// `serialize_field`, then a call to `end`. + /// + /// 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. + /// + /// ```edition2021 + /// use serde::ser::{Serialize, SerializeTupleVariant, Serializer}; + /// + /// enum E { + /// T(u8, u8), + /// U(String, u32, u32), + /// } + /// + /// impl Serialize for E { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// match *self { + /// E::T(ref a, ref b) => { + /// let mut tv = serializer.serialize_tuple_variant("E", 0, "T", 2)?; + /// tv.serialize_field(a)?; + /// tv.serialize_field(b)?; + /// tv.end() + /// } + /// E::U(ref a, ref b, ref c) => { + /// let mut tv = serializer.serialize_tuple_variant("E", 1, "U", 3)?; + /// tv.serialize_field(a)?; + /// tv.serialize_field(b)?; + /// tv.serialize_field(c)?; + /// tv.end() + /// } + /// } + /// } + /// } + /// ``` + fn serialize_tuple_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result; + + /// Begin to serialize a map. This call must be followed by zero or more + /// calls to `serialize_key` and `serialize_value`, then a call to `end`. + /// + /// The argument is the number of elements in the map, which may or may not + /// be computable before the map is iterated. Some serializers only support + /// maps whose length is known up front. + /// + /// ```edition2021 + /// # use std::marker::PhantomData; + /// # + /// # struct HashMap(PhantomData, PhantomData); + /// # + /// # impl HashMap { + /// # fn len(&self) -> usize { + /// # unimplemented!() + /// # } + /// # } + /// # + /// # impl<'a, K, V> IntoIterator for &'a HashMap { + /// # type Item = (&'a K, &'a V); + /// # type IntoIter = Box>; + /// # + /// # fn into_iter(self) -> Self::IntoIter { + /// # unimplemented!() + /// # } + /// # } + /// # + /// use serde::ser::{Serialize, SerializeMap, Serializer}; + /// + /// impl Serialize for HashMap + /// where + /// K: Serialize, + /// V: Serialize, + /// { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// let mut map = serializer.serialize_map(Some(self.len()))?; + /// for (k, v) in self { + /// map.serialize_entry(k, v)?; + /// } + /// map.end() + /// } + /// } + /// ``` + fn serialize_map(self, len: Option) -> Result; + + /// Begin to serialize a struct like `struct Rgb { r: u8, g: u8, b: u8 }`. + /// This call must be followed by zero or more calls to `serialize_field`, + /// 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. `len` does not include fields + /// which are skipped with [`SerializeStruct::skip_field`]. + /// + /// ```edition2021 + /// use serde::ser::{Serialize, SerializeStruct, Serializer}; + /// + /// struct Rgb { + /// r: u8, + /// g: u8, + /// b: u8, + /// } + /// + /// impl Serialize for Rgb { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// let mut rgb = serializer.serialize_struct("Rgb", 3)?; + /// rgb.serialize_field("r", &self.r)?; + /// rgb.serialize_field("g", &self.g)?; + /// rgb.serialize_field("b", &self.b)?; + /// rgb.end() + /// } + /// } + /// ``` + fn serialize_struct( + self, + name: &'static str, + len: usize, + ) -> Result; + + /// Begin to serialize a struct variant like `E::S` in `enum E { S { r: u8, + /// g: u8, b: u8 } }`. This call must be followed by zero or more calls to + /// `serialize_field`, then a call to `end`. + /// + /// 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`]. + /// + /// ```edition2021 + /// use serde::ser::{Serialize, SerializeStructVariant, Serializer}; + /// + /// enum E { + /// S { r: u8, g: u8, b: u8 }, + /// } + /// + /// impl Serialize for E { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// match *self { + /// E::S { + /// ref r, + /// ref g, + /// ref b, + /// } => { + /// let mut sv = serializer.serialize_struct_variant("E", 0, "S", 3)?; + /// sv.serialize_field("r", r)?; + /// sv.serialize_field("g", g)?; + /// sv.serialize_field("b", b)?; + /// sv.end() + /// } + /// } + /// } + /// } + /// ``` + fn serialize_struct_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result; + + /// Collect an iterator as a sequence. + /// + /// The default implementation serializes each item yielded by the iterator + /// using [`serialize_seq`]. Implementors should not need to override this + /// method. + /// + /// ```edition2021 + /// use serde::{Serialize, Serializer}; + /// + /// struct SecretlyOneHigher { + /// data: Vec, + /// } + /// + /// impl Serialize for SecretlyOneHigher { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.collect_seq(self.data.iter().map(|x| x + 1)) + /// } + /// } + /// ``` + /// + /// [`serialize_seq`]: #tymethod.serialize_seq + fn collect_seq(self, iter: I) -> Result + where + I: IntoIterator, + ::Item: Serialize, + { + 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() + } + + /// Collect an iterator as a map. + /// + /// The default implementation serializes each pair yielded by the iterator + /// using [`serialize_map`]. Implementors should not need to override this + /// method. + /// + /// ```edition2021 + /// use serde::{Serialize, Serializer}; + /// use std::collections::BTreeSet; + /// + /// struct MapToUnit { + /// keys: BTreeSet, + /// } + /// + /// // Serializes as a map in which the values are all unit. + /// impl Serialize for MapToUnit { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.collect_map(self.keys.iter().map(|k| (k, ()))) + /// } + /// } + /// ``` + /// + /// [`serialize_map`]: #tymethod.serialize_map + fn collect_map(self, iter: I) -> Result + where + K: Serialize, + V: Serialize, + I: IntoIterator, + { + 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() + } + + /// Serialize a string produced by an implementation of `Display`. + /// + /// The default implementation builds a heap-allocated [`String`] and + /// delegates to [`serialize_str`]. Serializers are encouraged to provide a + /// more efficient implementation if possible. + /// + /// ```edition2021 + /// # struct DateTime; + /// # + /// # impl DateTime { + /// # fn naive_local(&self) -> () { () } + /// # fn offset(&self) -> () { () } + /// # } + /// # + /// use serde::{Serialize, Serializer}; + /// + /// impl Serialize for DateTime { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.collect_str(&format_args!("{:?}{:?}", self.naive_local(), self.offset())) + /// } + /// } + /// ``` + /// + /// [`serialize_str`]: Self::serialize_str + #[cfg(any(feature = "std", feature = "alloc"))] + fn collect_str(self, value: &T) -> Result + where + T: ?Sized + Display, + { + self.serialize_str(&value.to_string()) + } + + /// Serialize a string produced by an implementation of `Display`. + /// + /// Serializers that use `no_std` are required to provide an implementation + /// of this method. If no more sensible behavior is possible, the + /// implementation is expected to return an error. + /// + /// ```edition2021 + /// # struct DateTime; + /// # + /// # impl DateTime { + /// # fn naive_local(&self) -> () { () } + /// # fn offset(&self) -> () { () } + /// # } + /// # + /// use serde::{Serialize, Serializer}; + /// + /// impl Serialize for DateTime { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// serializer.collect_str(&format_args!("{:?}{:?}", self.naive_local(), self.offset())) + /// } + /// } + /// ``` + #[cfg(not(any(feature = "std", feature = "alloc")))] + fn collect_str(self, value: &T) -> Result + where + T: ?Sized + Display; + + /// Determine whether `Serialize` implementations should serialize in + /// human-readable form. + /// + /// 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 Postcard will prefer the + /// compact one. + /// + /// ```edition2021 + /// # use std::fmt::{self, Display}; + /// # + /// # struct Timestamp; + /// # + /// # impl Timestamp { + /// # fn seconds_since_epoch(&self) -> u64 { unimplemented!() } + /// # } + /// # + /// # impl Display for Timestamp { + /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// # unimplemented!() + /// # } + /// # } + /// # + /// use serde::{Serialize, Serializer}; + /// + /// impl Serialize for Timestamp { + /// fn serialize(&self, serializer: S) -> Result + /// where + /// S: Serializer, + /// { + /// if serializer.is_human_readable() { + /// // Serialize to a human-readable string "2015-05-15T17:01:00Z". + /// self.to_string().serialize(serializer) + /// } else { + /// // Serialize to a compact binary representation. + /// self.seconds_since_epoch().serialize(serializer) + /// } + /// } + /// } + /// ``` + /// + /// The default implementation of this method returns `true`. Data formats + /// may override this to `false` to request a compact form for types that + /// support one. Note that modifying this method to change a format from + /// human-readable to compact or vice versa should be regarded as a breaking + /// change, as a value serialized in human-readable mode is not required to + /// deserialize from the same data in compact mode. + #[inline] + fn is_human_readable(&self) -> bool { + true + } +} + +/// Returned from `Serializer::serialize_seq`. +/// +/// # Example use +/// +/// ```edition2021 +/// # use std::marker::PhantomData; +/// # +/// # struct Vec(PhantomData); +/// # +/// # impl Vec { +/// # fn len(&self) -> usize { +/// # unimplemented!() +/// # } +/// # } +/// # +/// # impl<'a, T> IntoIterator for &'a Vec { +/// # type Item = &'a T; +/// # type IntoIter = Box>; +/// # fn into_iter(self) -> Self::IntoIter { +/// # unimplemented!() +/// # } +/// # } +/// # +/// use serde::ser::{Serialize, SerializeSeq, Serializer}; +/// +/// impl Serialize for Vec +/// where +/// T: Serialize, +/// { +/// fn serialize(&self, serializer: S) -> Result +/// where +/// S: Serializer, +/// { +/// let mut seq = serializer.serialize_seq(Some(self.len()))?; +/// for element in self { +/// seq.serialize_element(element)?; +/// } +/// seq.end() +/// } +/// } +/// ``` +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// 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; + + /// Must match the `Error` type of our `Serializer`. + type Error: Error; + + /// Serialize a sequence element. + fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> + where + T: ?Sized + Serialize; + + /// Finish serializing a sequence. + fn end(self) -> Result; +} + +/// Returned from `Serializer::serialize_tuple`. +/// +/// # Example use +/// +/// ```edition2021 +/// use serde::ser::{Serialize, SerializeTuple, Serializer}; +/// +/// # mod fool { +/// # trait Serialize {} +/// impl Serialize for (A, B, C) +/// # {} +/// # } +/// # +/// # struct Tuple3(A, B, C); +/// # +/// # impl Serialize for Tuple3 +/// where +/// A: Serialize, +/// B: Serialize, +/// C: Serialize, +/// { +/// fn serialize(&self, serializer: S) -> Result +/// where +/// S: Serializer, +/// { +/// let mut tup = serializer.serialize_tuple(3)?; +/// tup.serialize_element(&self.0)?; +/// tup.serialize_element(&self.1)?; +/// tup.serialize_element(&self.2)?; +/// tup.end() +/// } +/// } +/// ``` +/// +/// ```edition2021 +/// # use std::marker::PhantomData; +/// # +/// # struct Array(PhantomData); +/// # +/// # impl Array { +/// # fn len(&self) -> usize { +/// # unimplemented!() +/// # } +/// # } +/// # +/// # impl<'a, T> IntoIterator for &'a Array { +/// # type Item = &'a T; +/// # type IntoIter = Box>; +/// # fn into_iter(self) -> Self::IntoIter { +/// # unimplemented!() +/// # } +/// # } +/// # +/// use serde::ser::{Serialize, SerializeTuple, Serializer}; +/// +/// # mod fool { +/// # trait Serialize {} +/// impl Serialize for [T; 16] +/// # {} +/// # } +/// # +/// # impl Serialize for Array +/// where +/// T: Serialize, +/// { +/// fn serialize(&self, serializer: S) -> Result +/// where +/// S: Serializer, +/// { +/// let mut seq = serializer.serialize_tuple(16)?; +/// for element in self { +/// seq.serialize_element(element)?; +/// } +/// seq.end() +/// } +/// } +/// ``` +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// 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; + + /// Must match the `Error` type of our `Serializer`. + type Error: Error; + + /// Serialize a tuple element. + fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> + where + T: ?Sized + Serialize; + + /// Finish serializing a tuple. + fn end(self) -> Result; +} + +/// Returned from `Serializer::serialize_tuple_struct`. +/// +/// # Example use +/// +/// ```edition2021 +/// use serde::ser::{Serialize, SerializeTupleStruct, Serializer}; +/// +/// struct Rgb(u8, u8, u8); +/// +/// impl Serialize for Rgb { +/// fn serialize(&self, serializer: S) -> Result +/// where +/// S: Serializer, +/// { +/// let mut ts = serializer.serialize_tuple_struct("Rgb", 3)?; +/// ts.serialize_field(&self.0)?; +/// ts.serialize_field(&self.1)?; +/// ts.serialize_field(&self.2)?; +/// ts.end() +/// } +/// } +/// ``` +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// 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; + + /// Must match the `Error` type of our `Serializer`. + type Error: Error; + + /// Serialize a tuple struct field. + fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> + where + T: ?Sized + Serialize; + + /// Finish serializing a tuple struct. + fn end(self) -> Result; +} + +/// Returned from `Serializer::serialize_tuple_variant`. +/// +/// # Example use +/// +/// ```edition2021 +/// use serde::ser::{Serialize, SerializeTupleVariant, Serializer}; +/// +/// enum E { +/// T(u8, u8), +/// U(String, u32, u32), +/// } +/// +/// impl Serialize for E { +/// fn serialize(&self, serializer: S) -> Result +/// where +/// S: Serializer, +/// { +/// match *self { +/// E::T(ref a, ref b) => { +/// let mut tv = serializer.serialize_tuple_variant("E", 0, "T", 2)?; +/// tv.serialize_field(a)?; +/// tv.serialize_field(b)?; +/// tv.end() +/// } +/// E::U(ref a, ref b, ref c) => { +/// let mut tv = serializer.serialize_tuple_variant("E", 1, "U", 3)?; +/// tv.serialize_field(a)?; +/// tv.serialize_field(b)?; +/// tv.serialize_field(c)?; +/// tv.end() +/// } +/// } +/// } +/// } +/// ``` +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// 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; + + /// Must match the `Error` type of our `Serializer`. + type Error: Error; + + /// Serialize a tuple variant field. + fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> + where + T: ?Sized + Serialize; + + /// Finish serializing a tuple variant. + fn end(self) -> Result; +} + +/// Returned from `Serializer::serialize_map`. +/// +/// # Example use +/// +/// ```edition2021 +/// # use std::marker::PhantomData; +/// # +/// # struct HashMap(PhantomData, PhantomData); +/// # +/// # impl HashMap { +/// # fn len(&self) -> usize { +/// # unimplemented!() +/// # } +/// # } +/// # +/// # impl<'a, K, V> IntoIterator for &'a HashMap { +/// # type Item = (&'a K, &'a V); +/// # type IntoIter = Box>; +/// # +/// # fn into_iter(self) -> Self::IntoIter { +/// # unimplemented!() +/// # } +/// # } +/// # +/// use serde::ser::{Serialize, SerializeMap, Serializer}; +/// +/// impl Serialize for HashMap +/// where +/// K: Serialize, +/// V: Serialize, +/// { +/// fn serialize(&self, serializer: S) -> Result +/// where +/// S: Serializer, +/// { +/// let mut map = serializer.serialize_map(Some(self.len()))?; +/// for (k, v) in self { +/// map.serialize_entry(k, v)?; +/// } +/// map.end() +/// } +/// } +/// ``` +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// 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; + + /// Must match the `Error` type of our `Serializer`. + type Error: Error; + + /// Serialize a map key. + /// + /// If possible, `Serialize` implementations are encouraged to use + /// `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> + where + T: ?Sized + Serialize; + + /// Serialize a map value. + /// + /// # Panics + /// + /// 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> + where + T: ?Sized + Serialize; + + /// Serialize a map entry consisting of a key and a value. + /// + /// Some [`Serialize`] types are not able to hold a key and value in memory + /// at the same time so `SerializeMap` implementations are required to + /// support [`serialize_key`] and [`serialize_value`] individually. The + /// `serialize_entry` method allows serializers to optimize for the case + /// where key and value are both available. [`Serialize`] implementations + /// are encouraged to use `serialize_entry` if possible. + /// + /// The default implementation delegates to [`serialize_key`] and + /// [`serialize_value`]. This is appropriate for serializers that do not + /// care about performance or are not able to optimize `serialize_entry` any + /// better than this. + /// + /// [`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: ?Sized + Serialize, + V: ?Sized + Serialize, + { + tri!(self.serialize_key(key)); + self.serialize_value(value) + } + + /// Finish serializing a map. + fn end(self) -> Result; +} + +/// Returned from `Serializer::serialize_struct`. +/// +/// # Example use +/// +/// ```edition2021 +/// use serde::ser::{Serialize, SerializeStruct, Serializer}; +/// +/// struct Rgb { +/// r: u8, +/// g: u8, +/// b: u8, +/// } +/// +/// impl Serialize for Rgb { +/// fn serialize(&self, serializer: S) -> Result +/// where +/// S: Serializer, +/// { +/// let mut rgb = serializer.serialize_struct("Rgb", 3)?; +/// rgb.serialize_field("r", &self.r)?; +/// rgb.serialize_field("g", &self.g)?; +/// rgb.serialize_field("b", &self.b)?; +/// rgb.end() +/// } +/// } +/// ``` +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// 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; + + /// Must match the `Error` type of our `Serializer`. + type Error: Error; + + /// Serialize a struct field. + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> + where + 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; + Ok(()) + } + + /// Finish serializing a struct. + fn end(self) -> Result; +} + +/// Returned from `Serializer::serialize_struct_variant`. +/// +/// # Example use +/// +/// ```edition2021 +/// use serde::ser::{Serialize, SerializeStructVariant, Serializer}; +/// +/// enum E { +/// S { r: u8, g: u8, b: u8 }, +/// } +/// +/// impl Serialize for E { +/// fn serialize(&self, serializer: S) -> Result +/// where +/// S: Serializer, +/// { +/// match *self { +/// E::S { +/// ref r, +/// ref g, +/// ref b, +/// } => { +/// let mut sv = serializer.serialize_struct_variant("E", 0, "S", 3)?; +/// sv.serialize_field("r", r)?; +/// sv.serialize_field("g", g)?; +/// sv.serialize_field("b", b)?; +/// sv.end() +/// } +/// } +/// } +/// } +/// ``` +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// 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; + + /// Must match the `Error` type of our `Serializer`. + type Error: Error; + + /// Serialize a struct variant field. + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> + where + 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; + Ok(()) + } + + /// Finish serializing a struct variant. + fn end(self) -> Result; +} + +fn iterator_len_hint(iter: &I) -> Option +where + I: Iterator, +{ + match iter.size_hint() { + (lo, Some(hi)) if lo == hi => Some(lo), + _ => None, + } +} diff --git a/third_party/crates/serde_core-1.0.229/src/std_error.rs b/third_party/crates/serde_core-1.0.229/src/std_error.rs new file mode 100644 index 0000000..e026ace --- /dev/null +++ b/third_party/crates/serde_core-1.0.229/src/std_error.rs @@ -0,0 +1,48 @@ +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. +/// +/// Serde's error traits [`serde::ser::Error`] and [`serde::de::Error`] require +/// [`std::error::Error`] as a supertrait, but only when Serde is built with +/// "std" enabled. Data formats that don't care about no\_std support should +/// generally provide their error types with a `std::error::Error` impl +/// directly: +/// +/// ```edition2021 +/// #[derive(Debug)] +/// struct MySerError {...} +/// +/// impl serde::ser::Error for MySerError {...} +/// +/// impl std::fmt::Display for MySerError {...} +/// +/// // We don't support no_std! +/// impl std::error::Error for MySerError {} +/// ``` +/// +/// Data formats that *do* support no\_std may either have a "std" feature of +/// their own: +/// +/// ```toml +/// [features] +/// std = ["serde/std"] +/// ``` +/// +/// ```edition2021 +/// #[cfg(feature = "std")] +/// impl std::error::Error for MySerError {} +/// ``` +/// +/// ... or else provide the std Error impl unconditionally via Serde's +/// re-export: +/// +/// ```edition2021 +/// impl serde::ser::StdError for MySerError {} +/// ``` +pub trait Error: Debug + Display { + /// The underlying cause of this error, if any. + fn source(&self) -> Option<&(dyn Error + 'static)> { + None + } +} diff --git a/third_party/crates/serde_derive-1.0.229/.cargo-checksum.json b/third_party/crates/serde_derive-1.0.229/.cargo-checksum.json new file mode 100644 index 0000000..b374fbb --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/.cargo-checksum.json @@ -0,0 +1 @@ +{"$comment":"This file only protects against accidental modifications. It is not a security mechanism and does not protect against malicious changes.","files":{".cargo_vcs_info.json":"0b5d17eb470ba78f4d915159f7545c9178e21e63b52e1c033f6c4cb97a0f188a","Cargo.lock":"745122d422b997c60bdae98ca48376f2fa2e8817fb02ba6b2db4160ae1fb0088","Cargo.toml":"d2581160ffa61baa386f882e08b0db20051dc3c782a82268d6473998b61c926e","Cargo.toml.orig":"c8e1a7cff52301a94da8bb1a1eeff9e729bf0c5cab63945a1633b7808f82c91c","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"0a33359b87747c0ae2437374c1dd4fc4d151ae3122b3931e2757b45d0ed519b8","crates-io.md":"00b72e63d4f3393e28f9a219c8cb8c122013d82f0d10d6d551e239b13c5ba9e4","src/bound.rs":"7daa248b3b1121bba90c5a184bbd9b630d46bca4b4c1b5814df97f494bf1ee9e","src/de.rs":"a04fdb321ce47b479b42b2dd0ca1cfd57db88e06451d7dc95303c582fedc135c","src/de/enum_.rs":"5a099a25034e4f9364d421a53cfb4428ea8a94fd66515c66207bf8bfb7c4db4f","src/de/enum_adjacently.rs":"987d3a9fc7eda53776f0ccc3fbe64147ccfc8caf2ee202d3ad6432daf033a194","src/de/enum_externally.rs":"d001b7eab7f89165f29c7459a12c2baf4898c0ff456c219afabb5d19c20462e3","src/de/enum_internally.rs":"9d898dbc1c46262f695ef7ba1660b2af70de48e07bbac8f44b740326b7c5b303","src/de/enum_untagged.rs":"b66ad3cea36ee786d50270f6648f1075c1e615b5f04173b47f034a251df5220e","src/de/identifier.rs":"b653c26f4274e5c323e3f893c6f9a2b21bd5c873abdc2a801f0289a5e56a9f6c","src/de/struct_.rs":"7b26982ce59504a9bb5a18c3ab56eee2d75e70fd465774ff035d15c50452c118","src/de/tuple.rs":"5496ee711b935b17269960f4a0cfcb7d23de668db9489dfca7276ce1fcdf0f6f","src/de/unit.rs":"b792db7952fc2e4719fdce9552fe4ba1836086cc967ae9a5b919c28b30f2b4a0","src/deprecated.rs":"cff374e86ea5f134913a2a194a68d7c2510ffd5214956d10b9c496e90a20a952","src/dummy.rs":"dce9d53f7f6efb41043d6dbd741e03e65fe0a56b2f739a041184036cd7491b16","src/fragment.rs":"6757cb4c3131d4300f093572efc273c4ab5a20e3e1efb54a311dcfa52d0bd6eb","src/internals/ast.rs":"bc6244a25f536cfee82f14a29df25b7e9bc299a639debe702b9bb060c1ac99fb","src/internals/attr.rs":"7abe82fde303a3c31f967c13e0ee1afe49ea584d882b9d2c32b067888e1c8225","src/internals/case.rs":"10c8dda2b32d8c6c6b63cf09cdc63d02375af7e95ecefe8fecb34f93b65191bb","src/internals/check.rs":"86ea817316638ec33f70ecdf9634a31c934fd3df84533e3e315816dc130f0bff","src/internals/ctxt.rs":"79c058495febd402facbfa24d8a82d0d53fd91a6497ad4e9595a4dcca2e0e0bc","src/internals/mod.rs":"c1ece6bbce5a5e8a2bf5d6d9a29e85551258db9c610fab73ac19c6b7d8cf98fd","src/internals/name.rs":"9bc1553d7b493794cd436664ee6b43fccb914f271fa86705ae2937ae923a876f","src/internals/receiver.rs":"c75e0ba04602c5771d662004f32b82bf01e11c1905153ba4c073969788b75abe","src/internals/respan.rs":"899753859c58ce5f532a3ec4584796a52f13ed5a0533191e48c953ba5c1b52ff","src/internals/symbol.rs":"d2590f1c8356d6a10923476b558c39a85b77392ba09c92fa97e05e2c403e73c7","src/lib.rs":"9c8efaaaad77caa41178ca4316bff1ccbb7a864673d88639d258b7c5619a4ad4","src/pretend.rs":"b3e4928f49b1f380c91afc575733586e5bced5d76f02847736c267c00872df91","src/ser.rs":"18b3a4d06cd721c402835b17f008a63fdbaad379734f0fd4132aa28d8ea5c1de","src/this.rs":"87818dc80cbb521b51938a653d09daf10aafc220bb10425948de82ad670fcb85"},"package":"e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"} \ No newline at end of file diff --git a/third_party/crates/serde_derive-1.0.229/.cargo_vcs_info.json b/third_party/crates/serde_derive-1.0.229/.cargo_vcs_info.json new file mode 100644 index 0000000..0893822 --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "7fc3b4c30c94f73a96ebd1553f2b090d928fc3a8" + }, + "path_in_vcs": "serde_derive" +} \ No newline at end of file diff --git a/third_party/crates/serde_derive-1.0.229/BUILD.bazel b/third_party/crates/serde_derive-1.0.229/BUILD.bazel new file mode 100644 index 0000000..70b9202 --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/BUILD.bazel @@ -0,0 +1,118 @@ +############################################################################### +# @generated +# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To +# regenerate this file, run the following: +# +# bazel run @@//third_party:vendor_crates +############################################################################### + +load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") +load("@rules_rust//rust:defs.bzl", "rust_proc_macro") + +package(default_visibility = ["//visibility:public"]) + +cargo_toml_env_vars( + name = "cargo_toml_env_vars", + src = "Cargo.toml", +) + +rust_proc_macro( + name = "serde_derive", + srcs = glob( + include = ["**/*.rs"], + allow_empty = False, + ), + compile_data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + crate_features = [ + "default", + ], + crate_root = "src/lib.rs", + edition = "2021", + rustc_env_files = [ + ":cargo_toml_env_vars", + ], + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=serde_derive", + "manual", + "noclippy", + "norustfmt", + ], + target_compatible_with = select({ + "@rules_rust//rust/platform:aarch64-apple-darwin": [], + "@rules_rust//rust/platform:aarch64-apple-ios": [], + "@rules_rust//rust/platform:aarch64-apple-ios-macabi": [], + "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], + "@rules_rust//rust/platform:aarch64-linux-android": [], + "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], + "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], + "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-none": [], + "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], + "@rules_rust//rust/platform:aarch64-unknown-uefi": [], + "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], + "@rules_rust//rust/platform:armv7-linux-androideabi": [], + "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:i686-apple-darwin": [], + "@rules_rust//rust/platform:i686-linux-android": [], + "@rules_rust//rust/platform:i686-pc-windows-msvc": [], + "@rules_rust//rust/platform:i686-unknown-freebsd": [], + "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], + "@rules_rust//rust/platform:loongarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:mips-unknown-linux-gnu": [], + "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv32imac-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], + "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-netbsd": [], + "@rules_rust//rust/platform:sparc64-unknown-openbsd": [], + "@rules_rust//rust/platform:thumbv6m-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabihf": [], + "@rules_rust//rust/platform:thumbv7m-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabihf": [], + "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], + "@rules_rust//rust/platform:wasm32-unknown-unknown": [], + "@rules_rust//rust/platform:wasm32-wasip1": [], + "@rules_rust//rust/platform:wasm32-wasip1-threads": [], + "@rules_rust//rust/platform:wasm32-wasip2": [], + "@rules_rust//rust/platform:x86_64-apple-darwin": [], + "@rules_rust//rust/platform:x86_64-apple-ios": [], + "@rules_rust//rust/platform:x86_64-apple-ios-macabi": [], + "@rules_rust//rust/platform:x86_64-linux-android": [], + "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], + "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], + "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], + "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-none": [], + "@rules_rust//rust/platform:x86_64-unknown-uefi": [], + "//conditions:default": ["@platforms//:incompatible"], + }), + version = "1.0.229", + deps = [ + "//third_party/crates/proc-macro2-1.0.107:proc_macro2", + "//third_party/crates/quote-1.0.47:quote", + "//third_party/crates/syn-3.0.5:syn", + ], +) diff --git a/third_party/crates/serde_derive-1.0.229/Cargo.lock b/third_party/crates/serde_derive-1.0.229/Cargo.lock new file mode 100644 index 0000000..5aa966e --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/Cargo.lock @@ -0,0 +1,88 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive 1.0.228", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "syn 3.0.0", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fac314a64dc9a36e61a9eb4261a5e9bbfbc922b27e518af97bc32b926cf967" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" diff --git a/third_party/crates/serde_derive-1.0.229/Cargo.toml b/third_party/crates/serde_derive-1.0.229/Cargo.toml new file mode 100644 index 0000000..7d1f7a2 --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/Cargo.toml @@ -0,0 +1,87 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.71" +name = "serde_derive" +version = "1.0.229" +authors = [ + "Erick Tryzelaar ", + "David Tolnay ", +] +build = false +exclude = ["build.rs"] +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" +homepage = "https://serde.rs" +documentation = "https://serde.rs/derive.html" +readme = "crates-io.md" +keywords = [ + "serde", + "serialization", + "no_std", + "derive", +] +categories = [ + "no-std", + "no-std::no-alloc", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/serde-rs/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", +] + +[features] +default = [] +deserialize_in_place = [] + +[lib] +name = "serde_derive" +path = "src/lib.rs" +proc-macro = true + +[dependencies.proc-macro2] +version = "1.0.74" +features = ["proc-macro"] +default-features = false + +[dependencies.quote] +version = "1.0.35" +features = ["proc-macro"] +default-features = false + +[dependencies.syn] +version = "3" +features = [ + "clone-impls", + "derive", + "parsing", + "printing", + "proc-macro", +] +default-features = false + +[dev-dependencies.serde] +version = "1" diff --git a/third_party/crates/serde_derive-1.0.229/Cargo.toml.orig b/third_party/crates/serde_derive-1.0.229/Cargo.toml.orig new file mode 100644 index 0000000..6f35500 --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/Cargo.toml.orig @@ -0,0 +1,42 @@ +[package] +name = "serde_derive" +version = "1.0.229" +authors = ["Erick Tryzelaar ", "David Tolnay "] +categories = ["no-std", "no-std::no-alloc"] +description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" +documentation = "https://serde.rs/derive.html" +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" +repository = "https://github.com/serde-rs/serde" +rust-version = "1.71" + +[features] +default = [] +deserialize_in_place = [] + +[lib] +name = "serde_derive" +proc-macro = true + +[dependencies] +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", 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/third_party/crates/serde_derive-1.0.229/LICENSE-APACHE b/third_party/crates/serde_derive-1.0.229/LICENSE-APACHE new file mode 100644 index 0000000..1b5ec8b --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/third_party/crates/serde_derive-1.0.229/LICENSE-MIT b/third_party/crates/serde_derive-1.0.229/LICENSE-MIT new file mode 100644 index 0000000..31aa793 --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/crates/serde_derive-1.0.229/README.md b/third_party/crates/serde_derive-1.0.229/README.md new file mode 100644 index 0000000..681b874 --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/README.md @@ -0,0 +1,114 @@ +# Serde   [![Build Status]][actions] [![Latest Version]][crates.io] [![serde msrv]][Rust 1.56] [![serde_derive msrv]][Rust 1.71] + +[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 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.71]: https://blog.rust-lang.org/2023/07/13/Rust-1.71.0/ + +**Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.** + +--- + +You may be looking for: + +- [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.rs/serde) +- [Release notes](https://github.com/serde-rs/serde/releases) + +## Serde in action + + +

+ +```rust +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug)] +struct Point { + x: i32, + y: i32, +} + +fn main() { + let point = Point { x: 1, y: 2 }; + + // Convert the Point to a JSON string. + let serialized = serde_json::to_string(&point).unwrap(); + + // Prints serialized = {"x":1,"y":2} + println!("serialized = {}", serialized); + + // Convert the JSON string back to a Point. + let deserialized: Point = serde_json::from_str(&serialized).unwrap(); + + // Prints deserialized = Point { x: 1, y: 2 } + println!("deserialized = {:?}", deserialized); +} +``` + +## Getting help + +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 +[#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 +[discourse]: https://users.rust-lang.org + +
+ +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + diff --git a/third_party/crates/serde_derive-1.0.229/crates-io.md b/third_party/crates/serde_derive-1.0.229/crates-io.md new file mode 100644 index 0000000..e6e7d9f --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/crates-io.md @@ -0,0 +1,65 @@ + + +**Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.** + +--- + +You may be looking for: + +- [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.rs/serde) +- [Release notes](https://github.com/serde-rs/serde/releases) + +## Serde in action + +```rust +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug)] +struct Point { + x: i32, + y: i32, +} + +fn main() { + let point = Point { x: 1, y: 2 }; + + // Convert the Point to a JSON string. + let serialized = serde_json::to_string(&point).unwrap(); + + // Prints serialized = {"x":1,"y":2} + println!("serialized = {}", serialized); + + // Convert the JSON string back to a Point. + let deserialized: Point = serde_json::from_str(&serialized).unwrap(); + + // Prints deserialized = Point { x: 1, y: 2 } + println!("deserialized = {:?}", deserialized); +} +``` + +## Getting help + +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 +[#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 +[discourse]: https://users.rust-lang.org diff --git a/third_party/crates/serde_derive-1.0.229/src/bound.rs b/third_party/crates/serde_derive-1.0.229/src/bound.rs new file mode 100644 index 0000000..ea49e9f --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/src/bound.rs @@ -0,0 +1,431 @@ +use crate::internals::ast::{Container, Data}; +use crate::internals::{attr, ungroup}; +use proc_macro2::Span; +use std::collections::HashSet; +use syn::punctuated::{Pair, Punctuated}; +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 +// allowed here". +pub fn without_defaults(generics: &syn::Generics) -> syn::Generics { + syn::Generics { + params: generics + .params + .iter() + .map(|param| match param { + syn::GenericParam::Type(param) => syn::GenericParam::Type(syn::TypeParam { + default: None, + ..param.clone() + }), + _ => param.clone(), + }) + .collect(), + ..generics.clone() + } +} + +pub fn with_where_predicates( + generics: &syn::Generics, + predicates: &[syn::WherePredicate], +) -> syn::Generics { + let mut generics = generics.clone(); + let dst_predicates = &mut generics.make_where_clause().predicates; + + for predicate in predicates { + dst_predicates.push(predicate.clone()); + } + generics +} + +pub fn with_where_predicates_from_fields( + cont: &Container, + generics: &syn::Generics, + from_field: fn(&attr::Field) -> Option<&[syn::WherePredicate]>, +) -> syn::Generics { + let mut generics = generics.clone(); + let dst_predicates = &mut generics.make_where_clause().predicates; + + for field in cont.data.all_fields() { + let Some(predicate_slice) = from_field(&field.attrs) else { + continue; + }; + for inner_predicate in predicate_slice { + dst_predicates.push(inner_predicate.clone()); + } + } + generics +} + +pub fn with_where_predicates_from_variants( + cont: &Container, + generics: &syn::Generics, + from_variant: fn(&attr::Variant) -> Option<&[syn::WherePredicate]>, +) -> syn::Generics { + let variants = match &cont.data { + Data::Enum(variants) => variants, + Data::Struct(_, _) => { + return generics.clone(); + } + }; + let mut generics = generics.clone(); + let dst_predicates = &mut generics.make_where_clause().predicates; + + for variant in variants { + let Some(predicate_slice) = from_variant(&variant.attrs) else { + continue; + }; + for inner_predicate in predicate_slice { + dst_predicates.push(inner_predicate.clone()); + } + } + generics +} + +// Puts the given bound on any generic type parameters that are used in fields +// for which filter returns true. +// +// For example, the following struct needs the bound `A: Serialize, B: +// Serialize`. +// +// struct S<'b, A, B: 'b, C> { +// a: A, +// b: Option<&'b B> +// #[serde(skip_serializing)] +// c: C, +// } +pub fn with_bound( + cont: &Container, + generics: &syn::Generics, + filter: fn(&attr::Field, Option<&attr::Variant>) -> bool, + bound: &syn::Path, +) -> syn::Generics { + struct FindTyParams<'ast> { + // Set of all generic type parameters on the current struct (A, B, C in + // the example). Initialized up front. + all_type_params: HashSet, + + // Set of generic type parameters used in fields for which filter + // returns true (A and B in the example). Filled in as the visitor sees + // them. + relevant_type_params: HashSet, + + // Fields whose type is an associated type of one of the generic type + // parameters. + associated_type_usage: Vec<&'ast syn::TypePath>, + } + + 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() { + if self.all_type_params.contains(&t.ident) { + self.associated_type_usage.push(ty); + } + } + } + self.visit_type(&field.ty); + } + + fn visit_path(&mut self, path: &'ast syn::Path) { + if let Some(seg) = path.segments.last() { + if seg.ident == "PhantomData" { + // Hardcoded exception, because PhantomData implements + // Serialize and Deserialize whether or not T implements it. + return; + } + } + if path.leading_colon.is_none() && path.segments.len() == 1 { + let id = &path.segments[0].ident; + if self.all_type_params.contains(id) { + self.relevant_type_params.insert(id.clone()); + } + } + 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::FnPtr(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.ty); + } + 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. + // + // struct TypeMacro { + // mac: T!(), + // marker: PhantomData, + // } + fn visit_macro(&mut self, _mac: &'ast syn::Macro) {} + } + + let all_type_params = generics + .type_params() + .map(|param| param.ident.clone()) + .collect(); + + let mut visitor = FindTyParams { + all_type_params, + relevant_type_params: HashSet::new(), + associated_type_usage: Vec::new(), + }; + match &cont.data { + Data::Enum(variants) => { + for variant in variants { + for field in &variant.fields { + if filter(&field.attrs, Some(&variant.attrs)) { + visitor.visit_field(field.original); + } + } + } + } + Data::Struct(_, fields) => { + for field in fields { + if filter(&field.attrs, None) { + visitor.visit_field(field.original); + } + } + } + } + + let relevant_type_params = visitor.relevant_type_params; + let associated_type_usage = visitor.associated_type_usage; + + fn make_where_bounded_type( + bounded_ty: syn::TypePath, + bound: &syn::Path, + ) -> syn::WherePredicate { + syn::WherePredicate::Type(syn::PredicateType { + attrs: Vec::new(), + lifetimes: None, + // the type parameter that is being bounded e.g. T + bounded_ty: syn::Type::Path(bounded_ty), + colon_token: ::default(), + // the bound e.g. Serialize + bounds: { + let mut punct = Punctuated::new(); + punct.push(syn::TypeParamBound::Trait(syn::TraitBound { + paren_token: None, + lifetimes: None, + modifiers: syn::TraitBoundModifiers::default(), + maybe: None, + path: bound.clone(), + })); + punct + }, + }) + } + + let mut dst_generics = generics.clone(); + let dst_predicates = &mut dst_generics.make_where_clause().predicates; + for param in generics.type_params() { + let id = ¶m.ident; + if !relevant_type_params.contains(id) { + continue; + } + let bounded_ty = syn::TypePath { + attrs: Vec::new(), + qself: None, + path: id.clone().into(), + }; + dst_predicates.push(make_where_bounded_type(bounded_ty, bound)); + } + for bounded_ty in associated_type_usage { + dst_predicates.push(make_where_bounded_type(bounded_ty.clone(), bound)); + } + dst_generics +} + +pub fn with_self_bound( + cont: &Container, + generics: &syn::Generics, + bound: &syn::Path, +) -> syn::Generics { + let mut generics = generics.clone(); + generics + .make_where_clause() + .predicates + .push(syn::WherePredicate::Type(syn::PredicateType { + attrs: Vec::new(), + lifetimes: None, + // the type that is being bounded e.g. MyStruct<'a, T> + bounded_ty: type_of_item(cont), + colon_token: ::default(), + // the bound e.g. Default + bounds: vec![syn::TypeParamBound::Trait(syn::TraitBound { + paren_token: None, + lifetimes: None, + modifiers: syn::TraitBoundModifiers::default(), + maybe: None, + path: bound.clone(), + })] + .into_iter() + .collect(), + })); + generics +} + +pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Generics { + let bound = syn::Lifetime::new(lifetime, Span::call_site()); + let def = syn::LifetimeParam { + attrs: Vec::new(), + lifetime: bound.clone(), + colon_token: None, + bounds: Punctuated::new(), + }; + + let params = Some(syn::GenericParam::Lifetime(def)) + .into_iter() + .chain(generics.params.iter().cloned().map(|mut param| { + match &mut param { + syn::GenericParam::Lifetime(param) => { + param.bounds.push(bound.clone()); + } + syn::GenericParam::Type(param) => { + param + .bounds + .push(syn::TypeParamBound::Lifetime(bound.clone())); + } + syn::GenericParam::Const(_) => {} + } + param + })) + .collect(); + + syn::Generics { + params, + ..generics.clone() + } +} + +fn type_of_item(cont: &Container) -> syn::Type { + syn::Type::Path(syn::TypePath { + attrs: Vec::new(), + qself: None, + path: syn::Path { + leading_colon: None, + segments: vec![syn::PathSegment { + ident: cont.ident.clone(), + arguments: syn::PathArguments::AngleBracketed( + syn::AngleBracketedGenericArguments { + colon2_token: None, + lt_token: ::default(), + args: cont + .generics + .params + .iter() + .map(|param| match param { + syn::GenericParam::Type(param) => { + syn::GenericArgument::Type(syn::Type::Path(syn::TypePath { + attrs: Vec::new(), + qself: None, + path: param.ident.clone().into(), + })) + } + syn::GenericParam::Lifetime(param) => { + syn::GenericArgument::Lifetime(param.lifetime.clone()) + } + syn::GenericParam::Const(_) => { + panic!("Serde does not support const generics yet"); + } + }) + .collect(), + gt_token: ]>::default(), + }, + ), + }] + .into_iter() + .collect(), + }, + }) +} diff --git a/third_party/crates/serde_derive-1.0.229/src/de.rs b/third_party/crates/serde_derive-1.0.229/src/de.rs new file mode 100644 index 0000000..e7b8579 --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/src/de.rs @@ -0,0 +1,976 @@ +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::{parse_quote, Ident, Index, Member}; + +mod enum_; +mod enum_adjacently; +mod enum_externally; +mod enum_internally; +mod enum_untagged; +mod identifier; +mod struct_; +mod tuple; +mod unit; + +pub fn expand_derive_deserialize(input: &mut syn::DeriveInput) -> syn::Result { + replace_receiver(input); + + let ctxt = Ctxt::new(); + 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) = params.generics_with_de_lifetime(); + let body = Stmts(deserialize_body(&cont, ¶ms)); + let delife = params.borrowed.de_lifetime(); + 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, params.is_packed); + quote! { + #[automatically_derived] + #allow_deprecated + impl #de_impl_generics #ident #ty_generics #where_clause { + #vis fn deserialize<__D>(__deserializer: __D) -> _serde::#private::Result<#remote #ty_generics, __D::Error> + where + __D: _serde::Deserializer<#delife>, + { + #used + #body + } + } + } + } else { + let fn_deserialize_in_place = deserialize_in_place_body(&cont, ¶ms); + + quote! { + #[automatically_derived] + #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>, + { + #body + } + + #fn_deserialize_in_place + } + } + }; + + Ok(dummy::wrap_in_const( + cont.attrs.custom_serde_path(), + impl_block, + )) +} + +fn precondition(cx: &Ctxt, cont: &Container) { + precondition_sized(cx, cont); + precondition_no_de_lifetime(cx, cont); +} + +fn precondition_sized(cx: &Ctxt, cont: &Container) { + if let Data::Struct(_, fields) = &cont.data { + if let Some(last) = fields.last() { + if let syn::Type::Slice(_) = ungroup(last.ty) { + cx.error_spanned_by( + cont.original, + "cannot deserialize a dynamically sized struct", + ); + } + } + } +} + +fn precondition_no_de_lifetime(cx: &Ctxt, cont: &Container) { + if let BorrowedLifetimes::Borrowed(_) = borrowed_lifetimes(cont) { + for param in cont.generics.lifetimes() { + if param.lifetime.to_string() == "'de" { + cx.error_spanned_by( + ¶m.lifetime, + "cannot deserialize when there is a lifetime parameter called 'de", + ); + return; + } + } + } +} + +struct Parameters { + /// Name of the type the `derive` is on. + local: syn::Ident, + + /// Path to the type the impl is for. Either a single `Ident` for local + /// types (does not include generic parameters) or `some::remote::Path` for + /// remote types. + this_type: syn::Path, + + /// Same as `this_type` but using `::` 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, + + /// Lifetimes borrowed from the deserializer. These will become bounds on + /// the `'de` lifetime of the deserializer. + borrowed: BorrowedLifetimes, + + /// 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_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_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_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) + } +} + +// All the generics in the input, plus a bound `T: Deserialize` for each generic +// field type that will be deserialized by us, plus a bound `T: Default` for +// each generic field type that will be set to a default value. +fn build_generics(cont: &Container, borrowed: &BorrowedLifetimes) -> syn::Generics { + let generics = bound::without_defaults(cont.generics); + + let generics = bound::with_where_predicates_from_fields(cont, &generics, attr::Field::de_bound); + + let generics = + bound::with_where_predicates_from_variants(cont, &generics, attr::Variant::de_bound); + + match cont.attrs.de_bound() { + 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::#private::Default), + ), + attr::Default::None | attr::Default::Path(_) => generics, + }; + + let delife = borrowed.de_lifetime(); + let generics = bound::with_bound( + cont, + &generics, + needs_deserialize_bound, + &parse_quote!(_serde::Deserialize<#delife>), + ); + + bound::with_bound( + cont, + &generics, + requires_default, + &parse_quote!(_serde::#private::Default), + ) + } + } +} + +// Fields with a `skip_deserializing` or `deserialize_with` attribute, or which +// belong to a variant with a `skip_deserializing` or `deserialize_with` +// attribute, are not deserialized 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: Deserialize` bound where T is the type of the +// field. +fn needs_deserialize_bound(field: &attr::Field, variant: Option<&attr::Variant>) -> bool { + !field.skip_deserializing() + && field.deserialize_with().is_none() + && field.de_bound().is_none() + && variant.map_or(true, |variant| { + !variant.skip_deserializing() + && variant.deserialize_with().is_none() + && variant.de_bound().is_none() + }) +} + +// Fields with a `default` attribute (not `default=...`), and fields with a +// `skip_deserializing` attribute that do not also have `default=...`. +fn requires_default(field: &attr::Field, _variant: Option<&attr::Variant>) -> bool { + if let attr::Default::Default = *field.default() { + true + } else { + false + } +} + +enum BorrowedLifetimes { + Borrowed(BTreeSet), + Static, +} + +impl BorrowedLifetimes { + fn de_lifetime(&self) -> syn::Lifetime { + match *self { + BorrowedLifetimes::Borrowed(_) => syn::Lifetime::new("'de", Span::call_site()), + BorrowedLifetimes::Static => syn::Lifetime::new("'static", Span::call_site()), + } + } + + fn de_lifetime_param(&self) -> Option { + match self { + BorrowedLifetimes::Borrowed(bounds) => Some(syn::LifetimeParam { + attrs: Vec::new(), + lifetime: syn::Lifetime::new("'de", Span::call_site()), + colon_token: None, + bounds: bounds.iter().cloned().collect(), + }), + BorrowedLifetimes::Static => None, + } + } +} + +// The union of lifetimes borrowed by each field of the container. +// +// These turn into bounds on the `'de` lifetime of the Deserialize impl. If +// lifetimes `'a` and `'b` are borrowed but `'c` is not, the impl is: +// +// impl<'de: 'a + 'b, 'a, 'b, 'c> Deserialize<'de> for S<'a, 'b, 'c> +// +// If any borrowed lifetime is `'static`, then `'de: 'static` would be redundant +// and we use plain `'static` instead of `'de`. +fn borrowed_lifetimes(cont: &Container) -> BorrowedLifetimes { + let mut lifetimes = BTreeSet::new(); + for field in cont.data.all_fields() { + if !field.attrs.skip_deserializing() { + lifetimes.extend(field.attrs.borrowed_lifetimes().iter().cloned()); + } + } + if lifetimes.iter().any(|b| b.to_string() == "'static") { + BorrowedLifetimes::Static + } else { + BorrowedLifetimes::Borrowed(lifetimes) + } +} + +fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment { + if cont.attrs.transparent() { + deserialize_transparent(cont, params) + } else if let Some(type_from) = cont.attrs.type_from() { + deserialize_from(type_from) + } else if let Some(type_try_from) = cont.attrs.type_try_from() { + deserialize_try_from(type_try_from) + } else if let attr::Identifier::No = cont.attrs.identifier() { + match &cont.data { + Data::Enum(variants) => enum_::deserialize(params, variants, &cont.attrs), + Data::Struct(Style::Struct, fields) => { + struct_::deserialize(params, fields, &cont.attrs, StructForm::Struct) + } + Data::Struct(Style::Tuple, fields) | Data::Struct(Style::Newtype, fields) => { + tuple::deserialize(params, fields, &cont.attrs, TupleForm::Tuple) + } + Data::Struct(Style::Unit, _) => unit::deserialize(params, &cont.attrs), + } + } else { + match &cont.data { + Data::Enum(variants) => identifier::deserialize_custom(params, variants, &cont.attrs), + Data::Struct(_, _) => unreachable!("checked in serde_derive_internals"), + } + } +} + +#[cfg(feature = "deserialize_in_place")] +fn deserialize_in_place_body(cont: &Container, params: &Parameters) -> Option { + // Only remote derives have getters, and we do not generate + // deserialize_in_place for remote derives. + assert!(!params.has_getter); + + if cont.attrs.transparent() + || cont.attrs.type_from().is_some() + || cont.attrs.type_try_from().is_some() + || cont.attrs.identifier().is_some() + || cont + .data + .all_fields() + .all(|f| f.attrs.deserialize_with().is_some()) + { + return None; + } + + let code = match &cont.data { + Data::Struct(Style::Struct, fields) => { + struct_::deserialize_in_place(params, fields, &cont.attrs)? + } + Data::Struct(Style::Tuple, fields) | Data::Struct(Style::Newtype, fields) => { + tuple::deserialize_in_place(params, fields, &cont.attrs) + } + Data::Enum(_) | Data::Struct(Style::Unit, _) => { + return None; + } + }; + + let delife = params.borrowed.de_lifetime(); + let stmts = Stmts(code); + + let fn_deserialize_in_place = quote_block! { + fn deserialize_in_place<__D>(__deserializer: __D, __place: &mut Self) -> _serde::#private::Result<(), __D::Error> + where + __D: _serde::Deserializer<#delife>, + { + #stmts + } + }; + + Some(Stmts(fn_deserialize_in_place)) +} + +#[cfg(not(feature = "deserialize_in_place"))] +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_value = ¶ms.this_value; + let transparent_field = fields.iter().find(|f| f.attrs.transparent()).unwrap(); + + let path = match transparent_field.attrs.deserialize_with() { + Some(path) => quote!(#path), + None => { + let span = transparent_field.original.span(); + quote_spanned!(span=> _serde::Deserialize::deserialize) + } + }; + + let assign = fields.iter().map(|field| { + let member = &field.member; + if ptr::eq(field, transparent_field) { + quote!(#member: __transparent) + } else { + let value = match field.attrs.default() { + 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::#private::Result::map( + #path(__deserializer), + |__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::#private::Result::map( + <#type_from as _serde::Deserialize>::deserialize(__deserializer), + _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::#private::Result::and_then( + <#type_try_from as _serde::Deserialize>::deserialize(__deserializer), + |v| _serde::#private::TryFrom::try_from(v).map_err(_serde::de::Error::custom)) + } +} + +enum TupleForm<'a> { + Tuple, + /// Contains a variant name + ExternallyTagged(&'a syn::Ident), + /// Contains a variant name + Untagged(&'a syn::Ident), +} + +fn deserialize_seq( + type_path: &TokenStream, + params: &Parameters, + fields: &[Field], + is_struct: bool, + cattrs: &attr::Container, + expecting: &str, +) -> Fragment { + let vars = (0..fields.len()).map(field_i as fn(_) -> _); + + let deserialized_count = fields + .iter() + .filter(|field| !field.attrs.skip_deserializing()) + .count(); + let expecting = if deserialized_count == 1 { + format!("{} with 1 element", expecting) + } 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)| { + if field.attrs.skip_deserializing() { + let default = Expr(expr_is_missing(field, cattrs)); + quote! { + let #var = #default; + } + } else { + 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::SeqAccess::next_element::<#field_ty>); + quote!(#func(&mut __seq)?) + } + Some(path) => { + let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); + quote!({ + #wrapper + _serde::#private::Option::map( + _serde::de::SeqAccess::next_element::<#wrapper_ty>(&mut __seq)?, + |__wrap| __wrap.value) + }) + } + }; + let value_if_none = expr_is_missing_seq(None, index_in_seq, field, cattrs, expecting); + let assign = quote! { + let #var = match #visit { + _serde::#private::Some(__value) => __value, + _serde::#private::None => #value_if_none, + }; + }; + index_in_seq += 1; + assign + } + }); + + let mut result = if is_struct { + let names = fields.iter().map(|f| &f.member); + quote! { + #type_path { #( #names: #vars ),* } + } + } else { + quote! { + #type_path ( #(#vars),* ) + } + }; + + 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) + }; + } + + 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 + } + }; + + quote_block! { + #let_default + #(#let_values)* + _serde::#private::Ok(#result) + } +} + +#[cfg(feature = "deserialize_in_place")] +fn deserialize_seq_in_place( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, + expecting: &str, +) -> Fragment { + let deserialized_count = fields + .iter() + .filter(|field| !field.attrs.skip_deserializing()) + .count(); + let expecting = if deserialized_count == 1 { + format!("{} with 1 element", expecting) + } 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| { + let member = &field.member; + + if field.attrs.skip_deserializing() { + let default = Expr(expr_is_missing(field, cattrs)); + quote! { + self.place.#member = #default; + } + } else { + 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::#private::None = _serde::de::SeqAccess::next_element_seed(&mut __seq, + _serde::#private::de::InPlaceSeed(&mut self.place.#member))? + { + #value_if_none; + } + } + } + Some(path) => { + let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); + quote!({ + #wrapper + match _serde::de::SeqAccess::next_element::<#wrapper_ty>(&mut __seq) { + _serde::#private::Ok(_serde::#private::Some(__wrap)) => { + self.place.#member = __wrap.value; + } + _serde::#private::Ok(_serde::#private::None) => { + #value_if_none; + } + _serde::#private::Err(__err) => { + return _serde::#private::Err(__err); + } + } + }) + } + }; + index_in_seq += 1; + write + } + }); + + 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_default + #(#write_values)* + _serde::#private::Ok(()) + } +} + +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), +} + +struct FieldWithAliases<'a> { + ident: Ident, + aliases: &'a BTreeSet, +} + +pub(crate) 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_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 deserializer_var = quote!(__deserializer); + + // 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)? + }; + 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 ()>, + } + + #[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 + __D: _serde::Deserializer<#delife>, + { + _serde::#private::Ok(__DeserializeWith { + value: #value, + phantom: _serde::#private::PhantomData, + lifetime: _serde::#private::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) +} + +// 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 (arg, wrapper) = if with_wrapper { + (quote! { __wrap }, quote! { __wrap.value }) + } else { + let field_tys = variant.fields.iter().map(|field| field.ty); + (quote! { __wrap: (#(#field_tys),*) }, quote! { __wrap }) + }; + + let field_access = (0..variant.fields.len()).map(|n| { + Member::Unnamed(Index { + index: n as u32, + span: Span::call_site(), + }) + }); + + match variant.style { + Style::Struct if variant.fields.len() == 1 => { + let member = &variant.fields[0].member; + quote! { + |#arg| #this_value::#variant_ident { #member: #wrapper } + } + } + Style::Struct => { + let members = variant.fields.iter().map(|field| &field.member); + quote! { + |#arg| #this_value::#variant_ident { #(#members: #wrapper.#field_access),* } + } + } + Style::Tuple => quote! { + |#arg| #this_value::#variant_ident(#(#wrapper.#field_access),*) + }, + Style::Newtype => quote! { + |#arg| #this_value::#variant_ident(#wrapper) + }, + Style::Unit => quote! { + |#arg| #this_value::#variant_ident + }, + } +} + +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::#private::Default::default); + return quote_expr!(#func()); + } + 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 Fragment::Expr(quote_spanned!(path.span()=> #path())); + } + attr::Default::None => { /* below */ } + } + + match *cattrs.default() { + attr::Default::Default | attr::Default::Path(_) => { + let member = &field.member; + return quote_expr!(__default.#member); + } + attr::Default::None => { /* below */ } + } + + let name = field.attrs.name().deserialize_name(); + match field.attrs.deserialize_with() { + None => { + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::#private::de::missing_field); + quote_expr! { + #func(#name)? + } + } + Some(_) => { + quote_expr! { + 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, + other => other, + } +} + +/// 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); + +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_param() { + generics.params = Some(syn::GenericParam::Lifetime(de_lifetime)) + .into_iter() + .chain(generics.params) + .collect(); + } + let (impl_generics, _, _) = generics.split_for_impl(); + impl_generics.to_tokens(tokens); + } +} + +#[cfg(feature = "deserialize_in_place")] +impl<'a> ToTokens for InPlaceImplGenerics<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let place_lifetime = place_lifetime(); + let mut generics = self.0.generics.clone(); + + // Add lifetime for `&'place mut Self, and `'a: 'place` + for param in &mut generics.params { + match param { + syn::GenericParam::Lifetime(param) => { + param.bounds.push(place_lifetime.lifetime.clone()); + } + syn::GenericParam::Type(param) => { + param.bounds.push(syn::TypeParamBound::Lifetime( + place_lifetime.lifetime.clone(), + )); + } + syn::GenericParam::Const(_) => {} + } + } + generics.params = Some(syn::GenericParam::Lifetime(place_lifetime)) + .into_iter() + .chain(generics.params) + .collect(); + if let Some(de_lifetime) = self.0.borrowed.de_lifetime_param() { + generics.params = Some(syn::GenericParam::Lifetime(de_lifetime)) + .into_iter() + .chain(generics.params) + .collect(); + } + let (impl_generics, _, _) = generics.split_for_impl(); + impl_generics.to_tokens(tokens); + } +} + +#[cfg(feature = "deserialize_in_place")] +impl<'a> DeImplGenerics<'a> { + fn in_place(self) -> InPlaceImplGenerics<'a> { + InPlaceImplGenerics(self.0) + } +} + +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) { + de_type_generics_to_tokens(self.0.generics.clone(), &self.0.borrowed, tokens); + } +} + +#[cfg(feature = "deserialize_in_place")] +impl<'a> ToTokens for InPlaceTypeGenerics<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let mut generics = self.0.generics.clone(); + generics.params = Some(syn::GenericParam::Lifetime(place_lifetime())) + .into_iter() + .chain(generics.params) + .collect(); + + de_type_generics_to_tokens(generics, &self.0.borrowed, tokens); + } +} + +#[cfg(feature = "deserialize_in_place")] +impl<'a> DeTypeGenerics<'a> { + fn in_place(self) -> InPlaceTypeGenerics<'a> { + InPlaceTypeGenerics(self.0) + } +} + +#[cfg(feature = "deserialize_in_place")] +fn place_lifetime() -> syn::LifetimeParam { + syn::LifetimeParam { + attrs: Vec::new(), + lifetime: syn::Lifetime::new("'place", Span::call_site()), + colon_token: None, + bounds: Punctuated::new(), + } +} diff --git a/third_party/crates/serde_derive-1.0.229/src/de/enum_.rs b/third_party/crates/serde_derive-1.0.229/src/de/enum_.rs new file mode 100644 index 0000000..6f5094f --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/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/third_party/crates/serde_derive-1.0.229/src/de/enum_adjacently.rs b/third_party/crates/serde_derive-1.0.229/src/de/enum_adjacently.rs new file mode 100644 index 0000000..ead66ac --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/src/de/enum_adjacently.rs @@ -0,0 +1,324 @@ +//! 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 mut variant_arms = Vec::new(); + for (i, variant) in variants.iter().enumerate() { + if variant.attrs.skip_deserializing() { + continue; + } + let variant_index = field_i(i); + + let block = Match(enum_untagged::deserialize_variant(params, variant, cattrs)); + + variant_arms.push(quote! { + __Field::#variant_index => #block + }); + } + + 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 mut missing_content_arms = Vec::new(); + for (i, variant) in variants.iter().enumerate() { + if variant.attrs.skip_deserializing() { + continue; + } + 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); + continue; + } + }; + missing_content_arms.push(quote! { + __Field::#variant_index => #arm, + }); + } + + 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/third_party/crates/serde_derive-1.0.229/src/de/enum_externally.rs b/third_party/crates/serde_derive-1.0.229/src/de/enum_externally.rs new file mode 100644 index 0000000..1a4c36b --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/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/third_party/crates/serde_derive-1.0.229/src/de/enum_internally.rs b/third_party/crates/serde_derive-1.0.229/src/de/enum_internally.rs new file mode 100644 index 0000000..b669eef --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/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/third_party/crates/serde_derive-1.0.229/src/de/enum_untagged.rs b/third_party/crates/serde_derive-1.0.229/src/de/enum_untagged.rs new file mode 100644 index 0000000..f66d98d --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/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/third_party/crates/serde_derive-1.0.229/src/de/identifier.rs b/third_party/crates/serde_derive-1.0.229/src/de/identifier.rs new file mode 100644 index 0000000..8e67b96 --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/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/third_party/crates/serde_derive-1.0.229/src/de/struct_.rs b/third_party/crates/serde_derive-1.0.229/src/de/struct_.rs new file mode 100644 index 0000000..6a5da23 --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/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/third_party/crates/serde_derive-1.0.229/src/de/tuple.rs b/third_party/crates/serde_derive-1.0.229/src/de/tuple.rs new file mode 100644 index 0000000..a76089f --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/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/third_party/crates/serde_derive-1.0.229/src/de/unit.rs b/third_party/crates/serde_derive-1.0.229/src/de/unit.rs new file mode 100644 index 0000000..0d15ef4 --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/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/third_party/crates/serde_derive-1.0.229/src/deprecated.rs b/third_party/crates/serde_derive-1.0.229/src/deprecated.rs new file mode 100644 index 0000000..3abdc1b --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/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/third_party/crates/serde_derive-1.0.229/src/dummy.rs b/third_party/crates/serde_derive-1.0.229/src/dummy.rs new file mode 100644 index 0000000..e0bca64 --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/src/dummy.rs @@ -0,0 +1,31 @@ +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(unused_extern_crates, clippy::useless_attribute)] + extern crate serde as _serde; + }, + }; + + quote! { + #[doc(hidden)] + #[allow( + non_upper_case_globals, + unused_attributes, + unused_qualifications, + clippy::absolute_paths, + )] + const _: () = { + #use_serde + + _serde::__require_serde_not_serde_core!(); + + #code + }; + } +} diff --git a/third_party/crates/serde_derive-1.0.229/src/fragment.rs b/third_party/crates/serde_derive-1.0.229/src/fragment.rs new file mode 100644 index 0000000..6627c26 --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/src/fragment.rs @@ -0,0 +1,74 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::{token, Token}; + +pub enum Fragment { + /// Tokens that can be used as an expression. + Expr(TokenStream), + /// Tokens that can be used inside a block. The surrounding curly braces are + /// not part of these tokens. + Block(TokenStream), +} + +macro_rules! quote_expr { + ($($tt:tt)*) => { + $crate::fragment::Fragment::Expr(quote!($($tt)*)) + } +} + +macro_rules! quote_block { + ($($tt:tt)*) => { + $crate::fragment::Fragment::Block(quote!($($tt)*)) + } +} + +/// Interpolate a fragment in place of an expression. This involves surrounding +/// Block fragments in curly braces. +pub struct Expr(pub Fragment); +impl ToTokens for Expr { + fn to_tokens(&self, out: &mut TokenStream) { + match &self.0 { + Fragment::Expr(expr) => expr.to_tokens(out), + Fragment::Block(block) => { + token::Brace::default().surround(out, |out| block.to_tokens(out)); + } + } + } +} + +/// Interpolate a fragment as the statements of a block. +pub struct Stmts(pub Fragment); +impl ToTokens for Stmts { + fn to_tokens(&self, out: &mut TokenStream) { + match &self.0 { + Fragment::Expr(expr) => expr.to_tokens(out), + Fragment::Block(block) => block.to_tokens(out), + } + } +} + +/// Interpolate a fragment as the value part of a `match` expression. This +/// involves putting a comma after expressions and curly braces around blocks. +pub struct Match(pub Fragment); +impl ToTokens for Match { + fn to_tokens(&self, out: &mut TokenStream) { + match &self.0 { + Fragment::Expr(expr) => { + expr.to_tokens(out); + ::default().to_tokens(out); + } + Fragment::Block(block) => { + token::Brace::default().surround(out, |out| block.to_tokens(out)); + } + } + } +} + +impl AsRef for Fragment { + fn as_ref(&self) -> &TokenStream { + match self { + Fragment::Expr(expr) => expr, + Fragment::Block(block) => block, + } + } +} diff --git a/third_party/crates/serde_derive-1.0.229/src/internals/ast.rs b/third_party/crates/serde_derive-1.0.229/src/internals/ast.rs new file mode 100644 index 0000000..1b89c6a --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/src/internals/ast.rs @@ -0,0 +1,225 @@ +//! A Serde ast, parsed from the Syn ast and ready to generate Rust code. + +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. +pub struct Container<'a> { + /// The struct or enum name (without generics). + pub ident: syn::Ident, + /// Attributes on the structure, parsed for Serde. + pub attrs: attr::Container, + /// The contents of the struct or enum. + pub data: Data<'a>, + /// Any generics on the struct or enum. + pub generics: &'a syn::Generics, + /// Original input. + pub original: &'a syn::DeriveInput, +} + +/// The fields of a struct or enum. +/// +/// Analogous to `syn::Data`. +pub enum Data<'a> { + Enum(Vec>), + Struct(Style, Vec>), +} + +/// A variant of an enum. +pub struct Variant<'a> { + pub ident: syn::Ident, + pub attrs: attr::Variant, + pub style: Style, + pub fields: Vec>, + pub original: &'a syn::Variant, +} + +/// A field of a struct. +pub struct Field<'a> { + pub member: syn::Member, + pub attrs: attr::Field, + pub ty: &'a syn::Type, + pub original: &'a syn::Field, +} + +#[derive(Copy, Clone)] +pub enum Style { + /// Named fields. + Struct, + /// Many unnamed fields. + Tuple, + /// One unnamed field. + Newtype, + /// No fields. + Unit, +} + +impl<'a> Container<'a> { + /// Convert the raw Syn ast into a parsed container object, collecting errors in `cx`. + pub fn from_ast( + cx: &Ctxt, + item: &'a syn::DeriveInput, + derive: Derive, + private: &Ident, + ) -> Option> { + 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(), private)) + } + syn::Data::Struct(data) => { + let (style, fields) = + struct_from_ast(cx, &data.fields, None, attrs.default(), private); + Data::Struct(style, fields) + } + syn::Data::Union(_) => { + cx.error_spanned_by(item, "Serde does not support derive for unions"); + return None; + } + }; + + 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 { + field.attrs.rename_by_rules( + variant + .attrs + .rename_all_rules() + .or(attrs.rename_all_fields_rules()), + ); + } + } + } + Data::Struct(_, fields) => { + for field in fields { + field.attrs.rename_by_rules(attrs.rename_all_rules()); + } + } + } + + let mut item = Container { + ident: item.ident.clone(), + attrs, + data, + generics: &item.generics, + original: item, + }; + check::check(cx, &mut item, derive); + Some(item) + } +} + +impl<'a> Data<'a> { + pub fn all_fields(&'a self) -> Box> + 'a> { + match self { + Data::Enum(variants) => { + Box::new(variants.iter().flat_map(|variant| variant.fields.iter())) + } + Data::Struct(_, fields) => Box::new(fields.iter()), + } + } + + pub fn has_getter(&self) -> bool { + self.all_fields().any(|f| f.attrs.getter().is_some()) + } +} + +fn enum_from_ast<'a>( + cx: &Ctxt, + variants: &'a Punctuated, + container_default: &attr::Default, + private: &Ident, +) -> Vec> { + 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, + private, + ); + Variant { + ident: variant.ident.clone(), + attrs, + style, + fields, + original: variant, + } + }) + .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>( + cx: &Ctxt, + 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, private), + ), + syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => ( + Style::Newtype, + 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, private), + ), + syn::Fields::Unit => (Style::Unit, Vec::new()), + } +} + +fn fields_from_ast<'a>( + cx: &Ctxt, + fields: &'a Punctuated, + attrs: Option<&attr::Variant>, + container_default: &attr::Default, + private: &Ident, +) -> Vec> { + let mut dst_fields = Vec::with_capacity(fields.len()); + for field in fields { + dst_fields.push(Field { + member: match &field.ident { + Some(ident) => syn::Member::Named(ident.clone()), + None => syn::Member::Unnamed(dst_fields.len().into()), + }, + attrs: attr::Field::from_ast( + cx, + dst_fields.len(), + field, + attrs, + container_default, + private, + ), + ty: &field.ty, + original: field, + }); + } + dst_fields +} diff --git a/third_party/crates/serde_derive-1.0.229/src/internals/attr.rs b/third_party/crates/serde_derive-1.0.229/src/internals/attr.rs new file mode 100644 index 0000000..c0f08f4 --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/src/internals/attr.rs @@ -0,0 +1,1818 @@ +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::collections::BTreeSet; +use std::iter::FromIterator; +use syn::meta::ParseNestedMeta; +use syn::parse::ParseStream; +use syn::punctuated::Punctuated; +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 +// `attr::Field::from_ast`. Each returns an instance of the corresponding +// struct. Note that none of them return a Result. Unrecognized, malformed, or +// duplicated attributes result in a span_err but otherwise are ignored. The +// user will see errors simultaneously for all bad attributes in the crate +// rather than just the first. + +pub use crate::internals::case::RenameRule; + +pub(crate) struct Attr<'c, T> { + cx: &'c Ctxt, + name: Symbol, + tokens: TokenStream, + value: Option, +} + +impl<'c, T> Attr<'c, T> { + fn none(cx: &'c Ctxt, name: Symbol) -> Self { + Attr { + cx, + name, + tokens: TokenStream::new(), + value: None, + } + } + + fn set(&mut self, obj: A, value: T) { + let tokens = obj.into_token_stream(); + + if self.value.is_some() { + let msg = format!("duplicate serde attribute `{}`", self.name); + self.cx.error_spanned_by(tokens, msg); + } else { + self.tokens = tokens; + self.value = Some(value); + } + } + + fn set_opt(&mut self, obj: A, value: Option) { + if let Some(value) = value { + self.set(obj, value); + } + } + + fn set_if_none(&mut self, value: T) { + if self.value.is_none() { + self.value = Some(value); + } + } + + pub(crate) fn get(self) -> Option { + self.value + } + + fn get_with_tokens(self) -> Option<(TokenStream, T)> { + match self.value { + Some(v) => Some((self.tokens, v)), + None => None, + } + } +} + +struct BoolAttr<'c>(Attr<'c, ()>); + +impl<'c> BoolAttr<'c> { + fn none(cx: &'c Ctxt, name: Symbol) -> Self { + BoolAttr(Attr::none(cx, name)) + } + + fn set_true(&mut self, obj: A) { + self.0.set(obj, ()); + } + + fn get(&self) -> bool { + self.0.value.is_some() + } +} + +pub(crate) struct VecAttr<'c, T> { + cx: &'c Ctxt, + name: Symbol, + first_dup_tokens: TokenStream, + values: Vec, +} + +impl<'c, T> VecAttr<'c, T> { + fn none(cx: &'c Ctxt, name: Symbol) -> Self { + VecAttr { + cx, + name, + first_dup_tokens: TokenStream::new(), + values: Vec::new(), + } + } + + fn insert(&mut self, obj: A, value: T) { + if self.values.len() == 1 { + self.first_dup_tokens = obj.into_token_stream(); + } + self.values.push(value); + } + + fn at_most_one(mut self) -> Option { + if self.values.len() > 1 { + let dup_token = self.first_dup_tokens; + let msg = format!("duplicate serde attribute `{}`", self.name); + self.cx.error_spanned_by(dup_token, msg); + None + } else { + self.values.pop() + } + } + + pub(crate) fn get(self) -> Vec { + self.values + } +} + +fn unraw(ident: &Ident) -> Ident { + Ident::new(ident.to_string().trim_start_matches("r#"), ident.span()) +} + +#[derive(Copy, Clone)] +pub struct RenameAllRules { + pub serialize: RenameRule, + pub deserialize: RenameRule, +} + +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), + } + } +} + +/// Represents struct or enum attribute information. +pub struct Container { + 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, + type_from: Option, + type_try_from: Option, + type_into: Option, + remote: Option, + identifier: Identifier, + 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. +pub enum TagType { + /// The default. + /// + /// ```json + /// {"variant1": {"key1": "value1", "key2": "value2"}} + /// ``` + External, + + /// `#[serde(tag = "type")]` + /// + /// ```json + /// {"type": "variant1", "key1": "value1", "key2": "value2"} + /// ``` + Internal { tag: String }, + + /// `#[serde(tag = "t", content = "c")]` + /// + /// ```json + /// {"t": "variant1", "c": {"key1": "value1", "key2": "value2"}} + /// ``` + Adjacent { tag: String, content: String }, + + /// `#[serde(untagged)]` + /// + /// ```json + /// {"key1": "value1", "key2": "value2"} + /// ``` + None, +} + +/// Whether this enum represents the fields of a struct or the variants of an +/// enum. +#[derive(Copy, Clone)] +pub enum Identifier { + /// It does not. + No, + + /// This enum represents the fields of a struct. All of the variants must be + /// unit variants, except possibly one which is annotated with + /// `#[serde(other)]` and is a newtype variant. + Field, + + /// This enum represents the variants of an enum. All of the variants must + /// be unit variants. + Variant, +} + +impl Identifier { + #[cfg(feature = "deserialize_in_place")] + pub fn is_some(self) -> bool { + match self { + Identifier::No => false, + Identifier::Field | Identifier::Variant => true, + } + } +} + +impl Container { + /// Extract out the `#[serde(...)]` attributes from an item. + pub fn from_ast(cx: &Ctxt, item: &syn::DeriveInput) -> Self { + let mut ser_name = Attr::none(cx, RENAME); + let mut de_name = Attr::none(cx, RENAME); + let mut transparent = BoolAttr::none(cx, TRANSPARENT); + let mut deny_unknown_fields = BoolAttr::none(cx, DENY_UNKNOWN_FIELDS); + 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); + let mut internal_tag = Attr::none(cx, TAG); + let mut content = Attr::none(cx, CONTENT); + let mut type_from = Attr::none(cx, FROM); + let mut type_try_from = Attr::none(cx, TRY_FROM); + let mut type_into = Attr::none(cx, INTO); + let mut remote = Attr::none(cx, REMOTE); + 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 attr in &item.attrs { + if attr.path() != SERDE { + non_exhaustive |= + matches!(&attr.meta, syn::Meta::Path(path) if path == NON_EXHAUSTIVE); + continue; + } + + if let syn::Meta::List(meta) = &attr.meta { + if meta.tokens.is_empty() { + continue; + } + } + + 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), + } + } + 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); + } + } + } + } + } 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)); + } + } + } 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)); + } + } + } + } else { + // #[serde(default)] + match &item.data { + 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)); + } + } + } + } 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)); + } + } + } 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(&meta.path, s.value()); + } + syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields { + syn::Fields::Named(_) => { + internal_tag.set(&meta.path, s.value()); + } + syn::Fields::Unnamed(_) | syn::Fields::Unit => { + let msg = "#[serde(tag = \"...\")] can only be used on enums and structs with named fields"; + cx.syn_error(meta.error(msg)); + } + }, + syn::Data::Union(_) => { + let msg = "#[serde(tag = \"...\")] can only be used on enums and structs with named fields"; + cx.syn_error(meta.error(msg)); + } + } + } + } 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(&meta.path, s.value()); + } + syn::Data::Struct(_) => { + let msg = "#[serde(content = \"...\")] can only be used on enums"; + cx.syn_error(meta.error(msg)); + } + syn::Data::Union(_) => { + let msg = "#[serde(content = \"...\")] can only be used on enums"; + cx.syn_error(meta.error(msg)); + } + } + } + } 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)); + } + } 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)); + } + } 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)); + } + } 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(&meta.path, item.ident.clone().into()); + } else { + remote.set(&meta.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); + } + } 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)) + ); + } + Ok(()) + }) { + cx.syn_error(err); + } + } + + let mut is_packed = false; + for attr in &item.attrs { + if attr.path() == REPR { + let _ = attr.parse_args_with(|input: ParseStream| { + while let Some(token) = input.parse()? { + if let TokenTree::Ident(ident) = token { + is_packed |= ident == "packed"; + } + } + Ok(()) + }); + } + } + + Container { + 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), + rename_all_rules: RenameAllRules { + 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), + type_from: type_from.get(), + type_try_from: type_try_from.get(), + type_into: type_into.get(), + remote: remote.get(), + identifier: decide_identifier(cx, item, field_identifier, variant_identifier), + serde_path: serde_path.get(), + is_packed, + expecting: expecting.get(), + non_exhaustive, + } + } + + pub fn name(&self) -> &MultiName { + &self.name + } + + 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 { + self.transparent + } + + pub fn deny_unknown_fields(&self) -> bool { + self.deny_unknown_fields + } + + pub fn default(&self) -> &Default { + &self.default + } + + pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> { + self.ser_bound.as_ref().map(|vec| &vec[..]) + } + + pub fn de_bound(&self) -> Option<&[syn::WherePredicate]> { + self.de_bound.as_ref().map(|vec| &vec[..]) + } + + pub fn tag(&self) -> &TagType { + &self.tag + } + + pub fn type_from(&self) -> Option<&syn::Type> { + self.type_from.as_ref() + } + + pub fn type_try_from(&self) -> Option<&syn::Type> { + self.type_try_from.as_ref() + } + + pub fn type_into(&self) -> Option<&syn::Type> { + self.type_into.as_ref() + } + + pub fn remote(&self) -> Option<&syn::Path> { + self.remote.as_ref() + } + + pub fn is_packed(&self) -> bool { + self.is_packed + } + + pub fn identifier(&self) -> Identifier { + self.identifier + } + + pub fn custom_serde_path(&self) -> Option<&syn::Path> { + self.serde_path.as_ref() + } + + /// 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 + } +} + +fn decide_tag( + cx: &Ctxt, + item: &syn::DeriveInput, + untagged: BoolAttr, + internal_tag: Attr, + content: Attr, +) -> TagType { + match ( + untagged.0.get_with_tokens(), + internal_tag.get_with_tokens(), + content.get_with_tokens(), + ) { + (None, None, None) => TagType::External, + (Some(_), None, None) => TagType::None, + (None, Some((_, tag)), None) => { + // Check that there are no tuple variants. + if let syn::Data::Enum(data) = &item.data { + for variant in &data.variants { + match &variant.fields { + syn::Fields::Named(_) | syn::Fields::Unit => {} + syn::Fields::Unnamed(fields) => { + if fields.unnamed.len() != 1 { + let msg = + "#[serde(tag = \"...\")] cannot be used with tuple variants"; + cx.error_spanned_by(variant, msg); + break; + } + } + } + } + } + TagType::Internal { tag } + } + (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, _))) => { + 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, _))) => { + 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, _))) => { + 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 + } + } +} + +fn decide_identifier( + cx: &Ctxt, + item: &syn::DeriveInput, + field_identifier: BoolAttr, + variant_identifier: BoolAttr, +) -> Identifier { + match ( + &item.data, + field_identifier.0.get_with_tokens(), + variant_identifier.0.get_with_tokens(), + ) { + (_, None, None) => Identifier::No, + (_, 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) => { + 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) => { + 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(_)) => { + 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(_)) => { + let msg = "#[serde(variant_identifier)] can only be used on an enum"; + cx.error_spanned_by(union_token, msg); + Identifier::No + } + } +} + +/// Represents variant attribute information +pub struct Variant { + name: MultiName, + rename_all_rules: RenameAllRules, + ser_bound: Option>, + de_bound: Option>, + skip_deserializing: bool, + skip_serializing: bool, + other: bool, + serialize_with: Option, + deserialize_with: Option, + borrow: Option, + untagged: bool, +} + +struct BorrowAttribute { + path: syn::Path, + lifetimes: Option>, +} + +impl Variant { + pub fn from_ast(cx: &Ctxt, variant: &syn::Variant) -> Self { + let mut ser_name = Attr::none(cx, RENAME); + let mut de_name = Attr::none(cx, RENAME); + let mut de_aliases = VecAttr::none(cx, RENAME); + let mut skip_deserializing = BoolAttr::none(cx, SKIP_DESERIALIZING); + let mut skip_serializing = BoolAttr::none(cx, SKIP_SERIALIZING); + let mut rename_all_ser_rule = Attr::none(cx, RENAME_ALL); + let mut rename_all_de_rule = Attr::none(cx, RENAME_ALL); + let mut ser_bound = Attr::none(cx, BOUND); + let mut de_bound = Attr::none(cx, BOUND); + let mut other = BoolAttr::none(cx, OTHER); + 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 attr in &variant.attrs { + if attr.path() != SERDE { + continue; + } + + if let syn::Meta::List(meta) = &attr.meta { + if meta.tokens.is_empty() { + continue; + } + } + + 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)); + } + } 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)); + } + } 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(&meta.path, rename_rule), + Err(err) => { + if !one_name { + cx.error_spanned_by(de, err); + } + } + } + } + } 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", ser_path.span()).into()); + serialize_with.set(&meta.path, ser_path); + let mut de_path = path; + de_path + .path + .segments + .push(Ident::new("deserialize", de_path.span()).into()); + deserialize_with.set(&meta.path, de_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); + } + } 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 == 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); + } + } + } 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)) + ); + } + Ok(()) + }) { + cx.syn_error(err); + } + } + + Variant { + 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), + }, + ser_bound: ser_bound.get(), + de_bound: de_bound.get(), + skip_deserializing: skip_deserializing.get(), + skip_serializing: skip_serializing.get(), + other: other.get(), + serialize_with: serialize_with.get(), + deserialize_with: deserialize_with.get(), + borrow: borrow.get(), + untagged: untagged.get(), + } + } + + pub fn name(&self) -> &MultiName { + &self.name + } + + pub fn aliases(&self) -> &BTreeSet { + self.name.deserialize_aliases() + } + + pub fn rename_by_rules(&mut self, rules: RenameAllRules) { + if !self.name.serialize_renamed { + self.name.serialize.value = + rules.serialize.apply_to_variant(&self.name.serialize.value); + } + if !self.name.deserialize_renamed { + 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 ser_bound(&self) -> Option<&[syn::WherePredicate]> { + self.ser_bound.as_ref().map(|vec| &vec[..]) + } + + pub fn de_bound(&self) -> Option<&[syn::WherePredicate]> { + self.de_bound.as_ref().map(|vec| &vec[..]) + } + + pub fn skip_deserializing(&self) -> bool { + self.skip_deserializing + } + + pub fn skip_serializing(&self) -> bool { + self.skip_serializing + } + + pub fn other(&self) -> bool { + self.other + } + + pub fn serialize_with(&self) -> Option<&syn::ExprPath> { + self.serialize_with.as_ref() + } + + 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: MultiName, + skip_serializing: bool, + skip_deserializing: bool, + skip_serializing_if: Option, + default: Default, + serialize_with: Option, + deserialize_with: Option, + ser_bound: Option>, + de_bound: Option>, + borrowed_lifetimes: BTreeSet, + getter: Option, + flatten: bool, + transparent: bool, +} + +/// Represents the default to use for a field when deserializing. +pub enum Default { + /// Field must always be specified because it does not have a default. + None, + /// The default is given by `std::default::Default::default()`. + Default, + /// The default is given by this function. + Path(syn::ExprPath), +} + +impl Default { + pub fn is_none(&self) -> bool { + match self { + Default::None => true, + Default::Default | Default::Path(_) => false, + } + } +} + +impl Field { + /// Extract out the `#[serde(...)]` attributes from a struct field. + pub fn from_ast( + cx: &Ctxt, + index: usize, + 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); + let mut de_aliases = VecAttr::none(cx, RENAME); + let mut skip_serializing = BoolAttr::none(cx, SKIP_SERIALIZING); + let mut skip_deserializing = BoolAttr::none(cx, SKIP_DESERIALIZING); + let mut skip_serializing_if = Attr::none(cx, SKIP_SERIALIZING_IF); + let mut default = Attr::none(cx, DEFAULT); + let mut serialize_with = Attr::none(cx, SERIALIZE_WITH); + let mut deserialize_with = Attr::none(cx, DESERIALIZE_WITH); + let mut ser_bound = Attr::none(cx, BOUND); + let mut de_bound = Attr::none(cx, BOUND); + let mut borrowed_lifetimes = Attr::none(cx, BORROW); + let mut getter = Attr::none(cx, GETTER); + let mut flatten = BoolAttr::none(cx, FLATTEN); + + let ident = match &field.ident { + Some(ident) => Name::from(&unraw(ident)), + None => Name { + value: index.to_string(), + span: Span::call_site(), + }, + }; + + 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); + } + } + } + + for attr in &field.attrs { + if attr.path() != SERDE { + continue; + } + + if let syn::Meta::List(meta) = &attr.meta { + if meta.tokens.is_empty() { + continue; + } + } + + 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)); + } + } 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)); + } + } 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); + } + } 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); + } + } 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", ser_path.span()).into()); + serialize_with.set(&meta.path, ser_path); + let mut de_path = path; + de_path + .path + .segments + .push(Ident::new("deserialize", de_path.span()).into()); + deserialize_with.set(&meta.path, de_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 == 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) { + let msg = format!( + "field `{}` does not have lifetime {}", + ident, lifetime, + ); + cx.error_spanned_by(field, msg); + } + } + borrowed_lifetimes.set(&meta.path, lifetimes); + } + } else { + // #[serde(borrow)] + if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) { + borrowed_lifetimes.set(&meta.path, borrowable); + } + } + } else if meta.path == GETTER { + // #[serde(getter = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, GETTER, &meta)? { + getter.set(&meta.path, 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)) + ); + } + Ok(()) + }) { + cx.syn_error(err); + } + } + + // 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 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(); + if !borrowed_lifetimes.is_empty() { + // Cow and Cow<[u8]> never borrow by default: + // + // impl<'de, 'a, T: ?Sized> Deserialize<'de> for Cow<'a, T> + // + // A #[serde(borrow)] attribute enables borrowing that corresponds + // roughly to these impls: + // + // impl<'de: 'a, 'a> Deserialize<'de> for Cow<'a, str> + // impl<'de: 'a, 'a> Deserialize<'de> for Cow<'a, [u8]> + if is_cow(&field.ty, is_str) { + let mut path = syn::Path { + leading_colon: None, + segments: Punctuated::new(), + }; + let span = Span::call_site(); + path.segments.push(Ident::new("_serde", 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()); + let expr = syn::ExprPath { + attrs: Vec::new(), + qself: None, + path, + }; + deserialize_with.set_if_none(expr); + } else if is_cow(&field.ty, is_slice_u8) { + let mut path = syn::Path { + leading_colon: None, + segments: Punctuated::new(), + }; + let span = Span::call_site(); + path.segments.push(Ident::new("_serde", 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()); + let expr = syn::ExprPath { + attrs: Vec::new(), + qself: None, + path, + }; + deserialize_with.set_if_none(expr); + } + } else if is_implicitly_borrowed(&field.ty) { + // Types &str and &[u8] are always implicitly borrowed. No need for + // a #[serde(borrow)]. + collect_lifetimes(&field.ty, &mut borrowed_lifetimes); + } + + Field { + 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(), + default: default.get().unwrap_or(Default::None), + serialize_with: serialize_with.get(), + deserialize_with: deserialize_with.get(), + ser_bound: ser_bound.get(), + de_bound: de_bound.get(), + borrowed_lifetimes, + getter: getter.get(), + flatten: flatten.get(), + transparent: false, + } + } + + pub fn name(&self) -> &MultiName { + &self.name + } + + pub fn aliases(&self) -> &BTreeSet { + self.name.deserialize_aliases() + } + + pub fn rename_by_rules(&mut self, rules: RenameAllRules) { + if !self.name.serialize_renamed { + self.name.serialize.value = rules.serialize.apply_to_field(&self.name.serialize.value); + } + if !self.name.deserialize_renamed { + 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 { + self.skip_serializing + } + + pub fn skip_deserializing(&self) -> bool { + self.skip_deserializing + } + + pub fn skip_serializing_if(&self) -> Option<&syn::ExprPath> { + self.skip_serializing_if.as_ref() + } + + pub fn default(&self) -> &Default { + &self.default + } + + pub fn serialize_with(&self) -> Option<&syn::ExprPath> { + self.serialize_with.as_ref() + } + + pub fn deserialize_with(&self) -> Option<&syn::ExprPath> { + self.deserialize_with.as_ref() + } + + pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> { + self.ser_bound.as_ref().map(|vec| &vec[..]) + } + + pub fn de_bound(&self) -> Option<&[syn::WherePredicate]> { + self.de_bound.as_ref().map(|vec| &vec[..]) + } + + pub fn borrowed_lifetimes(&self) -> &BTreeSet { + &self.borrowed_lifetimes + } + + pub fn getter(&self) -> Option<&syn::ExprPath> { + self.getter.as_ref() + } + + pub fn flatten(&self) -> bool { + self.flatten + } + + pub fn transparent(&self) -> bool { + self.transparent + } + + pub fn mark_transparent(&mut self) { + self.transparent = true; + } +} + +type SerAndDe = (Option, Option); + +fn get_ser_and_de<'c, T, F, R>( + cx: &'c Ctxt, + attr_name: Symbol, + meta: &ParseNestedMeta, + f: F, +) -> syn::Result<(VecAttr<'c, T>, VecAttr<'c, T>)> +where + 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); + + 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); + } + } 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, + ))); + } + Ok(()) + })?; + } else { + return Err(lookahead.error()); + } + + Ok((ser_meta, de_meta)) +} + +fn get_renames( + cx: &Ctxt, + 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( + cx: &Ctxt, + 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, + 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())) +} + +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( + cx: &Ctxt, + attr_name: Symbol, + meta_item_name: Symbol, + 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( + expr, + format!( + "expected serde {} attribute to be a string: `{} = \"...\"`", + attr_name, meta_item_name + ), + ); + Ok(None) + } +} + +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, + 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 + } + }) +} + +fn parse_lit_into_where( + cx: &Ctxt, + attr_name: Symbol, + meta_item_name: Symbol, + meta: &ParseNestedMeta, +) -> syn::Result> { + let Some(string) = get_lit_str2(cx, attr_name, meta_item_name, meta)? else { + return Ok(Vec::new()); + }; + + 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, + meta: &ParseNestedMeta, +) -> syn::Result> { + let Some(string) = get_lit_str(cx, attr_name, meta)? else { + return Ok(None); + }; + + Ok(match string.parse() { + Ok(ty) => Some(ty), + Err(_) => { + cx.error_spanned_by( + &string, + format!("failed to parse type: {} = {:?}", attr_name, string.value()), + ); + None + } + }) +} + +// Parses a string literal like "'a + 'b + 'c" containing a nonempty list of +// lifetimes separated by `+`. +fn parse_lit_into_lifetimes( + cx: &Ctxt, + meta: &ParseNestedMeta, +) -> syn::Result> { + let Some(string) = get_lit_str(cx, BORROW, meta)? else { + return Ok(BTreeSet::new()); + }; + + if let Ok(lifetimes) = string.parse_with(|input: ParseStream| { + let mut set = BTreeSet::new(); + while !input.is_empty() { + let lifetime: Lifetime = input.parse()?; + if !set.insert(lifetime.clone()) { + cx.error_spanned_by( + &string, + format!("duplicate borrowed lifetime `{}`", lifetime), + ); + } + if input.is_empty() { + break; + } + input.parse::()?; + } + 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( + &string, + format!("failed to parse borrowed lifetimes: {:?}", string.value()), + ); + Ok(BTreeSet::new()) +} + +fn is_implicitly_borrowed(ty: &syn::Type) -> bool { + is_implicitly_borrowed_reference(ty) || is_option(ty, is_implicitly_borrowed_reference) +} + +fn is_implicitly_borrowed_reference(ty: &syn::Type) -> bool { + is_reference(ty, is_str) || is_reference(ty, is_slice_u8) +} + +// Whether the type looks like it might be `std::borrow::Cow` where elem="T". +// This can have false negatives and false positives. +// +// False negative: +// +// use std::borrow::Cow as Pig; +// +// #[derive(Deserialize)] +// struct S<'a> { +// #[serde(borrow)] +// pig: Pig<'a, str>, +// } +// +// False positive: +// +// type str = [i16]; +// +// #[derive(Deserialize)] +// struct S<'a> { +// #[serde(borrow)] +// cow: Cow<'a, str>, +// } +fn is_cow(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { + let path = match ungroup(ty) { + syn::Type::Path(ty) => &ty.path, + _ => { + return false; + } + }; + let Some(seg) = path.segments.last() else { + return false; + }; + let args = match &seg.arguments { + syn::PathArguments::AngleBracketed(bracketed) => &bracketed.args, + _ => { + return false; + } + }; + seg.ident == "Cow" + && args.len() == 2 + && match (&args[0], &args[1]) { + (syn::GenericArgument::Lifetime(_), syn::GenericArgument::Type(arg)) => elem(arg), + _ => false, + } +} + +fn is_option(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { + let path = match ungroup(ty) { + syn::Type::Path(ty) => &ty.path, + _ => { + return false; + } + }; + let Some(seg) = path.segments.last() else { + return false; + }; + let args = match &seg.arguments { + syn::PathArguments::AngleBracketed(bracketed) => &bracketed.args, + _ => { + return false; + } + }; + seg.ident == "Option" + && args.len() == 1 + && match &args[0] { + syn::GenericArgument::Type(arg) => elem(arg), + _ => false, + } +} + +// Whether the type looks like it might be `&T` where elem="T". This can have +// false negatives and false positives. +// +// False negative: +// +// type Yarn = str; +// +// #[derive(Deserialize)] +// struct S<'a> { +// r: &'a Yarn, +// } +// +// False positive: +// +// type str = [i16]; +// +// #[derive(Deserialize)] +// struct S<'a> { +// r: &'a str, +// } +fn is_reference(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { + match ungroup(ty) { + syn::Type::Reference(ty) => ty.mutability.is_none() && elem(&ty.elem), + _ => false, + } +} + +fn is_str(ty: &syn::Type) -> bool { + is_primitive_type(ty, "str") +} + +fn is_slice_u8(ty: &syn::Type) -> bool { + match ungroup(ty) { + syn::Type::Slice(ty) => is_primitive_type(&ty.elem, "u8"), + _ => false, + } +} + +fn is_primitive_type(ty: &syn::Type, primitive: &str) -> bool { + match ungroup(ty) { + syn::Type::Path(ty) => ty.qself.is_none() && is_primitive_path(&ty.path, primitive), + _ => false, + } +} + +fn is_primitive_path(path: &syn::Path, primitive: &str) -> bool { + path.leading_colon.is_none() + && path.segments.len() == 1 + && path.segments[0].ident == primitive + && path.segments[0].arguments.is_empty() +} + +// All lifetimes that this type could borrow from a Deserializer. +// +// For example a type `S<'a, 'b>` could borrow `'a` and `'b`. On the other hand +// a type `for<'a> fn(&'a str)` could not borrow `'a` from the Deserializer. +// +// This is used when there is an explicit or implicit `#[serde(borrow)]` +// attribute on the field so there must be at least one borrowable lifetime. +fn borrowable_lifetimes( + cx: &Ctxt, + name: &Name, + field: &syn::Field, +) -> Result, ()> { + let mut lifetimes = BTreeSet::new(); + collect_lifetimes(&field.ty, &mut lifetimes); + if lifetimes.is_empty() { + let msg = format!("field `{}` has no lifetimes to borrow", name); + cx.error_spanned_by(field, msg); + Err(()) + } else { + Ok(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); + } + syn::Type::Array(ty) => { + collect_lifetimes(&ty.elem, out); + } + syn::Type::Ptr(ty) => { + collect_lifetimes(&ty.elem, out); + } + syn::Type::Reference(ty) => { + out.extend(ty.lifetime.iter().cloned()); + collect_lifetimes(&ty.elem, out); + } + syn::Type::Tuple(ty) => { + for elem in &ty.elems { + collect_lifetimes(elem, out); + } + } + syn::Type::Path(ty) => { + if let Some(qself) = &ty.qself { + collect_lifetimes(&qself.ty, out); + } + for seg in &ty.path.segments { + if let syn::PathArguments::AngleBracketed(bracketed) = &seg.arguments { + for arg in &bracketed.args { + match arg { + syn::GenericArgument::Lifetime(lifetime) => { + out.insert(lifetime.clone()); + } + syn::GenericArgument::Type(ty) => { + collect_lifetimes(ty, out); + } + syn::GenericArgument::AssocType(binding) => { + collect_lifetimes(&binding.ty, out); + } + syn::GenericArgument::Const(_) + | syn::GenericArgument::AssocConst(_) + | syn::GenericArgument::Constraint(_) + | _ => {} + } + } + } + } + } + syn::Type::Paren(ty) => { + collect_lifetimes(&ty.elem, out); + } + syn::Type::Group(ty) => { + collect_lifetimes(&ty.elem, out); + } + syn::Type::Macro(ty) => { + collect_lifetimes_from_tokens(ty.mac.tokens.clone(), out); + } + syn::Type::FnPtr(_) + | syn::Type::Never(_) + | syn::Type::TraitObject(_) + | syn::Type::ImplTrait(_) + | syn::Type::Infer(_) + | syn::Type::Verbatim(_) => {} + + _ => {} + } +} + +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); + } + _ => {} + } + } +} diff --git a/third_party/crates/serde_derive-1.0.229/src/internals/case.rs b/third_party/crates/serde_derive-1.0.229/src/internals/case.rs new file mode 100644 index 0000000..8c8c02e --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/src/internals/case.rs @@ -0,0 +1,200 @@ +//! 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`). + +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)] +pub enum RenameRule { + /// Don't apply a default rename rule. + None, + /// Rename direct children to "lowercase" style. + LowerCase, + /// Rename direct children to "UPPERCASE" style. + UpperCase, + /// Rename direct children to "PascalCase" style, as typically used for + /// enum variants. + PascalCase, + /// Rename direct children to "camelCase" style. + CamelCase, + /// Rename direct children to "snake_case" style, as commonly used for + /// fields. + SnakeCase, + /// Rename direct children to "SCREAMING_SNAKE_CASE" style, as commonly + /// used for constants. + ScreamingSnakeCase, + /// Rename direct children to "kebab-case" style. + KebabCase, + /// Rename direct children to "SCREAMING-KEBAB-CASE" style. + 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 { + None | PascalCase => variant.to_owned(), + LowerCase => variant.to_ascii_lowercase(), + UpperCase => variant.to_ascii_uppercase(), + CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..], + SnakeCase => { + let mut snake = String::new(); + for (i, ch) in variant.char_indices() { + if i > 0 && ch.is_uppercase() { + snake.push('_'); + } + snake.push(ch.to_ascii_lowercase()); + } + snake + } + ScreamingSnakeCase => SnakeCase.apply_to_variant(variant).to_ascii_uppercase(), + KebabCase => SnakeCase.apply_to_variant(variant).replace('_', "-"), + ScreamingKebabCase => ScreamingSnakeCase + .apply_to_variant(variant) + .replace('_', "-"), + } + } + + /// 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 { + None | LowerCase | SnakeCase => field.to_owned(), + UpperCase => field.to_ascii_uppercase(), + PascalCase => { + let mut pascal = String::new(); + let mut capitalize = true; + for ch in field.chars() { + if ch == '_' { + capitalize = true; + } else if capitalize { + pascal.push(ch.to_ascii_uppercase()); + capitalize = false; + } else { + pascal.push(ch); + } + } + pascal + } + CamelCase => { + let pascal = PascalCase.apply_to_field(field); + pascal[..1].to_ascii_lowercase() + &pascal[1..] + } + ScreamingSnakeCase => field.to_ascii_uppercase(), + KebabCase => field.replace('_', "-"), + 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, + } + } +} + +pub struct ParseError<'a> { + unknown: &'a str, +} + +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(()) + } +} + +#[test] +fn rename_variants() { + for &(original, lower, upper, camel, snake, screaming, kebab, screaming_kebab) in &[ + ( + "Outcome", "outcome", "OUTCOME", "outcome", "outcome", "OUTCOME", "outcome", "OUTCOME", + ), + ( + "VeryTasty", + "verytasty", + "VERYTASTY", + "veryTasty", + "very_tasty", + "VERY_TASTY", + "very-tasty", + "VERY-TASTY", + ), + ("A", "a", "A", "a", "a", "A", "a", "A"), + ("Z42", "z42", "Z42", "z42", "z42", "Z42", "z42", "Z42"), + ] { + 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!(PascalCase.apply_to_variant(original), original); + assert_eq!(CamelCase.apply_to_variant(original), camel); + assert_eq!(SnakeCase.apply_to_variant(original), snake); + assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming); + assert_eq!(KebabCase.apply_to_variant(original), kebab); + assert_eq!( + ScreamingKebabCase.apply_to_variant(original), + screaming_kebab + ); + } +} + +#[test] +fn rename_fields() { + for &(original, upper, pascal, camel, screaming, kebab, screaming_kebab) in &[ + ( + "outcome", "OUTCOME", "Outcome", "outcome", "OUTCOME", "outcome", "OUTCOME", + ), + ( + "very_tasty", + "VERY_TASTY", + "VeryTasty", + "veryTasty", + "VERY_TASTY", + "very-tasty", + "VERY-TASTY", + ), + ("a", "A", "A", "a", "A", "a", "A"), + ("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!(PascalCase.apply_to_field(original), pascal); + assert_eq!(CamelCase.apply_to_field(original), camel); + assert_eq!(SnakeCase.apply_to_field(original), original); + assert_eq!(ScreamingSnakeCase.apply_to_field(original), screaming); + assert_eq!(KebabCase.apply_to_field(original), kebab); + assert_eq!(ScreamingKebabCase.apply_to_field(original), screaming_kebab); + } +} diff --git a/third_party/crates/serde_derive-1.0.229/src/internals/check.rs b/third_party/crates/serde_derive-1.0.229/src/internals/check.rs new file mode 100644 index 0000000..da2a0fb --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/src/internals/check.rs @@ -0,0 +1,477 @@ +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. +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); + check_variant_skip_attrs(cx, cont); + check_internal_tag_field_name_conflict(cx, cont); + check_adjacent_tag_conflict(cx, cont); + check_transparent(cx, cont, derive); + check_from_and_try_from(cx, cont); +} + +// 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(_) => { + if cont.data.has_getter() { + cx.error_spanned_by( + cont.original, + "#[serde(getter = \"...\")] is not allowed in an enum", + ); + } + } + Data::Struct(_, _) => { + if cont.data.has_getter() && cont.attrs.remote().is_none() { + cx.error_spanned_by( + cont.original, + "#[serde(getter = \"...\")] can only be used in structs that have #[serde(remote = \"...\")]", + ); + } + } + } +} + +// Flattening has some restrictions we can test. +fn check_flatten(cx: &Ctxt, cont: &Container) { + match &cont.data { + Data::Enum(variants) => { + for variant in variants { + for field in &variant.fields { + check_flatten_field(cx, variant.style, field); + } + } + } + Data::Struct(style, fields) => { + for field in fields { + check_flatten_field(cx, *style, field); + } + } + } +} + +fn check_flatten_field(cx: &Ctxt, style: Style, field: &Field) { + if !field.attrs.flatten() { + return; + } + match style { + Style::Tuple => { + cx.error_spanned_by( + field.original, + "#[serde(flatten)] cannot be used on tuple structs", + ); + } + Style::Newtype => { + cx.error_spanned_by( + field.original, + "#[serde(flatten)] cannot be used on newtype structs", + ); + } + _ => {} + } +} + +// 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, + }; + + for (i, variant) in variants.iter().enumerate() { + match ( + variant.style, + cont.attrs.identifier(), + variant.attrs.other(), + cont.attrs.tag(), + ) { + // The `other` attribute may not be used in a variant_identifier. + (_, Identifier::Variant, true, _) => { + cx.error_spanned_by( + variant.original, + "#[serde(other)] may not be used on a variant identifier", + ); + } + + // Variant with `other` attribute cannot appear in untagged enum + (_, Identifier::No, true, &TagType::None) => { + cx.error_spanned_by( + variant.original, + "#[serde(other)] cannot appear on untagged enum", + ); + } + + // Variant with `other` attribute must be the last one. + (Style::Unit, Identifier::Field, true, _) | (Style::Unit, Identifier::No, true, _) => { + if i < variants.len() - 1 { + cx.error_spanned_by( + variant.original, + "#[serde(other)] must be on the last variant", + ); + } + } + + // Variant with `other` attribute must be a unit variant. + (_, Identifier::Field, true, _) | (_, Identifier::No, true, _) => { + cx.error_spanned_by( + variant.original, + "#[serde(other)] must be on a unit variant", + ); + } + + // Any sort of variant is allowed if this is not an identifier. + (_, Identifier::No, false, _) => {} + + // Unit variant without `other` attribute is always fine. + (Style::Unit, _, false, _) => {} + + // The last field is allowed to be a newtype catch-all. + (Style::Newtype, Identifier::Field, false, _) => { + if i < variants.len() - 1 { + cx.error_spanned_by( + variant.original, + format!("`{}` must be the last variant", variant.ident), + ); + } + } + + (_, Identifier::Field, false, _) => { + cx.error_spanned_by( + variant.original, + "#[serde(field_identifier)] may only contain unit variants", + ); + } + + (_, Identifier::Variant, false, _) => { + cx.error_spanned_by( + variant.original, + "#[serde(variant_identifier)] may only contain unit variants", + ); + } + } + } +} + +// 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, + }; + + for variant in variants { + if variant.attrs.serialize_with().is_some() { + if variant.attrs.skip_serializing() { + cx.error_spanned_by( + variant.original, + format!( + "variant `{}` cannot have both #[serde(serialize_with)] and #[serde(skip_serializing)]", + variant.ident + ), + ); + } + + for field in &variant.fields { + let member = member_message(&field.member); + + if field.attrs.skip_serializing() { + cx.error_spanned_by( + variant.original, + format!( + "variant `{}` cannot have both #[serde(serialize_with)] and a field {} marked with #[serde(skip_serializing)]", + variant.ident, member + ), + ); + } + + if field.attrs.skip_serializing_if().is_some() { + cx.error_spanned_by( + variant.original, + format!( + "variant `{}` cannot have both #[serde(serialize_with)] and a field {} marked with #[serde(skip_serializing_if)]", + variant.ident, member + ), + ); + } + } + } + + if variant.attrs.deserialize_with().is_some() { + if variant.attrs.skip_deserializing() { + cx.error_spanned_by( + variant.original, + format!( + "variant `{}` cannot have both #[serde(deserialize_with)] and #[serde(skip_deserializing)]", + variant.ident + ), + ); + } + + for field in &variant.fields { + if field.attrs.skip_deserializing() { + let member = member_message(&field.member); + + cx.error_spanned_by( + variant.original, + format!( + "variant `{}` cannot have both #[serde(deserialize_with)] and a field {} marked with #[serde(skip_deserializing)]", + variant.ident, member + ), + ); + } + } + } + } +} + +// 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, + Data::Struct(_, _) => return, + }; + + let tag = match cont.attrs.tag() { + TagType::Internal { tag } => tag.as_str(), + TagType::External | TagType::Adjacent { .. } | TagType::None => return, + }; + + let diagnose_conflict = || { + 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() || 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.value == tag { + diagnose_conflict(); + return; + } + + for de_name in field.attrs.aliases() { + if check_de && de_name.value == tag { + diagnose_conflict(); + return; + } + } + } + } + Style::Unit | Style::Newtype | Style::Tuple => {} + } + } +} + +// 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), + TagType::Internal { .. } | TagType::External | TagType::None => return, + }; + + if type_tag == content_tag { + cx.error_spanned_by( + cont.original, + format!( + "enum tags `{}` for type and content conflict with each other", + type_tag + ), + ); + } +} + +// Enums and unit structs cannot be transparent. +fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) { + if !cont.attrs.transparent() { + return; + } + + if cont.attrs.type_from().is_some() { + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] is not allowed with #[serde(from = \"...\")]", + ); + } + + if cont.attrs.type_try_from().is_some() { + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] is not allowed with #[serde(try_from = \"...\")]", + ); + } + + if cont.attrs.type_into().is_some() { + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] is not allowed with #[serde(into = \"...\")]", + ); + } + + let fields = match &mut cont.data { + Data::Enum(_) => { + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] is not allowed on an enum", + ); + return; + } + Data::Struct(Style::Unit, _) => { + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] is not allowed on a unit struct", + ); + return; + } + Data::Struct(_, fields) => fields, + }; + + let mut transparent_field = None; + + for field in fields { + if allow_transparent(field, derive) { + if transparent_field.is_some() { + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] requires struct to have at most one transparent field", + ); + return; + } + transparent_field = Some(field); + } + } + + match transparent_field { + Some(transparent_field) => transparent_field.attrs.mark_transparent(), + None => match derive { + Derive::Serialize => { + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] requires at least one field that is not skipped", + ); + } + Derive::Deserialize => { + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] requires at least one field that is neither skipped nor has a default", + ); + } + }, + } +} + +fn member_message(member: &Member) -> String { + match member { + Member::Named(ident) => format!("`{}`", ident), + Member::Unnamed(i) => format!("#{}", i.index), + } +} + +fn allow_transparent(field: &Field, derive: Derive) -> bool { + if let Type::Path(ty) = ungroup(field.ty) { + if let Some(seg) = ty.path.segments.last() { + if seg.ident == "PhantomData" { + return false; + } + } + } + + match derive { + Derive::Serialize => !field.attrs.skip_serializing(), + Derive::Deserialize => !field.attrs.skip_deserializing() && field.attrs.default().is_none(), + } +} + +fn check_from_and_try_from(cx: &Ctxt, cont: &mut Container) { + if cont.attrs.type_from().is_some() && cont.attrs.type_try_from().is_some() { + cx.error_spanned_by( + cont.original, + "#[serde(from = \"...\")] and #[serde(try_from = \"...\")] conflict with each other", + ); + } +} diff --git a/third_party/crates/serde_derive-1.0.229/src/internals/ctxt.rs b/third_party/crates/serde_derive-1.0.229/src/internals/ctxt.rs new file mode 100644 index 0000000..30e1a72 --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/src/internals/ctxt.rs @@ -0,0 +1,67 @@ +use quote::ToTokens; +use std::cell::RefCell; +use std::fmt::Display; +use std::thread; + +/// A type to collect errors together and format them. +/// +/// Dropping this object will cause a panic. It must be consumed using `check`. +/// +/// References can be shared since this type uses run-time exclusive mut checking. +#[derive(Default)] +pub struct Ctxt { + // The contents will be set to `None` during checking. This is so that checking can be + // enforced. + errors: RefCell>>, +} + +impl Ctxt { + /// Create a new context object. + /// + /// This object contains no errors, but will still trigger a panic if it is not `check`ed. + pub fn new() -> Self { + Ctxt { + errors: RefCell::new(Some(Vec::new())), + } + } + + /// Add an error to the context object with a tokenizable object. + /// + /// The object is used for spanning in error messages. + pub fn error_spanned_by(&self, obj: A, msg: T) { + self.errors + .borrow_mut() + .as_mut() + .unwrap() + // Curb monomorphization from generating too many identical methods. + .push(syn::Error::new_spanned(obj.into_token_stream(), msg)); + } + + /// Add one of Syn's parse errors. + pub fn syn_error(&self, err: syn::Error) { + self.errors.borrow_mut().as_mut().unwrap().push(err); + } + + /// Consume this object, producing a formatted error string if there are errors. + 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) + } +} + +impl Drop for Ctxt { + fn drop(&mut self) { + if !thread::panicking() && self.errors.borrow().is_some() { + panic!("forgot to check for errors"); + } + } +} diff --git a/third_party/crates/serde_derive-1.0.229/src/internals/mod.rs b/third_party/crates/serde_derive-1.0.229/src/internals/mod.rs new file mode 100644 index 0000000..cd1e810 --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/src/internals/mod.rs @@ -0,0 +1,28 @@ +pub mod ast; +pub mod attr; +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, + Deserialize, +} + +pub fn ungroup(mut ty: &Type) -> &Type { + while let Type::Group(group) = ty { + ty = &group.elem; + } + ty +} diff --git a/third_party/crates/serde_derive-1.0.229/src/internals/name.rs b/third_party/crates/serde_derive-1.0.229/src/internals/name.rs new file mode 100644 index 0000000..4c59f96 --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/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/third_party/crates/serde_derive-1.0.229/src/internals/receiver.rs b/third_party/crates/serde_derive-1.0.229/src/internals/receiver.rs new file mode 100644 index 0000000..ca0d54f --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/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::FnPtr(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(&mut argument.ty); + } + 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/third_party/crates/serde_derive-1.0.229/src/internals/respan.rs b/third_party/crates/serde_derive-1.0.229/src/internals/respan.rs new file mode 100644 index 0000000..dcec701 --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/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/third_party/crates/serde_derive-1.0.229/src/internals/symbol.rs b/third_party/crates/serde_derive-1.0.229/src/internals/symbol.rs new file mode 100644 index 0000000..59ef8de --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/src/internals/symbol.rs @@ -0,0 +1,71 @@ +use std::fmt::{self, Display}; +use syn::{Ident, Path}; + +#[derive(Copy, Clone)] +pub struct Symbol(&'static str); + +pub const ALIAS: Symbol = Symbol("alias"); +pub const BORROW: Symbol = Symbol("borrow"); +pub const BOUND: Symbol = Symbol("bound"); +pub const CONTENT: Symbol = Symbol("content"); +pub const CRATE: Symbol = Symbol("crate"); +pub const DEFAULT: Symbol = Symbol("default"); +pub const DENY_UNKNOWN_FIELDS: Symbol = Symbol("deny_unknown_fields"); +pub const DESERIALIZE: Symbol = Symbol("deserialize"); +pub const DESERIALIZE_WITH: Symbol = Symbol("deserialize_with"); +pub const 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"); +pub const SKIP: Symbol = Symbol("skip"); +pub const SKIP_DESERIALIZING: Symbol = Symbol("skip_deserializing"); +pub const SKIP_SERIALIZING: Symbol = Symbol("skip_serializing"); +pub const SKIP_SERIALIZING_IF: Symbol = Symbol("skip_serializing_if"); +pub const TAG: Symbol = Symbol("tag"); +pub const TRANSPARENT: Symbol = Symbol("transparent"); +pub const TRY_FROM: Symbol = Symbol("try_from"); +pub const UNTAGGED: Symbol = Symbol("untagged"); +pub const VARIANT_IDENTIFIER: Symbol = Symbol("variant_identifier"); +pub const WITH: Symbol = Symbol("with"); + +impl PartialEq for Ident { + fn eq(&self, word: &Symbol) -> bool { + self == word.0 + } +} + +impl PartialEq for &Ident { + fn eq(&self, word: &Symbol) -> bool { + *self == word.0 + } +} + +impl PartialEq for Path { + fn eq(&self, word: &Symbol) -> bool { + self.is_ident(word.0) + } +} + +impl PartialEq for &Path { + fn eq(&self, word: &Symbol) -> bool { + self.is_ident(word.0) + } +} + +impl Display for Symbol { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(self.0) + } +} diff --git a/third_party/crates/serde_derive-1.0.229/src/lib.rs b/third_party/crates/serde_derive-1.0.229/src/lib.rs new file mode 100644 index 0000000..7fcd1f7 --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/src/lib.rs @@ -0,0 +1,127 @@ +//! This crate provides Serde's two derive macros. +//! +//! ```edition2021 +//! # use serde_derive::{Deserialize, Serialize}; +//! # +//! #[derive(Serialize, Deserialize)] +//! # struct S; +//! # +//! # fn main() {} +//! ``` +//! +//! Please refer to [https://serde.rs/derive.html] for how to set this up. +//! +//! [https://serde.rs/derive.html]: https://serde.rs/derive.html + +#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.229")] +#![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, + clippy::used_underscore_binding, + clippy::wildcard_in_or_patterns, + // clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704 + clippy::unnested_or_patterns, +)] +// Ignored clippy_pedantic lints +#![allow( + clippy::cast_possible_truncation, + clippy::checked_conversions, + clippy::doc_markdown, + clippy::elidable_lifetime_names, + clippy::enum_glob_use, + 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::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)] + +extern crate proc_macro2; +extern crate quote; +extern crate syn; + +extern crate proc_macro; + +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] +mod bound; +#[macro_use] +mod fragment; + +mod de; +mod deprecated; +mod dummy; +mod pretend; +mod ser; +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 mut input = parse_macro_input!(input as DeriveInput); + ser::expand_derive_serialize(&mut input) + .unwrap_or_else(syn::Error::into_compile_error) + .into() +} + +#[proc_macro_derive(Deserialize, attributes(serde))] +pub fn derive_deserialize(input: TokenStream) -> TokenStream { + let mut input = parse_macro_input!(input as DeriveInput); + de::expand_derive_deserialize(&mut input) + .unwrap_or_else(syn::Error::into_compile_error) + .into() +} diff --git a/third_party/crates/serde_derive-1.0.229/src/pretend.rs b/third_party/crates/serde_derive-1.0.229/src/pretend.rs new file mode 100644 index 0000000..b6173bb --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/src/pretend.rs @@ -0,0 +1,188 @@ +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 +// never has its fields referenced and an enum annotated with remote derive +// never has its variants constructed. +// +// warning: field is never used: `i` +// --> src/main.rs:4:20 +// | +// 4 | struct StructDef { i: i32 } +// | ^^^^^^ +// +// warning: variant is never constructed: `V` +// --> src/main.rs:8:16 +// | +// 8 | enum EnumDef { V } +// | ^ +// +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! { + #pretend_fields + #pretend_variants + } +} + +// 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: __v0, b: __v1 }) => {} +// _ => {} +// } +// +// For enums, expands to the following but only including struct variants: +// +// match None::<&T> { +// Some(T::A { a: __v0 }) => {} +// Some(T::B { b: __v0 }) => {} +// _ => {} +// } +// +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 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),* }) => {} + _ => {} + } + } +} + +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 mut patterns = Vec::new(); + for variant in variants { + 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)); + patterns.push(quote!(#type_ident::#variant_ident { #(#members: #placeholders),* })); + } + Style::Unit => {} + } + } + + let private2 = private; + quote! { + match _serde::#private::None::<&#type_ident #ty_generics> { + #( + _serde::#private2::Some(#patterns) => {} + )* + _ => {} + } + } +} + +// Expands to one of these per enum variant: +// +// match None { +// Some((__v0, __v1,)) => { +// let _ = E::V { a: __v0, b: __v1 }; +// } +// _ => {} +// } +// +fn pretend_variants_used(cont: &Container) -> TokenStream { + let variants = match &cont.data { + Data::Enum(variants) => variants, + Data::Struct(_, _) => { + return quote!(); + } + }; + + let type_ident = &cont.ident; + let (_, ty_generics, _) = cont.generics.split_for_impl(); + let turbofish = ty_generics.as_turbofish(); + + let cases = variants.iter().map(|variant| { + let variant_ident = &variant.ident; + let placeholders = &(0..variant.fields.len()) + .map(|i| format_ident!("__v{}", i)) + .collect::>(); + + let pat = match variant.style { + Style::Struct => { + let members = variant.fields.iter().map(|field| &field.member); + quote!({ #(#members: #placeholders),* }) + } + Style::Tuple | Style::Newtype => quote!(( #(#placeholders),* )), + Style::Unit => quote!(), + }; + + quote! { + match _serde::#private::None { + _serde::#private::Some((#(#placeholders,)*)) => { + let _ = #type_ident::#variant_ident #turbofish #pat; + } + _ => {} + } + } + }); + + quote!(#(#cases)*) +} diff --git a/third_party/crates/serde_derive-1.0.229/src/ser.rs b/third_party/crates/serde_derive-1.0.229/src/ser.rs new file mode 100644 index 0000000..6eb3b0f --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/src/ser.rs @@ -0,0 +1,1369 @@ +use crate::de::field_i; +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::{parse_quote, Ident, Index, Member}; + +pub fn expand_derive_serialize(input: &mut syn::DeriveInput) -> syn::Result { + replace_receiver(input); + + let ctxt = Ctxt::new(); + let Some(cont) = Container::from_ast(&ctxt, input, Derive::Serialize, &private.ident()) else { + return Err(ctxt.check().unwrap_err()); + }; + precondition(&ctxt, &cont); + ctxt.check()?; + + let ident = &cont.ident; + let params = Parameters::new(&cont); + let (impl_generics, ty_generics, where_clause) = params.generics.split_for_impl(); + let body = Stmts(serialize_body(&cont, ¶ms)); + 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, params.is_packed); + quote! { + #[automatically_derived] + #allow_deprecated + impl #impl_generics #ident #ty_generics #where_clause { + #vis fn serialize<__S>(__self: &#remote #ty_generics, __serializer: __S) -> _serde::#private::Result<__S::Ok, __S::Error> + where + __S: _serde::Serializer, + { + #used + #body + } + } + } + } else { + quote! { + #[automatically_derived] + #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, + { + #body + } + } + } + }; + + Ok(dummy::wrap_in_const( + cont.attrs.custom_serde_path(), + impl_block, + )) +} + +fn precondition(cx: &Ctxt, cont: &Container) { + match cont.attrs.identifier() { + attr::Identifier::No => {} + attr::Identifier::Field => { + cx.error_spanned_by(cont.original, "field identifiers cannot be serialized"); + } + attr::Identifier::Variant => { + cx.error_spanned_by(cont.original, "variant identifiers cannot be serialized"); + } + } +} + +struct Parameters { + /// Variable holding the value being serialized. Either `self` for local + /// types or `__self` for remote types. + self_var: Ident, + + /// Path to the type the impl is for. Either a single `Ident` for local + /// types (does not include generic parameters) or `some::remote::Path` for + /// remote types. + this_type: syn::Path, + + /// Same as `this_type` but using `::` 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, + + /// Type has a `serde(remote = "...")` attribute. + is_remote: bool, + + /// Type has a repr(packed) attribute. + is_packed: bool, +} + +impl Parameters { + fn new(cont: &Container) -> Self { + let is_remote = cont.attrs.remote().is_some(); + let self_var = if is_remote { + Ident::new("__self", Span::call_site()) + } else { + Ident::new("self", Span::call_site()) + }; + + 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_type, + this_value, + generics, + is_remote, + is_packed, + } + } + + /// Type name to use in error messages and `&'static str` arguments to + /// various Serializer methods. + fn type_name(&self) -> String { + self.this_type.segments.last().unwrap().ident.to_string() + } +} + +// All the generics in the input, plus a bound `T: Serialize` for each generic +// field type that will be serialized by us. +fn build_generics(cont: &Container) -> syn::Generics { + let generics = bound::without_defaults(cont.generics); + + let generics = + bound::with_where_predicates_from_fields(cont, &generics, attr::Field::ser_bound); + + let generics = + bound::with_where_predicates_from_variants(cont, &generics, attr::Variant::ser_bound); + + match cont.attrs.ser_bound() { + Some(predicates) => bound::with_where_predicates(&generics, predicates), + None => bound::with_bound( + cont, + &generics, + needs_serialize_bound, + &parse_quote!(_serde::Serialize), + ), + } +} + +// Fields with a `skip_serializing` or `serialize_with` attribute, or which +// 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. +fn needs_serialize_bound(field: &attr::Field, variant: Option<&attr::Variant>) -> bool { + !field.skip_serializing() + && field.serialize_with().is_none() + && field.ser_bound().is_none() + && variant.map_or(true, |variant| { + !variant.skip_serializing() + && variant.serialize_with().is_none() + && variant.ser_bound().is_none() + }) +} + +fn serialize_body(cont: &Container, params: &Parameters) -> Fragment { + if cont.attrs.transparent() { + serialize_transparent(cont, params) + } else if let Some(type_into) = cont.attrs.type_into() { + serialize_into(params, type_into) + } else { + match &cont.data { + Data::Enum(variants) => serialize_enum(params, variants, &cont.attrs), + Data::Struct(Style::Struct, fields) => serialize_struct(params, fields, &cont.attrs), + Data::Struct(Style::Tuple, fields) => { + serialize_tuple_struct(params, fields, &cont.attrs) + } + Data::Struct(Style::Newtype, fields) => { + serialize_newtype_struct(params, &fields[0], &cont.attrs) + } + Data::Struct(Style::Unit, _) => serialize_unit_struct(&cont.attrs), + } + } +} + +fn serialize_transparent(cont: &Container, params: &Parameters) -> Fragment { + let fields = match &cont.data { + Data::Struct(_, fields) => fields, + Data::Enum(_) => unreachable!(), + }; + + let self_var = ¶ms.self_var; + let transparent_field = fields.iter().find(|f| f.attrs.transparent()).unwrap(); + let member = &transparent_field.member; + + let path = match transparent_field.attrs.serialize_with() { + Some(path) => quote!(#path), + None => { + let span = transparent_field.original.span(); + quote_spanned!(span=> _serde::Serialize::serialize) + } + }; + + quote_block! { + #path(&#self_var.#member, __serializer) + } +} + +fn serialize_into(params: &Parameters, type_into: &syn::Type) -> Fragment { + let self_var = ¶ms.self_var; + quote_block! { + _serde::Serialize::serialize( + &_serde::#private::Into::<#type_into>::into(_serde::#private::Clone::clone(#self_var)), + __serializer) + } +} + +fn serialize_unit_struct(cattrs: &attr::Container) -> Fragment { + let type_name = cattrs.name().serialize_name(); + + quote_expr! { + _serde::Serializer::serialize_unit_struct(__serializer, #type_name) + } +} + +fn serialize_newtype_struct( + params: &Parameters, + field: &Field, + cattrs: &attr::Container, +) -> Fragment { + let type_name = cattrs.name().serialize_name(); + + let mut field_expr = get_member( + params, + field, + &Member::Unnamed(Index { + index: 0, + span: Span::call_site(), + }), + ); + if let Some(path) = field.attrs.serialize_with() { + field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); + } + + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::Serializer::serialize_newtype_struct); + quote_expr! { + #func(__serializer, #type_name, #field_expr) + } +} + +fn serialize_tuple_struct( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, +) -> Fragment { + let serialize_stmts = + serialize_tuple_struct_visitor(fields, params, false, &TupleTrait::SerializeTupleStruct); + + let type_name = cattrs.name().serialize_name(); + + let mut serialized_fields = fields + .iter() + .enumerate() + .filter(|(_, field)| !field.attrs.skip_serializing()) + .peekable(); + + let let_mut = mut_if(serialized_fields.peek().is_some()); + + let len = serialized_fields + .map(|(i, field)| match field.attrs.skip_serializing_if() { + None => quote!(1), + Some(path) => { + let index = syn::Index { + index: i as u32, + span: Span::call_site(), + }; + let field_expr = get_member(params, field, &Member::Unnamed(index)); + quote!(if #path(#field_expr) { 0 } else { 1 }) + } + }) + .fold(quote!(0), |sum, expr| quote!(#sum + #expr)); + + quote_block! { + 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), + "too many fields in {}: {}, maximum supported count is {}", + cattrs.name().serialize_name(), + fields.len(), + u32::MAX, + ); + + 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) + } +} + +fn serialize_struct_tag_field(cattrs: &attr::Container, struct_trait: &StructTrait) -> TokenStream { + match cattrs.tag() { + attr::TagType::Internal { tag } => { + let type_name = cattrs.name().serialize_name(); + let func = struct_trait.serialize_field(Span::call_site()); + quote! { + #func(&mut __serde_state, #tag, #type_name)?; + } + } + _ => quote! {}, + } +} + +fn serialize_struct_as_struct( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, +) -> Fragment { + let serialize_fields = + serialize_struct_visitor(fields, params, false, &StructTrait::SerializeStruct); + + let type_name = cattrs.name().serialize_name(); + + let tag_field = serialize_struct_tag_field(cattrs, &StructTrait::SerializeStruct); + let tag_field_exists = !tag_field.is_empty(); + + let mut serialized_fields = fields + .iter() + .filter(|&field| !field.attrs.skip_serializing()) + .peekable(); + + let let_mut = mut_if(serialized_fields.peek().is_some() || tag_field_exists); + + 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_block! { + let #let_mut __serde_state = _serde::Serializer::serialize_struct(__serializer, #type_name, #len)?; + #tag_field + #(#serialize_fields)* + _serde::ser::SerializeStruct::end(__serde_state) + } +} + +fn serialize_struct_as_map( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, +) -> Fragment { + let serialize_fields = + serialize_struct_visitor(fields, params, false, &StructTrait::SerializeMap); + + let tag_field = serialize_struct_tag_field(cattrs, &StructTrait::SerializeMap); + let tag_field_exists = !tag_field.is_empty(); + + let mut serialized_fields = fields + .iter() + .filter(|&field| !field.attrs.skip_serializing()) + .peekable(); + + let let_mut = mut_if(serialized_fields.peek().is_some() || tag_field_exists); + + quote_block! { + let #let_mut __serde_state = _serde::Serializer::serialize_map(__serializer, _serde::#private::None)?; + #tag_field + #(#serialize_fields)* + _serde::ser::SerializeMap::end(__serde_state) + } +} + +fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Container) -> Fragment { + assert!(variants.len() as u64 <= u64::from(u32::MAX)); + + let self_var = ¶ms.self_var; + + let mut arms: Vec<_> = variants + .iter() + .enumerate() + .map(|(variant_index, variant)| { + serialize_variant(params, variant, variant_index as u32, cattrs) + }) + .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)* + } + } +} + +fn serialize_variant( + params: &Parameters, + variant: &Variant, + variant_index: u32, + cattrs: &attr::Container, +) -> TokenStream { + let this_value = ¶ms.this_value; + let variant_ident = &variant.ident; + + if variant.attrs.skip_serializing() { + let skipped_msg = format!( + "the enum variant {}::{} cannot be serialized", + params.type_name(), + variant_ident + ); + let skipped_err = quote! { + _serde::#private::Err(_serde::ser::Error::custom(#skipped_msg)) + }; + let fields_pat = match variant.style { + Style::Unit => quote!(), + Style::Newtype | Style::Tuple => quote!((..)), + Style::Struct => quote!({ .. }), + }; + quote! { + #this_value::#variant_ident #fields_pat => #skipped_err, + } + } else { + // variant wasn't skipped + let case = match variant.style { + Style::Unit => { + quote! { + #this_value::#variant_ident + } + } + Style::Newtype => { + quote! { + #this_value::#variant_ident(ref __field0) + } + } + Style::Tuple => { + let field_names = (0..variant.fields.len()).map(field_i); + quote! { + #this_value::#variant_ident(#(ref #field_names),*) + } + } + Style::Struct => { + let members = variant.fields.iter().map(|f| &f.member); + quote! { + #this_value::#variant_ident { #(ref #members),* } + } + } + }; + + 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 }, false) => { + serialize_internally_tagged_variant(params, variant, cattrs, tag) + } + (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) + } + }); + + quote! { + #case => #body + } + } +} + +fn serialize_externally_tagged_variant( + params: &Parameters, + variant: &Variant, + variant_index: u32, + cattrs: &attr::Container, +) -> Fragment { + let type_name = cattrs.name().serialize_name(); + let variant_name = variant.attrs.name().serialize_name(); + + if let Some(path) = variant.attrs.serialize_with() { + let ser = wrap_serialize_variant_with(params, path, variant); + return quote_expr! { + _serde::Serializer::serialize_newtype_variant( + __serializer, + #type_name, + #variant_index, + #variant_name, + #ser, + ) + }; + } + + match effective_style(variant) { + Style::Unit => { + quote_expr! { + _serde::Serializer::serialize_unit_variant( + __serializer, + #type_name, + #variant_index, + #variant_name, + ) + } + } + Style::Newtype => { + let field = &variant.fields[0]; + let mut field_expr = quote!(__field0); + if let Some(path) = field.attrs.serialize_with() { + field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); + } + + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::Serializer::serialize_newtype_variant); + quote_expr! { + #func( + __serializer, + #type_name, + #variant_index, + #variant_name, + #field_expr, + ) + } + } + Style::Tuple => serialize_tuple_variant( + TupleVariant::ExternallyTagged { + type_name, + variant_index, + variant_name, + }, + params, + &variant.fields, + ), + Style::Struct => serialize_struct_variant( + StructVariant::ExternallyTagged { + variant_index, + variant_name, + }, + params, + &variant.fields, + type_name, + ), + } +} + +fn serialize_internally_tagged_variant( + params: &Parameters, + variant: &Variant, + cattrs: &attr::Container, + tag: &str, +) -> Fragment { + let type_name = cattrs.name().serialize_name(); + let variant_name = variant.attrs.name().serialize_name(); + + let enum_ident_str = params.type_name(); + let variant_ident_str = variant.ident.to_string(); + + 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( + __serializer, + #enum_ident_str, + #variant_ident_str, + #tag, + #variant_name, + #ser, + ) + }; + } + + match effective_style(variant) { + Style::Unit => { + quote_block! { + 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) + } + } + Style::Newtype => { + let field = &variant.fields[0]; + let mut field_expr = quote!(__field0); + if let Some(path) = field.attrs.serialize_with() { + field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); + } + + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::#private::ser::serialize_tagged_newtype); + quote_expr! { + #func( + __serializer, + #enum_ident_str, + #variant_ident_str, + #tag, + #variant_name, + #field_expr, + ) + } + } + Style::Struct => serialize_struct_variant( + StructVariant::InternallyTagged { tag, variant_name }, + params, + &variant.fields, + type_name, + ), + Style::Tuple => unreachable!("checked in serde_derive_internals"), + } +} + +fn serialize_adjacently_tagged_variant( + params: &Parameters, + variant: &Variant, + cattrs: &attr::Container, + variant_index: u32, + tag: &str, + content: &str, +) -> Fragment { + 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); + quote_expr! { + _serde::Serialize::serialize(#ser, __serializer) + } + } else { + match effective_style(variant) { + Style::Unit => { + return quote_block! { + 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) + }; + } + Style::Newtype => { + let field = &variant.fields[0]; + let mut field_expr = quote!(__field0); + if let Some(path) = field.attrs.serialize_with() { + field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); + } + + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::ser::SerializeStruct::serialize_field); + return quote_block! { + 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) + }; + } + Style::Tuple => { + serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields) + } + Style::Struct => serialize_struct_variant( + StructVariant::Untagged, + params, + &variant.fields, + variant_name, + ), + } + }); + + let fields_ty = variant.fields.iter().map(|f| &f.ty); + let fields_ident: &[_] = &match variant.style { + Style::Unit => { + if variant.attrs.serialize_with().is_some() { + vec![] + } else { + unreachable!() + } + } + Style::Newtype => vec![Member::Named(field_i(0))], + Style::Tuple => (0..variant.fields.len()) + .map(|i| Member::Named(field_i(i))) + .collect(), + Style::Struct => variant.fields.iter().map(|f| f.member.clone()).collect(), + }; + + let (_, ty_generics, where_clause) = params.generics.split_for_impl(); + + let wrapper_generics = if fields_ident.is_empty() { + params.generics.clone() + } else { + bound::with_lifetime_bound(¶ms.generics, "'__a") + }; + let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl(); + + quote_block! { + #[doc(hidden)] + struct __AdjacentlyTagged #wrapper_generics #where_clause { + data: (#(&'__a #fields_ty,)*), + phantom: _serde::#private::PhantomData<#this_type #ty_generics>, + } + + #[automatically_derived] + impl #wrapper_impl_generics _serde::Serialize for __AdjacentlyTagged #wrapper_ty_generics #where_clause { + fn serialize<__S>(&self, __serializer: __S) -> _serde::#private::Result<__S::Ok, __S::Error> + where + __S: _serde::Serializer, + { + // Elements that have skip_serializing will be unused. + #[allow(unused_variables)] + let (#(#fields_ident,)*) = self.data; + #inner + } + } + + 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::#private::PhantomData::<#this_type #ty_generics>, + })?; + _serde::ser::SerializeStruct::end(__struct) + } +} + +fn serialize_untagged_variant( + params: &Parameters, + variant: &Variant, + cattrs: &attr::Container, +) -> Fragment { + if let Some(path) = variant.attrs.serialize_with() { + let ser = wrap_serialize_variant_with(params, path, variant); + return quote_expr! { + _serde::Serialize::serialize(#ser, __serializer) + }; + } + + match effective_style(variant) { + Style::Unit => { + quote_expr! { + _serde::Serializer::serialize_unit(__serializer) + } + } + Style::Newtype => { + let field = &variant.fields[0]; + let mut field_expr = quote!(__field0); + if let Some(path) = field.attrs.serialize_with() { + field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); + } + + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::Serialize::serialize); + quote_expr! { + #func(#field_expr, __serializer) + } + } + 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) + } + } +} + +enum TupleVariant<'a> { + ExternallyTagged { + type_name: &'a Name, + variant_index: u32, + variant_name: &'a Name, + }, + Untagged, +} + +fn serialize_tuple_variant( + context: TupleVariant, + params: &Parameters, + fields: &[Field], +) -> Fragment { + let tuple_trait = match context { + TupleVariant::ExternallyTagged { .. } => TupleTrait::SerializeTupleVariant, + TupleVariant::Untagged => TupleTrait::SerializeTuple, + }; + + let serialize_stmts = serialize_tuple_struct_visitor(fields, params, true, &tuple_trait); + + let mut serialized_fields = fields + .iter() + .enumerate() + .filter(|(_, field)| !field.attrs.skip_serializing()) + .peekable(); + + let let_mut = mut_if(serialized_fields.peek().is_some()); + + let len = serialized_fields + .map(|(i, field)| match field.attrs.skip_serializing_if() { + None => quote!(1), + Some(path) => { + let field_expr = field_i(i); + quote!(if #path(#field_expr) { 0 } else { 1 }) + } + }) + .fold(quote!(0), |sum, expr| quote!(#sum + #expr)); + + match context { + TupleVariant::ExternallyTagged { + type_name, + variant_index, + variant_name, + } => { + quote_block! { + let #let_mut __serde_state = _serde::Serializer::serialize_tuple_variant( + __serializer, + #type_name, + #variant_index, + #variant_name, + #len)?; + #(#serialize_stmts)* + _serde::ser::SerializeTupleVariant::end(__serde_state) + } + } + TupleVariant::Untagged => { + quote_block! { + let #let_mut __serde_state = _serde::Serializer::serialize_tuple( + __serializer, + #len)?; + #(#serialize_stmts)* + _serde::ser::SerializeTuple::end(__serde_state) + } + } + } +} + +enum StructVariant<'a> { + ExternallyTagged { + variant_index: u32, + variant_name: &'a Name, + }, + InternallyTagged { + tag: &'a str, + variant_name: &'a Name, + }, + Untagged, +} + +fn serialize_struct_variant( + context: StructVariant, + params: &Parameters, + fields: &[Field], + name: &Name, +) -> Fragment { + if fields.iter().any(|field| field.attrs.flatten()) { + return serialize_struct_variant_with_flatten(context, params, fields, name); + } + + let struct_trait = match context { + StructVariant::ExternallyTagged { .. } => StructTrait::SerializeStructVariant, + StructVariant::InternallyTagged { .. } | StructVariant::Untagged => { + StructTrait::SerializeStruct + } + }; + + let serialize_fields = serialize_struct_visitor(fields, params, true, &struct_trait); + + let mut serialized_fields = fields + .iter() + .filter(|&field| !field.attrs.skip_serializing()) + .peekable(); + + let let_mut = mut_if(serialized_fields.peek().is_some()); + + let len = serialized_fields + .map(|field| { + let member = &field.member; + + match field.attrs.skip_serializing_if() { + Some(path) => quote!(if #path(#member) { 0 } else { 1 }), + None => quote!(1), + } + }) + .fold(quote!(0), |sum, expr| quote!(#sum + #expr)); + + match context { + StructVariant::ExternallyTagged { + variant_index, + variant_name, + } => { + quote_block! { + 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 = _serde::Serializer::serialize_struct( + __serializer, + #name, + #len + 1, + )?; + _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 = _serde::Serializer::serialize_struct( + __serializer, + #name, + #len, + )?; + #(#serialize_fields)* + _serde::ser::SerializeStruct::end(__serde_state) + } + } + } +} + +fn serialize_struct_variant_with_flatten( + context: StructVariant, + params: &Parameters, + fields: &[Field], + name: &Name, +) -> Fragment { + let struct_trait = StructTrait::SerializeMap; + let serialize_fields = serialize_struct_visitor(fields, params, true, &struct_trait); + + let mut serialized_fields = fields + .iter() + .filter(|&field| !field.attrs.skip_serializing()) + .peekable(); + + let let_mut = mut_if(serialized_fields.peek().is_some()); + + match context { + StructVariant::ExternallyTagged { + variant_index, + variant_name, + } => { + let this_type = ¶ms.this_type; + let fields_ty = fields.iter().map(|f| &f.ty); + let members = &fields.iter().map(|f| &f.member).collect::>(); + + let (_, ty_generics, where_clause) = params.generics.split_for_impl(); + let wrapper_generics = bound::with_lifetime_bound(¶ms.generics, "'__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::#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::#private::Result<__S::Ok, __S::Error> + where + __S: _serde::Serializer, + { + let (#(#members,)*) = self.data; + let #let_mut __serde_state = _serde::Serializer::serialize_map( + __serializer, + _serde::#private::None)?; + #(#serialize_fields)* + _serde::ser::SerializeMap::end(__serde_state) + } + } + + _serde::Serializer::serialize_newtype_variant( + __serializer, + #name, + #variant_index, + #variant_name, + &__EnumFlatten { + data: (#(#members,)*), + phantom: _serde::#private::PhantomData::<#this_type #ty_generics>, + }) + } + } + StructVariant::InternallyTagged { tag, variant_name } => { + quote_block! { + let #let_mut __serde_state = _serde::Serializer::serialize_map( + __serializer, + _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 = _serde::Serializer::serialize_map( + __serializer, + _serde::#private::None)?; + #(#serialize_fields)* + _serde::ser::SerializeMap::end(__serde_state) + } + } + } +} + +fn serialize_tuple_struct_visitor( + fields: &[Field], + params: &Parameters, + is_enum: bool, + tuple_trait: &TupleTrait, +) -> Vec { + let mut dst_fields = Vec::new(); + + for (i, field) in fields.iter().enumerate() { + if field.attrs.skip_serializing() { + continue; + } + let mut field_expr = if is_enum { + let id = field_i(i); + quote!(#id) + } else { + get_member( + params, + field, + &Member::Unnamed(Index { + index: i as u32, + span: Span::call_site(), + }), + ) + }; + + let skip = field + .attrs + .skip_serializing_if() + .map(|path| quote!(#path(#field_expr))); + + if let Some(path) = field.attrs.serialize_with() { + field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); + } + + let span = field.original.span(); + let func = tuple_trait.serialize_element(span); + let ser = quote! { + #func(&mut __serde_state, #field_expr)?; + }; + + dst_fields.push(match skip { + None => ser, + Some(skip) => quote!(if !#skip { #ser }), + }); + } + dst_fields +} + +fn serialize_struct_visitor( + fields: &[Field], + params: &Parameters, + is_enum: bool, + struct_trait: &StructTrait, +) -> Vec { + let mut dst_fields = Vec::new(); + + for field in fields { + if field.attrs.skip_serializing() { + continue; + } + let member = &field.member; + + let mut field_expr = if is_enum { + quote!(#member) + } else { + get_member(params, field, member) + }; + + let key_expr = field.attrs.name().serialize_name(); + + let skip = field + .attrs + .skip_serializing_if() + .map(|path| quote!(#path(#field_expr))); + + if let Some(path) = field.attrs.serialize_with() { + field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); + } + + let span = field.original.span(); + let ser = if field.attrs.flatten() { + let func = quote_spanned!(span=> _serde::Serialize::serialize); + quote! { + #func(&#field_expr, _serde::#private::ser::FlatMapSerializer(&mut __serde_state))?; + } + } else { + let func = struct_trait.serialize_field(span); + quote! { + #func(&mut __serde_state, #key_expr, #field_expr)?; + } + }; + + dst_fields.push(match skip { + None => ser, + Some(skip) => { + if let Some(skip_func) = struct_trait.skip_field(span) { + quote! { + if !#skip { + #ser + } else { + #skip_func(&mut __serde_state, #key_expr)?; + } + } + } else { + quote! { + if !#skip { + #ser + } + } + } + } + }); + } + dst_fields +} + +fn wrap_serialize_field_with( + params: &Parameters, + field_ty: &syn::Type, + serialize_with: &syn::ExprPath, + field_expr: &TokenStream, +) -> TokenStream { + wrap_serialize_with(params, serialize_with, &[field_ty], &[quote!(#field_expr)]) +} + +fn wrap_serialize_variant_with( + params: &Parameters, + serialize_with: &syn::ExprPath, + variant: &Variant, +) -> TokenStream { + let field_tys: Vec<_> = variant.fields.iter().map(|field| field.ty).collect(); + let field_exprs: Vec<_> = variant + .fields + .iter() + .map(|field| { + let id = match &field.member { + Member::Named(ident) => ident.clone(), + Member::Unnamed(member) => field_i(member.index as usize), + }; + quote!(#id) + }) + .collect(); + wrap_serialize_with( + params, + serialize_with, + field_tys.as_slice(), + field_exprs.as_slice(), + ) +} + +fn wrap_serialize_with( + params: &Parameters, + serialize_with: &syn::ExprPath, + field_tys: &[&syn::Type], + field_exprs: &[TokenStream], +) -> TokenStream { + let this_type = ¶ms.this_type; + let (_, ty_generics, where_clause) = params.generics.split_for_impl(); + + let wrapper_generics = if field_exprs.is_empty() { + params.generics.clone() + } else { + bound::with_lifetime_bound(¶ms.generics, "'__a") + }; + let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl(); + + let field_access = (0..field_exprs.len()).map(|n| { + Member::Unnamed(Index { + index: n as u32, + span: Span::call_site(), + }) + }); + + 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::#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_var, #serializer_var: __S) -> _serde::#private::Result<__S::Ok, __S::Error> + where + __S: _serde::Serializer, + { + #wrapper_serialize + } + } + + __SerializeWith { + values: (#(#field_exprs, )*), + phantom: _serde::#private::PhantomData::<#this_type #ty_generics>, + } + }) +} + +// Serialization of an empty struct results in code like: +// +// 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. +fn mut_if(is_mut: bool) -> Option { + if is_mut { + Some(quote!(mut)) + } else { + None + } +} + +fn get_member(params: &Parameters, field: &Field, member: &Member) -> TokenStream { + let self_var = ¶ms.self_var; + match (params.is_remote, field.attrs.getter()) { + (false, None) => { + if params.is_packed { + quote!(&{#self_var.#member}) + } else { + quote!(&#self_var.#member) + } + } + (true, None) => { + let inner = if params.is_packed { + quote!(&{#self_var.#member}) + } else { + quote!(&#self_var.#member) + }; + let ty = field.ty; + quote!(_serde::#private::ser::constrain::<#ty>(#inner)) + } + (true, Some(getter)) => { + let ty = field.ty; + quote!(_serde::#private::ser::constrain::<#ty>(&#getter(#self_var))) + } + (false, Some(_)) => { + unreachable!("getter is only allowed for remote impls"); + } + } +} + +fn effective_style(variant: &Variant) -> Style { + match variant.style { + Style::Newtype if variant.fields[0].attrs.skip_serializing() => Style::Unit, + other => other, + } +} + +enum StructTrait { + SerializeMap, + SerializeStruct, + SerializeStructVariant, +} + +impl StructTrait { + fn serialize_field(&self, span: Span) -> TokenStream { + match *self { + StructTrait::SerializeMap => { + quote_spanned!(span=> _serde::ser::SerializeMap::serialize_entry) + } + StructTrait::SerializeStruct => { + quote_spanned!(span=> _serde::ser::SerializeStruct::serialize_field) + } + StructTrait::SerializeStructVariant => { + quote_spanned!(span=> _serde::ser::SerializeStructVariant::serialize_field) + } + } + } + + fn skip_field(&self, span: Span) -> Option { + match *self { + StructTrait::SerializeMap => None, + StructTrait::SerializeStruct => { + Some(quote_spanned!(span=> _serde::ser::SerializeStruct::skip_field)) + } + StructTrait::SerializeStructVariant => { + Some(quote_spanned!(span=> _serde::ser::SerializeStructVariant::skip_field)) + } + } + } +} + +enum TupleTrait { + SerializeTuple, + SerializeTupleStruct, + SerializeTupleVariant, +} + +impl TupleTrait { + fn serialize_element(&self, span: Span) -> TokenStream { + match *self { + TupleTrait::SerializeTuple => { + quote_spanned!(span=> _serde::ser::SerializeTuple::serialize_element) + } + TupleTrait::SerializeTupleStruct => { + quote_spanned!(span=> _serde::ser::SerializeTupleStruct::serialize_field) + } + TupleTrait::SerializeTupleVariant => { + quote_spanned!(span=> _serde::ser::SerializeTupleVariant::serialize_field) + } + } + } +} diff --git a/third_party/crates/serde_derive-1.0.229/src/this.rs b/third_party/crates/serde_derive-1.0.229/src/this.rs new file mode 100644 index 0000000..941cea4 --- /dev/null +++ b/third_party/crates/serde_derive-1.0.229/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/third_party/crates/serde_json-1.0.151/.cargo-checksum.json b/third_party/crates/serde_json-1.0.151/.cargo-checksum.json new file mode 100644 index 0000000..1999b3b --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/.cargo-checksum.json @@ -0,0 +1 @@ +{"$comment":"This file only protects against accidental modifications. It is not a security mechanism and does not protect against malicious changes.","files":{".cargo_vcs_info.json":"5bfedd83df665d1746f17958cdf29a1e62743049730e95ffc64912a984336eb5",".github/workflows/ci.yml":"c34145e098a9d1891a740ee7d805933b6c6869df675b651d1433e256ef724e74","CONTRIBUTING.md":"f5270cafba66223a7b51ffc0d286075a17bb7cd88762fc80d333d3102629f4d8","Cargo.lock":"3dc87740936e57d7be685ad20618aaa3ec8d931085e54381d196a2ec8faa919f","Cargo.toml":"00b920255c320a278bf25b962b491263a19d8c90e12e4a91c1d823db71eabb2f","Cargo.toml.orig":"ade7399c00ef7d8320fe5427e4c23f50686d6476584b2ea558a795cc9139f78a","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"10cb8c14d9d29f29a031329747b352fc149a689b449ee5a8abb43712695aed72","build.rs":"a681e754be844c7dbef957f5d2d00b01f37c5dca160ef1055a8d8f975697a881","src/de.rs":"4998d7e252eb513be85b298e287048b4fb283882e9ba7df905f572f07200f3f3","src/error.rs":"a13add05a63adf53d89e37effa03221d897a60486cfe360a5a958c0dd2a7e90d","src/io/core.rs":"60ba28f67a9acaecf8964b611efba416b13f9f2bae4befc329fdf0e037293802","src/io/mod.rs":"fd1ed5080495cab21117f6f7d3c2c9e3687cad0c69a0cd087b08a145a9e672da","src/iter.rs":"f832c469cd7999d26ba9b76baa69b257a212a7edb3dfdf9b1d1bb35e8da85fa9","src/lexical/algorithm.rs":"54d599033e5a182a3076a0ba23a3550bf8680c99399b0313166b3c42c85b35b9","src/lexical/bhcomp.rs":"26f39d52008225a6b377d7246d326940d44200e160a7b4652733e712e1a45a04","src/lexical/bignum.rs":"db688e8112389998d0f91906f6857e28f9b510a8b4065ad476c8e8be2f77becf","src/lexical/cached.rs":"0e127398691f8042c19cde209e7f4b0161f0f3150342430145929f711e6fdac8","src/lexical/cached_float80.rs":"0f8f74a22cb7d871322a9893bffd0255ca10bf9dffd13afb2462dd3d7f51805f","src/lexical/digit.rs":"9502805adbc3da059131d1fac0a802e17065b36cd7472606b3af24e3241d5cb8","src/lexical/errors.rs":"3d9f6de6245533bcb101dfd718cfed61d59dc293f6768cedae28aa13ace164f5","src/lexical/exponent.rs":"51f19443008e8884b15c7d5d4b1f1cfbd5673a9d1da02f1af39fcf20e315f01f","src/lexical/float.rs":"fe356213c92a049f4bef2f58bc0e3a26866ca06b8c1d74d0f961c5b883852cad","src/lexical/large_powers.rs":"18d697b846b44ecb61bfaaa3b881e0696f9b7bb6be582623e9d3a8a176a48d2f","src/lexical/large_powers32.rs":"c70b57a727960beec258758a4d4a1050f8eaf3b4e60027c663a2bfb0246e0153","src/lexical/large_powers64.rs":"e7af83ce3159b5fc4669fc5a231e767d8af21bacaece52a0a48951198965b197","src/lexical/math.rs":"c5452d3ef9cc9ebd74a99f22dcabf74f4f062bbaeade46301260b79e4662d5df","src/lexical/mod.rs":"ace2ccea2cd541f019a84b9eeb3b9ecd88daf6bccbe9edf0eac00b62704f47c4","src/lexical/num.rs":"2d06111d28616221995f7b4d4f13625b8d902884921268b0e02e544f871a5339","src/lexical/parse.rs":"c2bfac4c70a19938ced61e991f4ec606764887cf12bac1a0978b5b5318a56aac","src/lexical/rounding.rs":"4762af3612880b17468ff2a1bb800c8e99f08330ae439699dd53d8dc5463ad13","src/lexical/shift.rs":"bc1ed053dd63d45ac9c35302f18de9f00d94027f28af4ab749c9248439de832a","src/lexical/small_powers.rs":"73c56b7b83310c6fefa898fb94771c65bdc251c1579ab105151da43935ea02be","src/lib.rs":"34a1ddabdcf4759d9a6c64a2e851372546d635d1a578ad902d962fef3c45de58","src/macros.rs":"94dda91c847e819a95e64d655eb066dfa44ed69712064016c3fe862c34ef92e6","src/map.rs":"b5a2fd1ee865e6cfd83ef2da0a2e1057f892465ac7ede8a78a11354a60526f33","src/number.rs":"70b83c36286f6c58123f544f27db2b54a1135f928fe33b08b521b2997773f862","src/raw.rs":"0e6ae2ade492a3c5c090dfaf31f03ff4e54123a5a47b59def5f1b3dcc035a2e3","src/read.rs":"17a2efe49e5a6937c8d7d4a5c0b9eac84453de0f86bf8e7ee421387e82341bb3","src/ser.rs":"f2b8cc0b97e30c49dbc58698fa22c14a7d56ea616cdb57b067835a59af49a75f","src/value/de.rs":"ceda1bf415aafde89caa83bf275811b70d393717d4e1038e0c61822d2da02993","src/value/from.rs":"ae4b5f93b27e578fa40e3a8d25d0df2032fe40b680cddb15963e47cbd56db613","src/value/index.rs":"f1404ed12e795a5553da4bdf72835c441a5e0cc0f6e794fee875eaa887d65319","src/value/mod.rs":"6331d59ea362a74b6cd3d302d08114a63a73a384ff56fef737de29edea2f8d91","src/value/partial_eq.rs":"c565f7886d3bdf5dd39b8c99acca17091c251f15b3c257addf5d02f414fd0571","src/value/ser.rs":"11f2b7daa1eba826d4086d5497f73729478dd7647bff77deccde5e47b0f126f2","tests/compiletest.rs":"4e381aa8ca3eabb7ac14d1e0c3700b3223e47640547a6988cfa13ad68255f60f","tests/debug.rs":"7d54721bbaea19c362e7c39046745ffb3c774d6af0b3af5643e4bdfbf0fa1011","tests/lexical.rs":"a863468815c2c1f1415b30eef42971604d860e6128e66c39d965322fbc567240","tests/lexical/algorithm.rs":"da378df9ee24bfa033968d5c94e91b58e52c39bf6c825dec51c3eb7250cc5874","tests/lexical/exponent.rs":"dc8fa8d05e561ff256f8b09385291768c7f45e5ad6cb878ef9194757aa014386","tests/lexical/float.rs":"0440f2d85c993bcccd925096d7f4136bf624ffd66b3c7ee565d158390685eb11","tests/lexical/math.rs":"4142ef090f563df1f6b14c9a4e6d4723535fa816dca3febc94b3423240e9db20","tests/lexical/num.rs":"e0bdc3b4facd579e9cfdf87c8bae107ed227c63cf9ef920fd85e9febb985c693","tests/lexical/parse.rs":"a11f09bb003a3a024548008cf78bf76526ed71b00077d1989f45eb8cebc93b9c","tests/lexical/rounding.rs":"6c56e39ba534616c1b2146e8efa6eb57aed322e683bf23183cd32a61fae6447e","tests/macros/mod.rs":"93aa1d54af20bc2c55b6ae8db73c1414cda2626eb9fa7bd57b9d613a3c6e6a19","tests/map.rs":"232a980d98b0ceac022ad34d25b0a0fc613389784222a45da4f5650a9414a847","tests/regression.rs":"2f2aa349a0dcc399e246e08e2fbae8fb349831b461169014605538fed8d65622","tests/regression/issue1004.rs":"38d7e3b6c515b881078ebd21ca8063d2ca105cd319695d29538f879e37f091b5","tests/regression/issue520.rs":"f95b362e45c57b431720c48eb47f7ddddf4078195d6859df523dc32950ce980a","tests/regression/issue795.rs":"37ff26744b1f950dd212565c6e3f276268882f7724cc589ac8b21ca8bd608413","tests/regression/issue845.rs":"10d2895cd1412cb6630f0a59db367f79ee672edb501151c7581e9921b5a84b92","tests/regression/issue953.rs":"b2cddc761f5ca6639900c173765a8a5868528a896924e5e925db2696469208f7","tests/regression/issue979.rs":"06851e827c7bcb069de03d878f56710786fad55d9d9ad1149a8e9629a5ac3062","tests/stream.rs":"794b672b52eb8f1696b32b8dd125a660fc19b83fcfef5390896b02149b5f0a9b","tests/test.rs":"bfb44a3ff847299e7ae7b1801a47c273c7ae897f746d2bf2ac0a8d543143c494","tests/ui/missing_colon.rs":"d07e0c34d98eb43465f0a0310f2c0b5d5b0d26d243b352a1c6bbe6ad3b27eda9","tests/ui/missing_colon.stderr":"a543cf9931a6224ba74f4592ea551f19438752c09427c649cd0211d363e88e75","tests/ui/missing_comma.rs":"b8a9662f99c3e6dd2b6417892c37640578ce91d3a8365bf10c1f686a3227aa87","tests/ui/missing_comma.stderr":"05de5cd378a91be9631b0491c326d45e180bb76ea834052e214ec9e1e14b1aaf","tests/ui/missing_value.rs":"bca25d67127fb88e7c191c7b03af5a4ce8a9abb630f3d2e6a6c1e77e213dc9a4","tests/ui/missing_value.stderr":"a03be58cfa3d80cf1bd967bc8473933e87226db69c7967710084b13ca43bccdc","tests/ui/not_found.rs":"d0a7adb309879ff65aee115b52cc33d36f4bad353cf97c4effc34a6128c2bee3","tests/ui/not_found.stderr":"359b751c0c21fab6d460daef4d5f73a265f7769c9b578f98ea3cb6cbf2387643","tests/ui/parse_expr.rs":"32e6d51f528db3d1ab0ed1e24765b865be393565c26f77413c5aa39d601ac563","tests/ui/parse_expr.stderr":"1daa690bd744a9559ed51019d88d0b4a1ffaea42f74a24d48688a7029a87e013","tests/ui/parse_key.rs":"18829b2af320d5cf8a0a5cd3aaf84c7e92cc874651c30e45a3acafb76c2d8b93","tests/ui/parse_key.stderr":"20cf0d2898749f3c36780fc065f5049ee809e74cb6f0ef776f43f45e01596ee3","tests/ui/unexpected_after_array_element.rs":"a343fc3104431720bdfcf330bcc3cfcd98c8dec3e951133b495242478b0b7eb3","tests/ui/unexpected_after_array_element.stderr":"9ec755bf0cd5a3e9dc9c4027ae03fbb3f33987b1ab61aa76cd88d4148b766487","tests/ui/unexpected_after_map_entry.rs":"6e3bd2def435ca610e346bbc75cdbaf61963eb2ef1885bb5f76781ba1fac37ef","tests/ui/unexpected_after_map_entry.stderr":"a39bd7a3ae4d20a24d311392022caa48f59697967995c2bb2cf5c1bc5c9c21d0","tests/ui/unexpected_colon.rs":"a313cff3fed4be4c33f1eda5d0c5c98147fb835a56d36470d9f367352c1d61ef","tests/ui/unexpected_colon.stderr":"80afe490b9615fd2d769b80602a7f64c5804fda666356fbcebd7658107d89c70","tests/ui/unexpected_comma.rs":"55a8b684bde1ce905837cce719fd457d8898b61cebc27e5b420d05cb6be97256","tests/ui/unexpected_comma.stderr":"0b6488f2e63c4cd7debc38696b76b325ef230fa97c33bf17476573993883a448"},"package":"c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"} \ No newline at end of file diff --git a/third_party/crates/serde_json-1.0.151/.cargo_vcs_info.json b/third_party/crates/serde_json-1.0.151/.cargo_vcs_info.json new file mode 100644 index 0000000..fad5602 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "de8500740cdcabffb9734f503e4889def823cf10" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/third_party/crates/serde_json-1.0.151/.github/workflows/ci.yml b/third_party/crates/serde_json-1.0.151/.github/workflows/ci.yml new file mode 100644 index 0000000..d9ce7ff --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/.github/workflows/ci.yml @@ -0,0 +1,157 @@ +name: CI + +on: + push: + pull_request: + workflow_dispatch: + schedule: [cron: "40 1 * * *"] + +permissions: + contents: read + +env: + RUSTFLAGS: -Dwarnings + +jobs: + test: + 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@v7 + - uses: dtolnay/rust-toolchain@nightly + - run: cargo test + - run: cargo test --features preserve_order --tests -- --skip ui --exact + - run: cargo test --features float_roundtrip --tests -- --skip ui --exact + - run: cargo test --features arbitrary_precision --tests -- --skip ui --exact + - run: cargo test --features float_roundtrip,arbitrary_precision --tests -- --skip ui --exact + - run: cargo test --features raw_value --tests -- --skip ui --exact + - run: cargo test --features unbounded_depth --tests -- --skip ui --exact + - uses: actions/upload-artifact@v7 + if: matrix.os == 'ubuntu' && always() + with: + name: Cargo.lock + path: Cargo.lock + continue-on-error: true + + build: + name: Rust ${{matrix.rust}} ${{matrix.os == 'windows' && '(windows)' || ''}} + runs-on: ${{matrix.os}}-latest + strategy: + fail-fast: false + matrix: + rust: [beta, 1.85.0, 1.71.0] + os: [ubuntu] + include: + - rust: stable + os: ubuntu + target: aarch64-unknown-none + - rust: stable + os: windows + timeout-minutes: 45 + steps: + - uses: actions/checkout@v7 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{matrix.rust}} + targets: ${{matrix.target}} + - run: cargo check --manifest-path tests/crate/Cargo.toml + - run: cargo check --manifest-path tests/crate/Cargo.toml --features float_roundtrip + - run: cargo check --manifest-path tests/crate/Cargo.toml --features arbitrary_precision + - run: cargo check --manifest-path tests/crate/Cargo.toml --features raw_value + - run: cargo check --manifest-path tests/crate/Cargo.toml --features unbounded_depth + - run: cargo check --manifest-path tests/crate/Cargo.toml --no-default-features --features alloc + - run: cargo check --manifest-path tests/crate/Cargo.toml --no-default-features --features alloc,arbitrary_precision + - run: cargo check --manifest-path tests/crate/Cargo.toml --no-default-features --features alloc,raw_value + - run: cargo check --manifest-path tests/crate/Cargo.toml --features serde_json/preserve_order + if: matrix.rust != '1.71.0' + - run: cargo check --manifest-path tests/crate/Cargo.toml --no-default-features --features alloc,serde_json/preserve_order + if: matrix.rust != '1.71.0' + - name: Build without std + run: cargo check --manifest-path tests/crate/Cargo.toml --target + ${{matrix.target}} --no-default-features --features alloc + if: matrix.target + + minimal: + name: Minimal versions + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@v7 + - uses: dtolnay/rust-toolchain@nightly + - run: cargo generate-lockfile -Z minimal-versions + - run: cargo check --locked + + miri: + name: Miri (${{matrix.name}}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - name: 64-bit little endian + target: x86_64-unknown-linux-gnu + - name: 64-bit big endian + target: powerpc64-unknown-linux-gnu + - name: 32-bit little endian + target: i686-unknown-linux-gnu + - name: 32-bit big endian + target: mips-unknown-linux-gnu + env: + MIRIFLAGS: -Zmiri-strict-provenance + timeout-minutes: 45 + steps: + - uses: actions/checkout@v7 + - uses: dtolnay/rust-toolchain@miri + - run: cargo miri setup + - run: cargo miri test --target ${{matrix.target}} + - run: cargo miri test --target ${{matrix.target}} --features preserve_order,float_roundtrip,arbitrary_precision,raw_value + + clippy: + name: Clippy + runs-on: ubuntu-latest + if: github.event_name != 'pull_request' + timeout-minutes: 45 + steps: + - uses: actions/checkout@v7 + - uses: dtolnay/rust-toolchain@clippy + - run: cargo clippy --tests -- -Dclippy::all -Dclippy::pedantic + - run: cargo clippy --all-features --tests -- -Dclippy::all -Dclippy::pedantic + + doc: + name: Documentation + runs-on: ubuntu-latest + timeout-minutes: 45 + env: + RUSTDOCFLAGS: -Dwarnings + steps: + - uses: actions/checkout@v7 + - uses: dtolnay/rust-toolchain@nightly + - uses: dtolnay/install@cargo-docs-rs + - run: cargo docs-rs + + fuzz: + name: Fuzz + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@v7 + - uses: dtolnay/rust-toolchain@nightly + - uses: dtolnay/install@cargo-fuzz + - run: cargo fuzz check + + outdated: + name: Outdated + runs-on: ubuntu-latest + if: github.event_name != 'pull_request' + timeout-minutes: 45 + steps: + - uses: actions/checkout@v7 + - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/install@cargo-outdated + - run: cargo outdated --exit-code 1 + - run: cargo outdated --manifest-path fuzz/Cargo.toml --exit-code 1 diff --git a/third_party/crates/serde_json-1.0.151/BUILD.bazel b/third_party/crates/serde_json-1.0.151/BUILD.bazel new file mode 100644 index 0000000..ab5a7cb --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/BUILD.bazel @@ -0,0 +1,191 @@ +############################################################################### +# @generated +# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To +# regenerate this file, run the following: +# +# bazel run @@//third_party:vendor_crates +############################################################################### + +load( + "@rules_rust//cargo:defs.bzl", + "cargo_build_script", + "cargo_toml_env_vars", +) +load("@rules_rust//rust:defs.bzl", "rust_library") + +package(default_visibility = ["//visibility:public"]) + +cargo_toml_env_vars( + name = "cargo_toml_env_vars", + src = "Cargo.toml", +) + +rust_library( + name = "serde_json", + srcs = glob( + include = ["**/*.rs"], + allow_empty = False, + ), + compile_data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + crate_features = [ + "default", + "std", + ], + crate_root = "src/lib.rs", + edition = "2021", + rustc_env_files = [ + ":cargo_toml_env_vars", + ], + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=serde_json", + "manual", + "noclippy", + "norustfmt", + ], + target_compatible_with = select({ + "@rules_rust//rust/platform:aarch64-apple-darwin": [], + "@rules_rust//rust/platform:aarch64-apple-ios": [], + "@rules_rust//rust/platform:aarch64-apple-ios-macabi": [], + "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], + "@rules_rust//rust/platform:aarch64-linux-android": [], + "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], + "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], + "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-none": [], + "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], + "@rules_rust//rust/platform:aarch64-unknown-uefi": [], + "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], + "@rules_rust//rust/platform:armv7-linux-androideabi": [], + "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:i686-apple-darwin": [], + "@rules_rust//rust/platform:i686-linux-android": [], + "@rules_rust//rust/platform:i686-pc-windows-msvc": [], + "@rules_rust//rust/platform:i686-unknown-freebsd": [], + "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], + "@rules_rust//rust/platform:loongarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:mips-unknown-linux-gnu": [], + "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv32imac-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], + "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-netbsd": [], + "@rules_rust//rust/platform:sparc64-unknown-openbsd": [], + "@rules_rust//rust/platform:thumbv6m-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabihf": [], + "@rules_rust//rust/platform:thumbv7m-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabihf": [], + "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], + "@rules_rust//rust/platform:wasm32-unknown-unknown": [], + "@rules_rust//rust/platform:wasm32-wasip1": [], + "@rules_rust//rust/platform:wasm32-wasip1-threads": [], + "@rules_rust//rust/platform:wasm32-wasip2": [], + "@rules_rust//rust/platform:x86_64-apple-darwin": [], + "@rules_rust//rust/platform:x86_64-apple-ios": [], + "@rules_rust//rust/platform:x86_64-apple-ios-macabi": [], + "@rules_rust//rust/platform:x86_64-linux-android": [], + "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], + "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], + "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], + "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-none": [], + "@rules_rust//rust/platform:x86_64-unknown-uefi": [], + "//conditions:default": ["@platforms//:incompatible"], + }), + version = "1.0.151", + deps = [ + ":build_script_build", + "//third_party/crates/itoa-1.0.18:itoa", + "//third_party/crates/memchr-2.8.3:memchr", + "//third_party/crates/serde_core-1.0.229:serde_core", + "//third_party/crates/zmij-1.0.23:zmij", + ], +) + +cargo_build_script( + name = "_bs", + srcs = glob( + include = ["**/*.rs"], + allow_empty = False, + ), + build_script_env_files = [ + ":cargo_toml_env_vars", + ], + compile_data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + "**/*.rs", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + crate_features = [ + "default", + "std", + ], + crate_name = "build_script_build", + crate_root = "build.rs", + data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + edition = "2021", + emit_warnings = False, + pkg_name = "serde_json", + rustc_env_files = [ + ":cargo_toml_env_vars", + ], + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=serde_json", + "manual", + "noclippy", + "norustfmt", + ], + version = "1.0.151", + visibility = ["//visibility:private"], +) + +alias( + name = "build_script_build", + actual = ":_bs", + tags = ["manual"], +) diff --git a/third_party/crates/serde_json-1.0.151/CONTRIBUTING.md b/third_party/crates/serde_json-1.0.151/CONTRIBUTING.md new file mode 100644 index 0000000..26e1578 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/CONTRIBUTING.md @@ -0,0 +1,46 @@ +# Contributing to Serde + +Serde welcomes contribution from everyone in the form of suggestions, bug +reports, pull requests, and feedback. This document gives some guidance if you +are thinking of helping us. + +## Submitting bug reports and feature requests + +Serde development is spread across lots of repositories. In general, prefer to +open issues against the main [serde-rs/serde] repository unless the topic is +clearly specific to JSON. + +[serde-rs/serde]: https://github.com/serde-rs/serde + +When reporting a bug or asking for help, please include enough details so that +the people helping you can reproduce the behavior you are seeing. For some tips +on how to approach this, read about how to produce a [Minimal, Complete, and +Verifiable example]. + +[Minimal, Complete, and Verifiable example]: https://stackoverflow.com/help/mcve + +When making a feature request, please make it clear what problem you intend to +solve with the feature, any ideas for how Serde could support solving that +problem, any possible alternatives, and any disadvantages. + +## Running the test suite + +We encourage you to check that the test suite passes locally before submitting a +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. + +The test suite requires a nightly compiler. + +```sh +# Run the full test suite, including doc test and compile-tests +cargo test +``` + +## Conduct + +In all Serde-related forums, we follow the [Rust Code of Conduct]. For +escalation or moderation issues please contact Erick (erick.tryzelaar@gmail.com) +instead of the Rust moderation team. + +[Rust Code of Conduct]: https://www.rust-lang.org/policies/code-of-conduct diff --git a/third_party/crates/serde_json-1.0.151/Cargo.lock b/third_party/crates/serde_json-1.0.151/Cargo.lock new file mode 100644 index 0000000..63a47b3 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/Cargo.lock @@ -0,0 +1,415 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ar_archive_writer" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4087686b4b0a3427190bae57a1d9a478dbb2d40c5dc1bd6e2b6d797913bdd348" +dependencies = [ + "object", +] + +[[package]] +name = "automod" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a273e731a7fb8c2268fd2932c9e9a3469f4fd171d85d070d2687190229653bd3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "cc" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89588d05638b5b4594a3348a2d6c20277e43a7f5c5202b05cc56888475a47b8" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "dissimilar" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aeda16ab4059c5fd2a83f2b9c9e9c981327b18aa8e3b313f7e6563799d4f093e" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "indoc" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +dependencies = [ + "rustversion", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "psm" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645dbe486e346d9b5de3ef16ede18c26e6c70ad97418f4874b8b1889d6e761ea" +dependencies = [ + "ar_archive_writer", + "cc", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ref-cast" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216e8f773d7923bcba9ceb86a86c93cabb3903a11872fc3f138c49630e50b96d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9283685feec7d69af75fb0e858d5e7378f33fe4fc699383b2916ab9273e03c" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.2", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.2", +] + +[[package]] +name = "serde_json" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +dependencies = [ + "automod", + "indexmap", + "indoc", + "itoa", + "memchr", + "ref-cast", + "rustversion", + "serde", + "serde_bytes", + "serde_core", + "serde_derive", + "serde_stacker", + "trybuild", + "zmij", +] + +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_stacker" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4936375d50c4be7eff22293a9344f8e46f323ed2b3c243e52f89138d9bb0f4a" +dependencies = [ + "serde", + "serde_core", + "stacker", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "stacker" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "640c8cdd92b6b12f5bcb1803ca3bbf5ab96e5e6b6b96b9ab77dabe9e880b3190" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a207d6d6a2b7fc470b80443726053f18a2481b7e1eee970597051596567987a3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "target-triple" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3a6bfce3d99adfa72d24750a61f782f3036a81e7f86d8841ee1326deaebd171" + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "toml" +version = "1.1.3+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53c96ecdfa941c8fc4fcaed14f99ada8ebed502eef533015095a07e3301d4c3c" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" + +[[package]] +name = "trybuild" +version = "1.0.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06649c6f63d86604ba0c8950d5a1829fc9a17afd70fc6629f481d75b6a624c78" +dependencies = [ + "dissimilar", + "glob", + "serde", + "serde_derive", + "serde_json 1.0.150", + "target-triple", + "termcolor", + "toml", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "winnow" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/third_party/crates/serde_json-1.0.151/Cargo.toml b/third_party/crates/serde_json-1.0.151/Cargo.toml new file mode 100644 index 0000000..47480b4 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/Cargo.toml @@ -0,0 +1,162 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.71" +name = "serde_json" +version = "1.0.151" +authors = [ + "Erick Tryzelaar ", + "David Tolnay ", +] +build = "build.rs" +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "A JSON serialization file format" +documentation = "https://docs.rs/serde_json" +readme = "README.md" +keywords = [ + "json", + "serde", + "serialization", +] +categories = [ + "encoding", + "parser-implementations", + "no-std", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/serde-rs/json" + +[package.metadata.docs.rs] +features = [ + "preserve_order", + "raw_value", + "unbounded_depth", +] +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", +] + +[package.metadata.playground] +features = [ + "float_roundtrip", + "raw_value", + "unbounded_depth", +] + +[features] +alloc = ["serde_core/alloc"] +arbitrary_precision = [] +default = ["std"] +float_roundtrip = [] +preserve_order = [ + "indexmap", + "std", +] +raw_value = [] +std = [ + "memchr/std", + "serde_core/std", +] +unbounded_depth = [] + +[lib] +name = "serde_json" +path = "src/lib.rs" + +[[test]] +name = "compiletest" +path = "tests/compiletest.rs" + +[[test]] +name = "debug" +path = "tests/debug.rs" + +[[test]] +name = "lexical" +path = "tests/lexical.rs" + +[[test]] +name = "map" +path = "tests/map.rs" + +[[test]] +name = "regression" +path = "tests/regression.rs" + +[[test]] +name = "stream" +path = "tests/stream.rs" + +[[test]] +name = "test" +path = "tests/test.rs" + +[dependencies.indexmap] +version = "2.2.3" +optional = true + +[dependencies.itoa] +version = "1.0" + +[dependencies.memchr] +version = "2" +default-features = false + +[dependencies.serde_core] +version = "1.0.220" +default-features = false + +[dependencies.zmij] +version = "1.0" + +[dev-dependencies.automod] +version = "1.0.11" + +[dev-dependencies.indoc] +version = "2.0.2" + +[dev-dependencies.ref-cast] +version = "1.0.18" + +[dev-dependencies.rustversion] +version = "1.0.13" + +[dev-dependencies.serde] +version = "1.0.194" +features = ["derive"] + +[dev-dependencies.serde_bytes] +version = "0.11.10" + +[dev-dependencies.serde_derive] +version = "1.0.166" + +[dev-dependencies.serde_stacker] +version = "0.1.8" + +[dev-dependencies.trybuild] +version = "1.0.108" +features = ["diff"] + +[target."cfg(any())".dependencies.serde] +version = "1.0.220" +default-features = false diff --git a/third_party/crates/serde_json-1.0.151/Cargo.toml.orig b/third_party/crates/serde_json-1.0.151/Cargo.toml.orig new file mode 100644 index 0000000..888735e --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/Cargo.toml.orig @@ -0,0 +1,95 @@ +[package] +name = "serde_json" +version = "1.0.151" +authors = ["Erick Tryzelaar ", "David Tolnay "] +categories = ["encoding", "parser-implementations", "no-std"] +description = "A JSON serialization file format" +documentation = "https://docs.rs/serde_json" +edition = "2021" +keywords = ["json", "serde", "serialization"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/serde-rs/json" +rust-version = "1.71" + +[dependencies] +indexmap = { version = "2.2.3", optional = true } +itoa = "1.0" +memchr = { version = "2", default-features = false } +serde_core = { version = "1.0.220", default-features = false } +zmij = "1.0" + +[target.'cfg(any())'.dependencies] +serde = { version = "1.0.220", default-features = false } + +[dev-dependencies] +automod = "1.0.11" +indoc = "2.0.2" +ref-cast = "1.0.18" +rustversion = "1.0.13" +serde = { version = "1.0.194", features = ["derive"] } +serde_bytes = "0.11.10" +serde_derive = "1.0.166" +serde_stacker = "0.1.8" +trybuild = { version = "1.0.108", features = ["diff"] } + +[package.metadata.docs.rs] +features = ["preserve_order", "raw_value", "unbounded_depth"] +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", +] + +[package.metadata.playground] +features = ["float_roundtrip", "raw_value", "unbounded_depth"] + + +### FEATURES ################################################################# + +[features] +default = ["std"] + +std = ["memchr/std", "serde_core/std"] + +# Provide integration for heap-allocated collections without depending on the +# rest of the Rust standard library. +# NOTE: Disabling both `std` *and* `alloc` features is not supported yet. +alloc = ["serde_core/alloc"] + +# Make serde_json::Map use a representation which maintains insertion order. +# This allows data to be read into a Value and written back to a JSON string +# while preserving the order of map keys in the input. +preserve_order = ["indexmap", "std"] + +# Use sufficient precision when parsing fixed precision floats from JSON to +# ensure that they maintain accuracy when round-tripped through JSON. This comes +# at an approximately 2x performance cost for parsing floats compared to the +# default best-effort precision. +# +# Unlike arbitrary_precision, this feature makes f64 -> JSON -> f64 produce +# output identical to the input. +float_roundtrip = [] + +# Use an arbitrary precision number representation for serde_json::Number. This +# allows JSON numbers of arbitrary size/precision to be read into a Number and +# written back to a JSON string without loss of precision. +# +# Unlike float_roundtrip, this feature makes JSON -> serde_json::Number -> JSON +# produce output identical to the input. +arbitrary_precision = [] + +# Provide a RawValue type that can hold unprocessed JSON during deserialization. +raw_value = [] + +# Provide a method disable_recursion_limit to parse arbitrarily deep JSON +# structures without any consideration for overflowing the stack. When using +# this feature, you will want to provide some other way to protect against stack +# overflows, such as by wrapping your Deserializer in the dynamically growing +# stack adapter provided by the serde_stacker crate. Additionally you will need +# to be careful around other recursive operations on the parsed result which may +# overflow the stack after deserialization has completed, including, but not +# limited to, Display and Debug and Drop impls. +unbounded_depth = [] diff --git a/third_party/crates/serde_json-1.0.151/LICENSE-APACHE b/third_party/crates/serde_json-1.0.151/LICENSE-APACHE new file mode 100644 index 0000000..1b5ec8b --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/third_party/crates/serde_json-1.0.151/LICENSE-MIT b/third_party/crates/serde_json-1.0.151/LICENSE-MIT new file mode 100644 index 0000000..31aa793 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/crates/serde_json-1.0.151/README.md b/third_party/crates/serde_json-1.0.151/README.md new file mode 100644 index 0000000..e19dc62 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/README.md @@ -0,0 +1,388 @@ +# Serde JSON   [![Build Status]][actions] [![Latest Version]][crates.io] + +[Build Status]: https://img.shields.io/github/actions/workflow/status/serde-rs/json/ci.yml?branch=master +[actions]: https://github.com/serde-rs/json/actions?query=branch%3Amaster +[Latest Version]: https://img.shields.io/crates/v/serde_json.svg +[crates.io]: https://crates.io/crates/serde\_json + +**Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.** + +--- + +```toml +[dependencies] +serde_json = "1.0" +``` + +You may be looking for: + +- [JSON API documentation](https://docs.rs/serde_json) +- [Serde API documentation](https://docs.rs/serde) +- [Detailed documentation about Serde](https://serde.rs/) +- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/derive.html) +- [Release notes](https://github.com/serde-rs/json/releases) + +JSON is a ubiquitous open-standard format that uses human-readable text to +transmit data objects consisting of key-value pairs. + +```json +{ + "name": "John Doe", + "age": 43, + "address": { + "street": "10 Downing Street", + "city": "London" + }, + "phones": [ + "+44 1234567", + "+44 2345678" + ] +} +``` + +There are three common ways that you might find yourself needing to work with +JSON data in Rust. + + - **As text data.** An unprocessed string of JSON data that you receive on an + HTTP endpoint, read from a file, or prepare to send to a remote server. + - **As an untyped or loosely typed representation.** Maybe you want to check + that some JSON data is valid before passing it on, but without knowing the + structure of what it contains. Or you want to do very basic manipulations + like insert a key in a particular spot. + - **As a strongly typed Rust data structure.** When you expect all or most of + your data to conform to a particular structure and want to get real work done + without JSON's loosey-goosey nature tripping you up. + +Serde JSON provides efficient, flexible, safe ways of converting data between +each of these representations. + +## Operating on untyped JSON values + +Any valid JSON data can be manipulated in the following recursive enum +representation. This data structure is [`serde_json::Value`][value]. + +```rust +enum Value { + Null, + Bool(bool), + Number(Number), + String(String), + Array(Vec), + Object(Map), +} +``` + +A string of JSON data can be parsed into a `serde_json::Value` by the +[`serde_json::from_str`][from_str] function. There is also +[`from_slice`][from_slice] for parsing from a byte slice `&[u8]` and +[`from_reader`][from_reader] for parsing from any `io::Read` like a File or a +TCP stream. + +
+ + + +
+ +```rust +use serde_json::{Result, Value}; + +fn untyped_example() -> Result<()> { + // Some JSON input data as a &str. Maybe this comes from the user. + let data = r#" + { + "name": "John Doe", + "age": 43, + "phones": [ + "+44 1234567", + "+44 2345678" + ] + }"#; + + // Parse the string of data into serde_json::Value. + let v: Value = serde_json::from_str(data)?; + + // Access parts of the data by indexing with square brackets. + println!("Please call {} at the number {}", v["name"], v["phones"][0]); + + Ok(()) +} +``` + +The result of square bracket indexing like `v["name"]` is a borrow of the data +at that index, so the type is `&Value`. A JSON map can be indexed with string +keys, while a JSON array can be indexed with integer keys. If the type of the +data is not right for the type with which it is being indexed, or if a map does +not contain the key being indexed, or if the index into a vector is out of +bounds, the returned element is `Value::Null`. + +When a `Value` is printed, it is printed as a JSON string. So in the code above, +the output looks like `Please call "John Doe" at the number "+44 1234567"`. The +quotation marks appear because `v["name"]` is a `&Value` containing a JSON +string and its JSON representation is `"John Doe"`. Printing as a plain string +without quotation marks involves converting from a JSON string to a Rust string +with [`as_str()`] or avoiding the use of `Value` as described in the following +section. + +[`as_str()`]: https://docs.rs/serde_json/1/serde_json/enum.Value.html#method.as_str + +The `Value` representation is sufficient for very basic tasks but can be tedious +to work with for anything more significant. Error handling is verbose to +implement correctly, for example imagine trying to detect the presence of +unrecognized fields in the input data. The compiler is powerless to help you +when you make a mistake, for example imagine typoing `v["name"]` as `v["nmae"]` +in one of the dozens of places it is used in your code. + +## Parsing JSON as strongly typed data structures + +Serde provides a powerful way of mapping JSON data into Rust data structures +largely automatically. + +
+ + + +
+ +```rust +use serde::{Deserialize, Serialize}; +use serde_json::Result; + +#[derive(Serialize, Deserialize)] +struct Person { + name: String, + age: u8, + phones: Vec, +} + +fn typed_example() -> Result<()> { + // Some JSON input data as a &str. Maybe this comes from the user. + let data = r#" + { + "name": "John Doe", + "age": 43, + "phones": [ + "+44 1234567", + "+44 2345678" + ] + }"#; + + // Parse the string of data into a Person object. This is exactly the + // same function as the one that produced serde_json::Value above, but + // now we are asking it for a Person as output. + let p: Person = serde_json::from_str(data)?; + + // Do things just like with any other Rust data structure. + println!("Please call {} at the number {}", p.name, p.phones[0]); + + Ok(()) +} +``` + +This is the same `serde_json::from_str` function as before, but this time we +assign the return value to a variable of type `Person` so Serde will +automatically interpret the input data as a `Person` and produce informative +error messages if the layout does not conform to what a `Person` is expected to +look like. + +Any type that implements Serde's `Deserialize` trait can be deserialized this +way. This includes built-in Rust standard library types like `Vec` and +`HashMap`, as well as any structs or enums annotated with +`#[derive(Deserialize)]`. + +Once we have `p` of type `Person`, our IDE and the Rust compiler can help us use +it correctly like they do for any other Rust code. The IDE can autocomplete +field names to prevent typos, which was impossible in the `serde_json::Value` +representation. And the Rust compiler can check that when we write +`p.phones[0]`, then `p.phones` is guaranteed to be a `Vec` so indexing +into it makes sense and produces a `String`. + +The necessary setup for using Serde's derive macros is explained on the *[Using +derive]* page of the Serde site. + +[Using derive]: https://serde.rs/derive.html + +## Constructing JSON values + +Serde JSON provides a [`json!` macro][macro] to build `serde_json::Value` +objects with very natural JSON syntax. + +
+ + + +
+ +```rust +use serde_json::json; + +fn main() { + // The type of `john` is `serde_json::Value` + let john = json!({ + "name": "John Doe", + "age": 43, + "phones": [ + "+44 1234567", + "+44 2345678" + ] + }); + + println!("first phone number: {}", john["phones"][0]); + + // Convert to a string of JSON and print it out + println!("{}", john.to_string()); +} +``` + +The `Value::to_string()` function converts a `serde_json::Value` into a `String` +of JSON text. + +One neat thing about the `json!` macro is that variables and expressions can be +interpolated directly into the JSON value as you are building it. Serde will +check at compile time that the value you are interpolating is able to be +represented as JSON. + +
+ + + +
+ +```rust +let full_name = "John Doe"; +let age_last_year = 42; + +// The type of `john` is `serde_json::Value` +let john = json!({ + "name": full_name, + "age": age_last_year + 1, + "phones": [ + format!("+44 {}", random_phone()) + ] +}); +``` + +This is amazingly convenient, but we have the problem we had before with +`Value`: the IDE and Rust compiler cannot help us if we get it wrong. Serde JSON +provides a better way of serializing strongly-typed data structures into JSON +text. + +## Creating JSON by serializing data structures + +A data structure can be converted to a JSON string by +[`serde_json::to_string`][to_string]. There is also +[`serde_json::to_vec`][to_vec] which serializes to a `Vec` and +[`serde_json::to_writer`][to_writer] which serializes to any `io::Write` +such as a File or a TCP stream. + +
+ + + +
+ +```rust +use serde::{Deserialize, Serialize}; +use serde_json::Result; + +#[derive(Serialize, Deserialize)] +struct Address { + street: String, + city: String, +} + +fn print_an_address() -> Result<()> { + // Some data structure. + let address = Address { + street: "10 Downing Street".to_owned(), + city: "London".to_owned(), + }; + + // Serialize it to a JSON string. + let j = serde_json::to_string(&address)?; + + // Print, write to a file, or send to an HTTP server. + println!("{}", j); + + Ok(()) +} +``` + +Any type that implements Serde's `Serialize` trait can be serialized this way. +This includes built-in Rust standard library types like `Vec` and `HashMap`, as well as any structs or enums annotated with `#[derive(Serialize)]`. + +## Performance + +It is fast. You should expect in the ballpark of 500 to 1000 megabytes per +second deserialization and 600 to 900 megabytes per second serialization, +depending on the characteristics of your data. This is competitive with the +fastest C and C++ JSON libraries or even 30% faster for many use cases. +Benchmarks live in the [serde-rs/json-benchmark] repo. + +[serde-rs/json-benchmark]: https://github.com/serde-rs/json-benchmark + +## Getting help + +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 [#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 +[discourse]: https://users.rust-lang.org + +## No-std support + +As long as there is a memory allocator, it is possible to use serde_json without +the rest of the Rust standard library. Disable the default "std" feature and +enable the "alloc" feature: + +```toml +[dependencies] +serde_json = { version = "1.0", default-features = false, features = ["alloc"] } +``` + +For JSON support in Serde without a memory allocator, please see the +[`serde-json-core`] crate. + +[`serde-json-core`]: https://github.com/rust-embedded-community/serde-json-core + +[value]: https://docs.rs/serde_json/1/serde_json/value/enum.Value.html +[from_str]: https://docs.rs/serde_json/1/serde_json/de/fn.from_str.html +[from_slice]: https://docs.rs/serde_json/1/serde_json/de/fn.from_slice.html +[from_reader]: https://docs.rs/serde_json/1/serde_json/de/fn.from_reader.html +[to_string]: https://docs.rs/serde_json/1/serde_json/ser/fn.to_string.html +[to_vec]: https://docs.rs/serde_json/1/serde_json/ser/fn.to_vec.html +[to_writer]: https://docs.rs/serde_json/1/serde_json/ser/fn.to_writer.html +[macro]: https://docs.rs/serde_json/1/serde_json/macro.json.html + +
+ +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + diff --git a/third_party/crates/serde_json-1.0.151/build.rs b/third_party/crates/serde_json-1.0.151/build.rs new file mode 100644 index 0000000..bbf4a74 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/build.rs @@ -0,0 +1,30 @@ +use std::env; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + + println!("cargo:rustc-check-cfg=cfg(fast_arithmetic, values(\"32\", \"64\"))"); + + // Decide ideal limb width for arithmetic in the float parser and string + // parser. + let target_arch = env::var_os("CARGO_CFG_TARGET_ARCH").unwrap(); + let target_pointer_width = env::var_os("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap(); + if target_arch == "aarch64" + || target_arch == "loongarch64" + || target_arch == "mips64" + || target_arch == "powerpc64" + || target_arch == "riscv64" + || target_arch == "wasm32" + || target_arch == "x86_64" + || target_pointer_width == "64" + { + // The above list of architectures are ones that have native support for + // 64-bit arithmetic, but which have some targets using a smaller + // pointer width. Examples include aarch64-unknown-linux-gnu_ilp32 and + // x86_64-unknown-linux-gnux32. So our choice of limb width is not + // equivalent to using usize everywhere. + println!("cargo:rustc-cfg=fast_arithmetic=\"64\""); + } else { + println!("cargo:rustc-cfg=fast_arithmetic=\"32\""); + } +} diff --git a/third_party/crates/serde_json-1.0.151/src/de.rs b/third_party/crates/serde_json-1.0.151/src/de.rs new file mode 100644 index 0000000..fda22f8 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/de.rs @@ -0,0 +1,2714 @@ +//! Deserialize JSON data to a Rust data structure. + +use crate::error::{Error, ErrorCode, Result}; +#[cfg(feature = "float_roundtrip")] +use crate::lexical; +use crate::number::Number; +use crate::read::{self, Fused, Reference}; +use alloc::string::String; +use alloc::vec::Vec; +#[cfg(feature = "float_roundtrip")] +use core::iter; +use core::iter::FusedIterator; +use core::marker::PhantomData; +use core::result; +use core::str::FromStr; +use serde::de::{self, Expected, Unexpected}; +use serde::forward_to_deserialize_any; + +#[cfg(feature = "arbitrary_precision")] +use crate::number::NumberDeserializer; + +pub use crate::read::{Read, SliceRead, StrRead}; + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +pub use crate::read::IoRead; + +////////////////////////////////////////////////////////////////////////////// + +/// A structure that deserializes JSON into Rust values. +pub struct Deserializer { + read: R, + scratch: Vec, + remaining_depth: u8, + #[cfg(feature = "float_roundtrip")] + single_precision: bool, + #[cfg(feature = "unbounded_depth")] + disable_recursion_limit: bool, +} + +impl<'de, R> Deserializer +where + R: read::Read<'de>, +{ + /// Create a JSON deserializer from one of the possible serde_json input + /// sources. + /// + /// When reading from a source against which short reads are not efficient, such + /// as a [`File`], you will want to apply your own buffering because serde_json + /// will not buffer the input. See [`std::io::BufReader`]. + /// + /// Typically it is more convenient to use one of these methods instead: + /// + /// - Deserializer::from_str + /// - Deserializer::from_slice + /// - Deserializer::from_reader + /// + /// [`File`]: std::fs::File + pub fn new(read: R) -> Self { + Deserializer { + read, + scratch: Vec::new(), + remaining_depth: 128, + #[cfg(feature = "float_roundtrip")] + single_precision: false, + #[cfg(feature = "unbounded_depth")] + disable_recursion_limit: false, + } + } +} + +#[cfg(feature = "std")] +impl Deserializer> +where + R: crate::io::Read, +{ + /// Creates a JSON deserializer from an `io::Read`. + /// + /// Reader-based deserializers do not support deserializing borrowed types + /// like `&str`, since the `std::io::Read` trait has no non-copying methods + /// -- everything it does involves copying bytes out of the data source. + pub fn from_reader(reader: R) -> Self { + Deserializer::new(read::IoRead::new(reader)) + } +} + +impl<'a> Deserializer> { + /// Creates a JSON deserializer from a `&[u8]`. + pub fn from_slice(bytes: &'a [u8]) -> Self { + Deserializer::new(read::SliceRead::new(bytes)) + } +} + +impl<'a> Deserializer> { + /// Creates a JSON deserializer from a `&str`. + pub fn from_str(s: &'a str) -> Self { + Deserializer::new(read::StrRead::new(s)) + } +} + +macro_rules! overflow { + ($a:ident * 10 + $b:ident, $c:expr) => { + match $c { + c => $a >= c / 10 && ($a > c / 10 || $b > c % 10), + } + }; +} + +pub(crate) enum ParserNumber { + F64(f64), + U64(u64), + I64(i64), + #[cfg(feature = "arbitrary_precision")] + String(String), +} + +impl ParserNumber { + fn visit<'de, V>(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + match self { + ParserNumber::F64(x) => visitor.visit_f64(x), + ParserNumber::U64(x) => visitor.visit_u64(x), + ParserNumber::I64(x) => visitor.visit_i64(x), + #[cfg(feature = "arbitrary_precision")] + ParserNumber::String(x) => visitor.visit_map(NumberDeserializer { number: x.into() }), + } + } + + fn invalid_type(self, exp: &dyn Expected) -> Error { + match self { + ParserNumber::F64(x) => de::Error::invalid_type(Unexpected::Float(x), exp), + ParserNumber::U64(x) => de::Error::invalid_type(Unexpected::Unsigned(x), exp), + ParserNumber::I64(x) => de::Error::invalid_type(Unexpected::Signed(x), exp), + #[cfg(feature = "arbitrary_precision")] + ParserNumber::String(_) => de::Error::invalid_type(Unexpected::Other("number"), exp), + } + } +} + +impl<'de, R: Read<'de>> Deserializer { + /// The `Deserializer::end` method should be called after a value has been fully deserialized. + /// This allows the `Deserializer` to validate that the input stream is at the end or that it + /// only has trailing whitespace. + pub fn end(&mut self) -> Result<()> { + match tri!(self.parse_whitespace()) { + Some(_) => Err(self.peek_error(ErrorCode::TrailingCharacters)), + None => Ok(()), + } + } + + /// Turn a JSON deserializer into an iterator over values of type T. + pub fn into_iter(self) -> StreamDeserializer<'de, R, T> + where + T: de::Deserialize<'de>, + { + // This cannot be an implementation of std::iter::IntoIterator because + // we need the caller to choose what T is. + let offset = self.read.byte_offset(); + StreamDeserializer { + de: self, + offset, + failed: false, + output: PhantomData, + lifetime: PhantomData, + } + } + + /// Parse arbitrarily deep JSON structures without any consideration for + /// overflowing the stack. + /// + /// You will want to provide some other way to protect against stack + /// overflows, such as by wrapping your Deserializer in the dynamically + /// growing stack adapter provided by the serde_stacker crate. Additionally + /// you will need to be careful around other recursive operations on the + /// parsed result which may overflow the stack after deserialization has + /// completed, including, but not limited to, Display and Debug and Drop + /// impls. + /// + /// *This method is only available if serde_json is built with the + /// `"unbounded_depth"` feature.* + /// + /// # Examples + /// + /// ``` + /// use serde::Deserialize; + /// use serde_json::Value; + /// + /// fn main() { + /// let mut json = String::new(); + /// for _ in 0..10000 { + /// json = format!("[{}]", json); + /// } + /// + /// let mut deserializer = serde_json::Deserializer::from_str(&json); + /// deserializer.disable_recursion_limit(); + /// let deserializer = serde_stacker::Deserializer::new(&mut deserializer); + /// let value = Value::deserialize(deserializer).unwrap(); + /// + /// carefully_drop_nested_arrays(value); + /// } + /// + /// fn carefully_drop_nested_arrays(value: Value) { + /// let mut stack = vec![value]; + /// while let Some(value) = stack.pop() { + /// if let Value::Array(array) = value { + /// stack.extend(array); + /// } + /// } + /// } + /// ``` + #[cfg(feature = "unbounded_depth")] + #[cfg_attr(docsrs, doc(cfg(feature = "unbounded_depth")))] + pub fn disable_recursion_limit(&mut self) { + self.disable_recursion_limit = true; + } + + pub(crate) fn peek(&mut self) -> Result> { + self.read.peek() + } + + fn peek_or_null(&mut self) -> Result { + Ok(tri!(self.peek()).unwrap_or(b'\x00')) + } + + fn eat_char(&mut self) { + self.read.discard(); + } + + fn next_char(&mut self) -> Result> { + self.read.next() + } + + fn next_char_or_null(&mut self) -> Result { + Ok(tri!(self.next_char()).unwrap_or(b'\x00')) + } + + /// Error caused by a byte from next_char(). + #[cold] + fn error(&self, reason: ErrorCode) -> Error { + let position = self.read.position(); + Error::syntax(reason, position.line, position.column) + } + + /// Error caused by a byte from peek(). + #[cold] + fn peek_error(&self, reason: ErrorCode) -> Error { + let position = self.read.peek_position(); + Error::syntax(reason, position.line, position.column) + } + + /// Returns the first non-whitespace byte without consuming it, or `None` if + /// EOF is encountered. + fn parse_whitespace(&mut self) -> Result> { + loop { + match tri!(self.peek()) { + Some(b' ' | b'\n' | b'\t' | b'\r') => { + self.eat_char(); + } + other => { + return Ok(other); + } + } + } + } + + #[cold] + fn peek_invalid_type(&mut self, exp: &dyn Expected) -> Error { + let err = match self.peek_or_null().unwrap_or(b'\x00') { + b'n' => { + self.eat_char(); + if let Err(err) = self.parse_ident(b"ull") { + return err; + } + de::Error::invalid_type(Unexpected::Unit, exp) + } + b't' => { + self.eat_char(); + if let Err(err) = self.parse_ident(b"rue") { + return err; + } + de::Error::invalid_type(Unexpected::Bool(true), exp) + } + b'f' => { + self.eat_char(); + if let Err(err) = self.parse_ident(b"alse") { + return err; + } + de::Error::invalid_type(Unexpected::Bool(false), exp) + } + b'-' => { + self.eat_char(); + match self.parse_any_number(false) { + Ok(n) => n.invalid_type(exp), + Err(err) => return err, + } + } + b'0'..=b'9' => match self.parse_any_number(true) { + Ok(n) => n.invalid_type(exp), + Err(err) => return err, + }, + b'"' => { + self.eat_char(); + self.scratch.clear(); + match self.read.parse_str(&mut self.scratch) { + Ok(s) => de::Error::invalid_type(Unexpected::Str(&s), exp), + Err(err) => return err, + } + } + b'[' => de::Error::invalid_type(Unexpected::Seq, exp), + b'{' => de::Error::invalid_type(Unexpected::Map, exp), + _ => self.peek_error(ErrorCode::ExpectedSomeValue), + }; + + self.fix_position(err) + } + + pub(crate) fn deserialize_number<'any, V>(&mut self, visitor: V) -> Result + where + V: de::Visitor<'any>, + { + let peek = match tri!(self.parse_whitespace()) { + Some(b) => b, + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + let value = match peek { + b'-' => { + self.eat_char(); + tri!(self.parse_integer(false)).visit(visitor) + } + b'0'..=b'9' => tri!(self.parse_integer(true)).visit(visitor), + _ => Err(self.peek_invalid_type(&visitor)), + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.fix_position(err)), + } + } + + #[cfg(feature = "float_roundtrip")] + pub(crate) fn do_deserialize_f32<'any, V>(&mut self, visitor: V) -> Result + where + V: de::Visitor<'any>, + { + self.single_precision = true; + let val = self.deserialize_number(visitor); + self.single_precision = false; + val + } + + pub(crate) fn do_deserialize_i128<'any, V>(&mut self, visitor: V) -> Result + where + V: de::Visitor<'any>, + { + let mut buf = String::new(); + + match tri!(self.parse_whitespace()) { + Some(b'-') => { + self.eat_char(); + buf.push('-'); + } + Some(_) => {} + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + } + + tri!(self.scan_integer128(&mut buf)); + + let value = match buf.parse() { + Ok(int) => visitor.visit_i128(int), + Err(_) => { + return Err(self.error(ErrorCode::NumberOutOfRange)); + } + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.fix_position(err)), + } + } + + pub(crate) fn do_deserialize_u128<'any, V>(&mut self, visitor: V) -> Result + where + V: de::Visitor<'any>, + { + match tri!(self.parse_whitespace()) { + Some(b'-') => { + return Err(self.peek_error(ErrorCode::NumberOutOfRange)); + } + Some(_) => {} + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + } + + let mut buf = String::new(); + tri!(self.scan_integer128(&mut buf)); + + let value = match buf.parse() { + Ok(int) => visitor.visit_u128(int), + Err(_) => { + return Err(self.error(ErrorCode::NumberOutOfRange)); + } + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.fix_position(err)), + } + } + + fn scan_integer128(&mut self, buf: &mut String) -> Result<()> { + match tri!(self.next_char_or_null()) { + b'0' => { + buf.push('0'); + // There can be only one leading '0'. + match tri!(self.peek_or_null()) { + b'0'..=b'9' => Err(self.peek_error(ErrorCode::InvalidNumber)), + _ => Ok(()), + } + } + c @ b'1'..=b'9' => { + buf.push(c as char); + while let c @ b'0'..=b'9' = tri!(self.peek_or_null()) { + self.eat_char(); + buf.push(c as char); + } + Ok(()) + } + _ => Err(self.error(ErrorCode::InvalidNumber)), + } + } + + #[cold] + fn fix_position(&self, err: Error) -> Error { + err.fix_position(move |code| self.error(code)) + } + + fn parse_ident(&mut self, ident: &[u8]) -> Result<()> { + for expected in ident { + match tri!(self.next_char()) { + None => { + return Err(self.error(ErrorCode::EofWhileParsingValue)); + } + Some(next) => { + if next != *expected { + return Err(self.error(ErrorCode::ExpectedSomeIdent)); + } + } + } + } + + Ok(()) + } + + fn parse_integer(&mut self, positive: bool) -> Result { + let next = match tri!(self.next_char()) { + Some(b) => b, + None => { + return Err(self.error(ErrorCode::EofWhileParsingValue)); + } + }; + + match next { + b'0' => { + // There can be only one leading '0'. + match tri!(self.peek_or_null()) { + b'0'..=b'9' => Err(self.peek_error(ErrorCode::InvalidNumber)), + _ => self.parse_number(positive, 0), + } + } + c @ b'1'..=b'9' => { + let mut significand = (c - b'0') as u64; + + loop { + match tri!(self.peek_or_null()) { + c @ b'0'..=b'9' => { + let digit = (c - b'0') as u64; + + // We need to be careful with overflow. If we can, + // try to keep the number as a `u64` until we grow + // too large. At that point, switch to parsing the + // value as a `f64`. + if overflow!(significand * 10 + digit, u64::MAX) { + return Ok(ParserNumber::F64(tri!( + self.parse_long_integer(positive, significand), + ))); + } + + self.eat_char(); + significand = significand * 10 + digit; + } + _ => { + return self.parse_number(positive, significand); + } + } + } + } + _ => Err(self.error(ErrorCode::InvalidNumber)), + } + } + + fn parse_number(&mut self, positive: bool, significand: u64) -> Result { + Ok(match tri!(self.peek_or_null()) { + b'.' => ParserNumber::F64(tri!(self.parse_decimal(positive, significand, 0))), + b'e' | b'E' => ParserNumber::F64(tri!(self.parse_exponent(positive, significand, 0))), + _ => { + if positive { + ParserNumber::U64(significand) + } else { + let neg = (significand as i64).wrapping_neg(); + + // Convert into a float if we underflow, or on `-0`. + if neg >= 0 { + ParserNumber::F64(-(significand as f64)) + } else { + ParserNumber::I64(neg) + } + } + } + }) + } + + fn parse_decimal( + &mut self, + positive: bool, + mut significand: u64, + exponent_before_decimal_point: i32, + ) -> Result { + self.eat_char(); + + let mut exponent_after_decimal_point = 0; + while let c @ b'0'..=b'9' = tri!(self.peek_or_null()) { + let digit = (c - b'0') as u64; + + if overflow!(significand * 10 + digit, u64::MAX) { + let exponent = exponent_before_decimal_point + exponent_after_decimal_point; + return self.parse_decimal_overflow(positive, significand, exponent); + } + + self.eat_char(); + significand = significand * 10 + digit; + exponent_after_decimal_point -= 1; + } + + // Error if there is not at least one digit after the decimal point. + if exponent_after_decimal_point == 0 { + match tri!(self.peek()) { + Some(_) => return Err(self.peek_error(ErrorCode::InvalidNumber)), + None => return Err(self.peek_error(ErrorCode::EofWhileParsingValue)), + } + } + + let exponent = exponent_before_decimal_point + exponent_after_decimal_point; + match tri!(self.peek_or_null()) { + b'e' | b'E' => self.parse_exponent(positive, significand, exponent), + _ => self.f64_from_parts(positive, significand, exponent), + } + } + + fn parse_exponent( + &mut self, + positive: bool, + significand: u64, + starting_exp: i32, + ) -> Result { + self.eat_char(); + + let positive_exp = match tri!(self.peek_or_null()) { + b'+' => { + self.eat_char(); + true + } + b'-' => { + self.eat_char(); + false + } + _ => true, + }; + + let next = match tri!(self.next_char()) { + Some(b) => b, + None => { + return Err(self.error(ErrorCode::EofWhileParsingValue)); + } + }; + + // Make sure a digit follows the exponent place. + let mut exp = match next { + c @ b'0'..=b'9' => (c - b'0') as i32, + _ => { + return Err(self.error(ErrorCode::InvalidNumber)); + } + }; + + while let c @ b'0'..=b'9' = tri!(self.peek_or_null()) { + self.eat_char(); + let digit = (c - b'0') as i32; + + if overflow!(exp * 10 + digit, i32::MAX) { + let zero_significand = significand == 0; + return self.parse_exponent_overflow(positive, zero_significand, positive_exp); + } + + exp = exp * 10 + digit; + } + + let final_exp = if positive_exp { + starting_exp.saturating_add(exp) + } else { + starting_exp.saturating_sub(exp) + }; + + self.f64_from_parts(positive, significand, final_exp) + } + + #[cfg(feature = "float_roundtrip")] + fn f64_from_parts(&mut self, positive: bool, significand: u64, exponent: i32) -> Result { + let f = if self.single_precision { + lexical::parse_concise_float::(significand, exponent) as f64 + } else { + lexical::parse_concise_float::(significand, exponent) + }; + + if f.is_infinite() { + Err(self.error(ErrorCode::NumberOutOfRange)) + } else { + Ok(if positive { f } else { -f }) + } + } + + #[cfg(not(feature = "float_roundtrip"))] + fn f64_from_parts( + &mut self, + positive: bool, + significand: u64, + mut exponent: i32, + ) -> Result { + let mut f = significand as f64; + loop { + match POW10.get(exponent.wrapping_abs() as usize) { + Some(&pow) => { + if exponent >= 0 { + f *= pow; + if f.is_infinite() { + return Err(self.error(ErrorCode::NumberOutOfRange)); + } + } else { + f /= pow; + } + break; + } + None => { + if f == 0.0 { + break; + } + if exponent >= 0 { + return Err(self.error(ErrorCode::NumberOutOfRange)); + } + f /= 1e308; + exponent += 308; + } + } + } + Ok(if positive { f } else { -f }) + } + + #[cfg(feature = "float_roundtrip")] + #[cold] + #[inline(never)] + fn parse_long_integer(&mut self, positive: bool, partial_significand: u64) -> Result { + // To deserialize floats we'll first push the integer and fraction + // parts, both as byte strings, into the scratch buffer and then feed + // both slices to lexical's parser. For example if the input is + // `12.34e5` we'll push b"1234" into scratch and then pass b"12" and + // b"34" to lexical. `integer_end` will be used to track where to split + // the scratch buffer. + // + // Note that lexical expects the integer part to contain *no* leading + // zeroes and the fraction part to contain *no* trailing zeroes. The + // first requirement is already handled by the integer parsing logic. + // The second requirement will be enforced just before passing the + // slices to lexical in f64_long_from_parts. + self.scratch.clear(); + self.scratch + .extend_from_slice(itoa::Buffer::new().format(partial_significand).as_bytes()); + + loop { + match tri!(self.peek_or_null()) { + c @ b'0'..=b'9' => { + self.scratch.push(c); + self.eat_char(); + } + b'.' => { + self.eat_char(); + return self.parse_long_decimal(positive, self.scratch.len()); + } + b'e' | b'E' => { + return self.parse_long_exponent(positive, self.scratch.len()); + } + _ => { + return self.f64_long_from_parts(positive, self.scratch.len(), 0); + } + } + } + } + + #[cfg(not(feature = "float_roundtrip"))] + #[cold] + #[inline(never)] + fn parse_long_integer(&mut self, positive: bool, significand: u64) -> Result { + let mut exponent = 0; + loop { + match tri!(self.peek_or_null()) { + b'0'..=b'9' => { + self.eat_char(); + // This could overflow... if your integer is gigabytes long. + // Ignore that possibility. + exponent += 1; + } + b'.' => { + return self.parse_decimal(positive, significand, exponent); + } + b'e' | b'E' => { + return self.parse_exponent(positive, significand, exponent); + } + _ => { + return self.f64_from_parts(positive, significand, exponent); + } + } + } + } + + #[cfg(feature = "float_roundtrip")] + #[cold] + fn parse_long_decimal(&mut self, positive: bool, integer_end: usize) -> Result { + let mut at_least_one_digit = integer_end < self.scratch.len(); + while let c @ b'0'..=b'9' = tri!(self.peek_or_null()) { + self.scratch.push(c); + self.eat_char(); + at_least_one_digit = true; + } + + if !at_least_one_digit { + match tri!(self.peek()) { + Some(_) => return Err(self.peek_error(ErrorCode::InvalidNumber)), + None => return Err(self.peek_error(ErrorCode::EofWhileParsingValue)), + } + } + + match tri!(self.peek_or_null()) { + b'e' | b'E' => self.parse_long_exponent(positive, integer_end), + _ => self.f64_long_from_parts(positive, integer_end, 0), + } + } + + #[cfg(feature = "float_roundtrip")] + fn parse_long_exponent(&mut self, positive: bool, integer_end: usize) -> Result { + self.eat_char(); + + let positive_exp = match tri!(self.peek_or_null()) { + b'+' => { + self.eat_char(); + true + } + b'-' => { + self.eat_char(); + false + } + _ => true, + }; + + let next = match tri!(self.next_char()) { + Some(b) => b, + None => { + return Err(self.error(ErrorCode::EofWhileParsingValue)); + } + }; + + // Make sure a digit follows the exponent place. + let mut exp = match next { + c @ b'0'..=b'9' => (c - b'0') as i32, + _ => { + return Err(self.error(ErrorCode::InvalidNumber)); + } + }; + + while let c @ b'0'..=b'9' = tri!(self.peek_or_null()) { + self.eat_char(); + let digit = (c - b'0') as i32; + + if overflow!(exp * 10 + digit, i32::MAX) { + let zero_significand = self.scratch.iter().all(|&digit| digit == b'0'); + return self.parse_exponent_overflow(positive, zero_significand, positive_exp); + } + + exp = exp * 10 + digit; + } + + let final_exp = if positive_exp { exp } else { -exp }; + + self.f64_long_from_parts(positive, integer_end, final_exp) + } + + // This cold code should not be inlined into the middle of the hot + // decimal-parsing loop above. + #[cfg(feature = "float_roundtrip")] + #[cold] + #[inline(never)] + fn parse_decimal_overflow( + &mut self, + positive: bool, + significand: u64, + exponent: i32, + ) -> Result { + let mut buffer = itoa::Buffer::new(); + let significand = buffer.format(significand); + let fraction_digits = -exponent as usize; + self.scratch.clear(); + if let Some(zeros) = fraction_digits.checked_sub(significand.len() + 1) { + self.scratch.extend(iter::repeat(b'0').take(zeros + 1)); + } + self.scratch.extend_from_slice(significand.as_bytes()); + let integer_end = self.scratch.len() - fraction_digits; + self.parse_long_decimal(positive, integer_end) + } + + #[cfg(not(feature = "float_roundtrip"))] + #[cold] + #[inline(never)] + fn parse_decimal_overflow( + &mut self, + positive: bool, + significand: u64, + exponent: i32, + ) -> Result { + // The next multiply/add would overflow, so just ignore all further + // digits. + while let b'0'..=b'9' = tri!(self.peek_or_null()) { + self.eat_char(); + } + + match tri!(self.peek_or_null()) { + b'e' | b'E' => self.parse_exponent(positive, significand, exponent), + _ => self.f64_from_parts(positive, significand, exponent), + } + } + + // This cold code should not be inlined into the middle of the hot + // exponent-parsing loop above. + #[cold] + #[inline(never)] + fn parse_exponent_overflow( + &mut self, + positive: bool, + zero_significand: bool, + positive_exp: bool, + ) -> Result { + // Error instead of +/- infinity. + if !zero_significand && positive_exp { + return Err(self.error(ErrorCode::NumberOutOfRange)); + } + + while let b'0'..=b'9' = tri!(self.peek_or_null()) { + self.eat_char(); + } + Ok(if positive { 0.0 } else { -0.0 }) + } + + #[cfg(feature = "float_roundtrip")] + fn f64_long_from_parts( + &mut self, + positive: bool, + integer_end: usize, + exponent: i32, + ) -> Result { + let integer = &self.scratch[..integer_end]; + let fraction = &self.scratch[integer_end..]; + + let f = if self.single_precision { + lexical::parse_truncated_float::(integer, fraction, exponent) as f64 + } else { + lexical::parse_truncated_float::(integer, fraction, exponent) + }; + + if f.is_infinite() { + Err(self.error(ErrorCode::NumberOutOfRange)) + } else { + Ok(if positive { f } else { -f }) + } + } + + fn parse_any_signed_number(&mut self) -> Result { + let peek = match tri!(self.peek()) { + Some(b) => b, + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + let value = match peek { + b'-' => { + self.eat_char(); + self.parse_any_number(false) + } + b'0'..=b'9' => self.parse_any_number(true), + _ => Err(self.peek_error(ErrorCode::InvalidNumber)), + }; + + let value = match tri!(self.peek()) { + Some(_) => Err(self.peek_error(ErrorCode::InvalidNumber)), + None => value, + }; + + match value { + Ok(value) => Ok(value), + // The de::Error impl creates errors with unknown line and column. + // Fill in the position here by looking at the current index in the + // input. There is no way to tell whether this should call `error` + // or `peek_error` so pick the one that seems correct more often. + // Worst case, the position is off by one character. + Err(err) => Err(self.fix_position(err)), + } + } + + #[cfg(not(feature = "arbitrary_precision"))] + fn parse_any_number(&mut self, positive: bool) -> Result { + self.parse_integer(positive) + } + + #[cfg(feature = "arbitrary_precision")] + fn parse_any_number(&mut self, positive: bool) -> Result { + let mut buf = String::with_capacity(16); + if !positive { + buf.push('-'); + } + tri!(self.scan_integer(&mut buf)); + if positive { + if let Ok(unsigned) = buf.parse() { + return Ok(ParserNumber::U64(unsigned)); + } + } else { + if let Ok(signed) = buf.parse() { + return Ok(ParserNumber::I64(signed)); + } + } + Ok(ParserNumber::String(buf)) + } + + #[cfg(feature = "arbitrary_precision")] + fn scan_or_eof(&mut self, buf: &mut String) -> Result { + match tri!(self.next_char()) { + Some(b) => { + buf.push(b as char); + Ok(b) + } + None => Err(self.error(ErrorCode::EofWhileParsingValue)), + } + } + + #[cfg(feature = "arbitrary_precision")] + fn scan_integer(&mut self, buf: &mut String) -> Result<()> { + match tri!(self.scan_or_eof(buf)) { + b'0' => { + // There can be only one leading '0'. + match tri!(self.peek_or_null()) { + b'0'..=b'9' => Err(self.peek_error(ErrorCode::InvalidNumber)), + _ => self.scan_number(buf), + } + } + b'1'..=b'9' => loop { + match tri!(self.peek_or_null()) { + c @ b'0'..=b'9' => { + self.eat_char(); + buf.push(c as char); + } + _ => { + return self.scan_number(buf); + } + } + }, + _ => Err(self.error(ErrorCode::InvalidNumber)), + } + } + + #[cfg(feature = "arbitrary_precision")] + fn scan_number(&mut self, buf: &mut String) -> Result<()> { + match tri!(self.peek_or_null()) { + b'.' => self.scan_decimal(buf), + b'e' | b'E' => self.scan_exponent(buf), + _ => Ok(()), + } + } + + #[cfg(feature = "arbitrary_precision")] + fn scan_decimal(&mut self, buf: &mut String) -> Result<()> { + self.eat_char(); + buf.push('.'); + + let mut at_least_one_digit = false; + while let c @ b'0'..=b'9' = tri!(self.peek_or_null()) { + self.eat_char(); + buf.push(c as char); + at_least_one_digit = true; + } + + if !at_least_one_digit { + match tri!(self.peek()) { + Some(_) => return Err(self.peek_error(ErrorCode::InvalidNumber)), + None => return Err(self.peek_error(ErrorCode::EofWhileParsingValue)), + } + } + + match tri!(self.peek_or_null()) { + b'e' | b'E' => self.scan_exponent(buf), + _ => Ok(()), + } + } + + #[cfg(feature = "arbitrary_precision")] + fn scan_exponent(&mut self, buf: &mut String) -> Result<()> { + self.eat_char(); + buf.push('e'); + + match tri!(self.peek_or_null()) { + b'+' => { + self.eat_char(); + buf.push('+'); + } + b'-' => { + self.eat_char(); + buf.push('-'); + } + _ => { + buf.push('+'); + } + } + + // Make sure a digit follows the exponent place. + match tri!(self.scan_or_eof(buf)) { + b'0'..=b'9' => {} + _ => { + return Err(self.error(ErrorCode::InvalidNumber)); + } + } + + while let c @ b'0'..=b'9' = tri!(self.peek_or_null()) { + self.eat_char(); + buf.push(c as char); + } + + Ok(()) + } + + fn parse_object_colon(&mut self) -> Result<()> { + match tri!(self.parse_whitespace()) { + Some(b':') => { + self.eat_char(); + Ok(()) + } + Some(_) => Err(self.peek_error(ErrorCode::ExpectedColon)), + None => Err(self.peek_error(ErrorCode::EofWhileParsingObject)), + } + } + + fn end_seq(&mut self) -> Result<()> { + match tri!(self.parse_whitespace()) { + Some(b']') => { + self.eat_char(); + Ok(()) + } + Some(b',') => { + self.eat_char(); + match self.parse_whitespace() { + Ok(Some(b']')) => Err(self.peek_error(ErrorCode::TrailingComma)), + _ => Err(self.peek_error(ErrorCode::TrailingCharacters)), + } + } + Some(_) => Err(self.peek_error(ErrorCode::TrailingCharacters)), + None => Err(self.peek_error(ErrorCode::EofWhileParsingList)), + } + } + + fn end_map(&mut self) -> Result<()> { + match tri!(self.parse_whitespace()) { + Some(b'}') => { + self.eat_char(); + Ok(()) + } + Some(b',') => Err(self.peek_error(ErrorCode::TrailingComma)), + Some(_) => Err(self.peek_error(ErrorCode::TrailingCharacters)), + None => Err(self.peek_error(ErrorCode::EofWhileParsingObject)), + } + } + + fn ignore_value(&mut self) -> Result<()> { + self.scratch.clear(); + let mut enclosing = None; + + loop { + let peek = match tri!(self.parse_whitespace()) { + Some(b) => b, + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + let frame = match peek { + b'n' => { + self.eat_char(); + tri!(self.parse_ident(b"ull")); + None + } + b't' => { + self.eat_char(); + tri!(self.parse_ident(b"rue")); + None + } + b'f' => { + self.eat_char(); + tri!(self.parse_ident(b"alse")); + None + } + b'-' => { + self.eat_char(); + tri!(self.ignore_integer()); + None + } + b'0'..=b'9' => { + tri!(self.ignore_integer()); + None + } + b'"' => { + self.eat_char(); + tri!(self.read.ignore_str()); + None + } + frame @ (b'[' | b'{') => { + self.scratch.extend(enclosing.take()); + self.eat_char(); + Some(frame) + } + _ => return Err(self.peek_error(ErrorCode::ExpectedSomeValue)), + }; + + let (mut accept_comma, mut frame) = match frame { + Some(frame) => (false, frame), + None => match enclosing.take() { + Some(frame) => (true, frame), + None => match self.scratch.pop() { + Some(frame) => (true, frame), + None => return Ok(()), + }, + }, + }; + + loop { + match tri!(self.parse_whitespace()) { + Some(b',') if accept_comma => { + self.eat_char(); + break; + } + Some(b']') if frame == b'[' => {} + Some(b'}') if frame == b'{' => {} + Some(_) => { + if accept_comma { + return Err(self.peek_error(match frame { + b'[' => ErrorCode::ExpectedListCommaOrEnd, + b'{' => ErrorCode::ExpectedObjectCommaOrEnd, + _ => unreachable!(), + })); + } else { + break; + } + } + None => { + return Err(self.peek_error(match frame { + b'[' => ErrorCode::EofWhileParsingList, + b'{' => ErrorCode::EofWhileParsingObject, + _ => unreachable!(), + })); + } + } + + self.eat_char(); + frame = match self.scratch.pop() { + Some(frame) => frame, + None => return Ok(()), + }; + accept_comma = true; + } + + if frame == b'{' { + match tri!(self.parse_whitespace()) { + Some(b'"') => self.eat_char(), + Some(_) => return Err(self.peek_error(ErrorCode::KeyMustBeAString)), + None => return Err(self.peek_error(ErrorCode::EofWhileParsingObject)), + } + tri!(self.read.ignore_str()); + match tri!(self.parse_whitespace()) { + Some(b':') => self.eat_char(), + Some(_) => return Err(self.peek_error(ErrorCode::ExpectedColon)), + None => return Err(self.peek_error(ErrorCode::EofWhileParsingObject)), + } + } + + enclosing = Some(frame); + } + } + + fn ignore_integer(&mut self) -> Result<()> { + match tri!(self.next_char_or_null()) { + b'0' => { + // There can be only one leading '0'. + if let b'0'..=b'9' = tri!(self.peek_or_null()) { + return Err(self.peek_error(ErrorCode::InvalidNumber)); + } + } + b'1'..=b'9' => { + while let b'0'..=b'9' = tri!(self.peek_or_null()) { + self.eat_char(); + } + } + _ => { + return Err(self.error(ErrorCode::InvalidNumber)); + } + } + + match tri!(self.peek_or_null()) { + b'.' => self.ignore_decimal(), + b'e' | b'E' => self.ignore_exponent(), + _ => Ok(()), + } + } + + fn ignore_decimal(&mut self) -> Result<()> { + self.eat_char(); + + let mut at_least_one_digit = false; + while let b'0'..=b'9' = tri!(self.peek_or_null()) { + self.eat_char(); + at_least_one_digit = true; + } + + if !at_least_one_digit { + return Err(self.peek_error(ErrorCode::InvalidNumber)); + } + + match tri!(self.peek_or_null()) { + b'e' | b'E' => self.ignore_exponent(), + _ => Ok(()), + } + } + + fn ignore_exponent(&mut self) -> Result<()> { + self.eat_char(); + + match tri!(self.peek_or_null()) { + b'+' | b'-' => self.eat_char(), + _ => {} + } + + // Make sure a digit follows the exponent place. + match tri!(self.next_char_or_null()) { + b'0'..=b'9' => {} + _ => { + return Err(self.error(ErrorCode::InvalidNumber)); + } + } + + while let b'0'..=b'9' = tri!(self.peek_or_null()) { + self.eat_char(); + } + + Ok(()) + } + + #[cfg(feature = "raw_value")] + fn deserialize_raw_value(&mut self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + tri!(self.parse_whitespace()); + self.read.begin_raw_buffering(); + tri!(self.ignore_value()); + self.read.end_raw_buffering(visitor) + } +} + +impl FromStr for Number { + type Err = Error; + + fn from_str(s: &str) -> result::Result { + Deserializer::from_str(s) + .parse_any_signed_number() + .map(Into::into) + } +} + +#[cfg(not(feature = "float_roundtrip"))] +static POW10: [f64; 309] = [ + 1e000, 1e001, 1e002, 1e003, 1e004, 1e005, 1e006, 1e007, 1e008, 1e009, // + 1e010, 1e011, 1e012, 1e013, 1e014, 1e015, 1e016, 1e017, 1e018, 1e019, // + 1e020, 1e021, 1e022, 1e023, 1e024, 1e025, 1e026, 1e027, 1e028, 1e029, // + 1e030, 1e031, 1e032, 1e033, 1e034, 1e035, 1e036, 1e037, 1e038, 1e039, // + 1e040, 1e041, 1e042, 1e043, 1e044, 1e045, 1e046, 1e047, 1e048, 1e049, // + 1e050, 1e051, 1e052, 1e053, 1e054, 1e055, 1e056, 1e057, 1e058, 1e059, // + 1e060, 1e061, 1e062, 1e063, 1e064, 1e065, 1e066, 1e067, 1e068, 1e069, // + 1e070, 1e071, 1e072, 1e073, 1e074, 1e075, 1e076, 1e077, 1e078, 1e079, // + 1e080, 1e081, 1e082, 1e083, 1e084, 1e085, 1e086, 1e087, 1e088, 1e089, // + 1e090, 1e091, 1e092, 1e093, 1e094, 1e095, 1e096, 1e097, 1e098, 1e099, // + 1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106, 1e107, 1e108, 1e109, // + 1e110, 1e111, 1e112, 1e113, 1e114, 1e115, 1e116, 1e117, 1e118, 1e119, // + 1e120, 1e121, 1e122, 1e123, 1e124, 1e125, 1e126, 1e127, 1e128, 1e129, // + 1e130, 1e131, 1e132, 1e133, 1e134, 1e135, 1e136, 1e137, 1e138, 1e139, // + 1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149, // + 1e150, 1e151, 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159, // + 1e160, 1e161, 1e162, 1e163, 1e164, 1e165, 1e166, 1e167, 1e168, 1e169, // + 1e170, 1e171, 1e172, 1e173, 1e174, 1e175, 1e176, 1e177, 1e178, 1e179, // + 1e180, 1e181, 1e182, 1e183, 1e184, 1e185, 1e186, 1e187, 1e188, 1e189, // + 1e190, 1e191, 1e192, 1e193, 1e194, 1e195, 1e196, 1e197, 1e198, 1e199, // + 1e200, 1e201, 1e202, 1e203, 1e204, 1e205, 1e206, 1e207, 1e208, 1e209, // + 1e210, 1e211, 1e212, 1e213, 1e214, 1e215, 1e216, 1e217, 1e218, 1e219, // + 1e220, 1e221, 1e222, 1e223, 1e224, 1e225, 1e226, 1e227, 1e228, 1e229, // + 1e230, 1e231, 1e232, 1e233, 1e234, 1e235, 1e236, 1e237, 1e238, 1e239, // + 1e240, 1e241, 1e242, 1e243, 1e244, 1e245, 1e246, 1e247, 1e248, 1e249, // + 1e250, 1e251, 1e252, 1e253, 1e254, 1e255, 1e256, 1e257, 1e258, 1e259, // + 1e260, 1e261, 1e262, 1e263, 1e264, 1e265, 1e266, 1e267, 1e268, 1e269, // + 1e270, 1e271, 1e272, 1e273, 1e274, 1e275, 1e276, 1e277, 1e278, 1e279, // + 1e280, 1e281, 1e282, 1e283, 1e284, 1e285, 1e286, 1e287, 1e288, 1e289, // + 1e290, 1e291, 1e292, 1e293, 1e294, 1e295, 1e296, 1e297, 1e298, 1e299, // + 1e300, 1e301, 1e302, 1e303, 1e304, 1e305, 1e306, 1e307, 1e308, +]; + +macro_rules! deserialize_number { + ($method:ident) => { + deserialize_number!($method, deserialize_number); + }; + + ($method:ident, $using:ident) => { + fn $method(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + self.$using(visitor) + } + }; +} + +#[cfg(not(feature = "unbounded_depth"))] +macro_rules! if_checking_recursion_limit { + ($($body:tt)*) => { + $($body)* + }; +} + +#[cfg(feature = "unbounded_depth")] +macro_rules! if_checking_recursion_limit { + ($this:ident $($body:tt)*) => { + if !$this.disable_recursion_limit { + $this $($body)* + } + }; +} + +macro_rules! check_recursion { + ($this:ident $($body:tt)*) => { + if_checking_recursion_limit! { + $this.remaining_depth -= 1; + if $this.remaining_depth == 0 { + return Err($this.peek_error(ErrorCode::RecursionLimitExceeded)); + } + } + + $this $($body)* + + if_checking_recursion_limit! { + $this.remaining_depth += 1; + } + }; +} + +impl<'de, R: Read<'de>> de::Deserializer<'de> for &mut Deserializer { + type Error = Error; + + #[inline] + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + let peek = match tri!(self.parse_whitespace()) { + Some(b) => b, + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + let value = match peek { + b'n' => { + self.eat_char(); + tri!(self.parse_ident(b"ull")); + visitor.visit_unit() + } + b't' => { + self.eat_char(); + tri!(self.parse_ident(b"rue")); + visitor.visit_bool(true) + } + b'f' => { + self.eat_char(); + tri!(self.parse_ident(b"alse")); + visitor.visit_bool(false) + } + b'-' => { + self.eat_char(); + tri!(self.parse_any_number(false)).visit(visitor) + } + b'0'..=b'9' => tri!(self.parse_any_number(true)).visit(visitor), + b'"' => { + self.eat_char(); + self.scratch.clear(); + match tri!(self.read.parse_str(&mut self.scratch)) { + Reference::Borrowed(s) => visitor.visit_borrowed_str(s), + Reference::Copied(s) => visitor.visit_str(s), + } + } + b'[' => { + check_recursion! { + self.eat_char(); + let ret = visitor.visit_seq(SeqAccess::new(self)); + } + + match (ret, self.end_seq()) { + (Ok(ret), Ok(())) => Ok(ret), + (Err(err), _) | (_, Err(err)) => Err(err), + } + } + b'{' => { + check_recursion! { + self.eat_char(); + let ret = visitor.visit_map(MapAccess::new(self)); + } + + match (ret, self.end_map()) { + (Ok(ret), Ok(())) => Ok(ret), + (Err(err), _) | (_, Err(err)) => Err(err), + } + } + _ => Err(self.peek_error(ErrorCode::ExpectedSomeValue)), + }; + + match value { + Ok(value) => Ok(value), + // The de::Error impl creates errors with unknown line and column. + // Fill in the position here by looking at the current index in the + // input. There is no way to tell whether this should call `error` + // or `peek_error` so pick the one that seems correct more often. + // Worst case, the position is off by one character. + Err(err) => Err(self.fix_position(err)), + } + } + + fn deserialize_bool(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + let peek = match tri!(self.parse_whitespace()) { + Some(b) => b, + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + let value = match peek { + b't' => { + self.eat_char(); + tri!(self.parse_ident(b"rue")); + visitor.visit_bool(true) + } + b'f' => { + self.eat_char(); + tri!(self.parse_ident(b"alse")); + visitor.visit_bool(false) + } + _ => Err(self.peek_invalid_type(&visitor)), + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.fix_position(err)), + } + } + + deserialize_number!(deserialize_i8); + deserialize_number!(deserialize_i16); + deserialize_number!(deserialize_i32); + deserialize_number!(deserialize_i64); + deserialize_number!(deserialize_u8); + deserialize_number!(deserialize_u16); + deserialize_number!(deserialize_u32); + deserialize_number!(deserialize_u64); + #[cfg(not(feature = "float_roundtrip"))] + deserialize_number!(deserialize_f32); + deserialize_number!(deserialize_f64); + + #[cfg(feature = "float_roundtrip")] + deserialize_number!(deserialize_f32, do_deserialize_f32); + deserialize_number!(deserialize_i128, do_deserialize_i128); + deserialize_number!(deserialize_u128, do_deserialize_u128); + + fn deserialize_char(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_str(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + let peek = match tri!(self.parse_whitespace()) { + Some(b) => b, + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + let value = match peek { + b'"' => { + self.eat_char(); + self.scratch.clear(); + match tri!(self.read.parse_str(&mut self.scratch)) { + Reference::Borrowed(s) => visitor.visit_borrowed_str(s), + Reference::Copied(s) => visitor.visit_str(s), + } + } + _ => Err(self.peek_invalid_type(&visitor)), + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.fix_position(err)), + } + } + + fn deserialize_string(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + self.deserialize_str(visitor) + } + + /// Parses a JSON string as bytes. Note that this function does not check + /// whether the bytes represent a valid UTF-8 string. + /// + /// The relevant part of the JSON specification is Section 8.2 of [RFC + /// 7159]: + /// + /// > When all the strings represented in a JSON text are composed entirely + /// > of Unicode characters (however escaped), then that JSON text is + /// > interoperable in the sense that all software implementations that + /// > parse it will agree on the contents of names and of string values in + /// > objects and arrays. + /// > + /// > However, the ABNF in this specification allows member names and string + /// > values to contain bit sequences that cannot encode Unicode characters; + /// > for example, "\uDEAD" (a single unpaired UTF-16 surrogate). Instances + /// > of this have been observed, for example, when a library truncates a + /// > UTF-16 string without checking whether the truncation split a + /// > surrogate pair. The behavior of software that receives JSON texts + /// > containing such values is unpredictable; for example, implementations + /// > might return different values for the length of a string value or even + /// > suffer fatal runtime exceptions. + /// + /// [RFC 7159]: https://tools.ietf.org/html/rfc7159 + /// + /// The behavior of serde_json is specified to fail on non-UTF-8 strings + /// when deserializing into Rust UTF-8 string types such as String, and + /// succeed with the bytes representing the [WTF-8] encoding of code points + /// when deserializing using this method. + /// + /// [WTF-8]: https://simonsapin.github.io/wtf-8 + /// + /// Escape sequences are processed as usual, and for `\uXXXX` escapes it is + /// still checked if the hex number represents a valid Unicode code point. + /// + /// # Examples + /// + /// You can use this to parse JSON strings containing invalid UTF-8 bytes, + /// or unpaired surrogates. + /// + /// ``` + /// use serde_bytes::ByteBuf; + /// + /// fn look_at_bytes() -> Result<(), serde_json::Error> { + /// let json_data = b"\"some bytes: \xe5\x00\xe5\""; + /// let bytes: ByteBuf = serde_json::from_slice(json_data)?; + /// + /// assert_eq!(b'\xe5', bytes[12]); + /// assert_eq!(b'\0', bytes[13]); + /// assert_eq!(b'\xe5', bytes[14]); + /// + /// Ok(()) + /// } + /// # + /// # look_at_bytes().unwrap(); + /// ``` + /// + /// Backslash escape sequences like `\n` are still interpreted and required + /// to be valid. `\u` escape sequences are required to represent a valid + /// Unicode code point or lone surrogate. + /// + /// ``` + /// use serde_bytes::ByteBuf; + /// + /// fn look_at_bytes() -> Result<(), serde_json::Error> { + /// let json_data = b"\"lone surrogate: \\uD801\""; + /// let bytes: ByteBuf = serde_json::from_slice(json_data)?; + /// let expected = b"lone surrogate: \xED\xA0\x81"; + /// assert_eq!(expected, bytes.as_slice()); + /// Ok(()) + /// } + /// # + /// # look_at_bytes(); + /// ``` + fn deserialize_bytes(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + let peek = match tri!(self.parse_whitespace()) { + Some(b) => b, + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + let value = match peek { + b'"' => { + self.eat_char(); + self.scratch.clear(); + match tri!(self.read.parse_str_raw(&mut self.scratch)) { + Reference::Borrowed(b) => visitor.visit_borrowed_bytes(b), + Reference::Copied(b) => visitor.visit_bytes(b), + } + } + b'[' => self.deserialize_seq(visitor), + _ => Err(self.peek_invalid_type(&visitor)), + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.fix_position(err)), + } + } + + #[inline] + fn deserialize_byte_buf(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + self.deserialize_bytes(visitor) + } + + /// Parses a `null` as a None, and any other values as a `Some(...)`. + #[inline] + fn deserialize_option(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + match tri!(self.parse_whitespace()) { + Some(b'n') => { + self.eat_char(); + tri!(self.parse_ident(b"ull")); + visitor.visit_none() + } + _ => visitor.visit_some(self), + } + } + + fn deserialize_unit(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + let peek = match tri!(self.parse_whitespace()) { + Some(b) => b, + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + let value = match peek { + b'n' => { + self.eat_char(); + tri!(self.parse_ident(b"ull")); + visitor.visit_unit() + } + _ => Err(self.peek_invalid_type(&visitor)), + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.fix_position(err)), + } + } + + fn deserialize_unit_struct(self, _name: &'static str, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + self.deserialize_unit(visitor) + } + + /// Parses a newtype struct as the underlying value. + #[inline] + fn deserialize_newtype_struct(self, name: &str, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + #[cfg(feature = "raw_value")] + { + if name == crate::raw::TOKEN { + return self.deserialize_raw_value(visitor); + } + } + + let _ = name; + visitor.visit_newtype_struct(self) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + let peek = match tri!(self.parse_whitespace()) { + Some(b) => b, + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + let value = match peek { + b'[' => { + check_recursion! { + self.eat_char(); + let ret = visitor.visit_seq(SeqAccess::new(self)); + } + + match (ret, self.end_seq()) { + (Ok(ret), Ok(())) => Ok(ret), + (Err(err), _) | (_, Err(err)) => Err(err), + } + } + _ => Err(self.peek_invalid_type(&visitor)), + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.fix_position(err)), + } + } + + fn deserialize_tuple(self, _len: usize, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_map(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + let peek = match tri!(self.parse_whitespace()) { + Some(b) => b, + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + let value = match peek { + b'{' => { + check_recursion! { + self.eat_char(); + let ret = visitor.visit_map(MapAccess::new(self)); + } + + match (ret, self.end_map()) { + (Ok(ret), Ok(())) => Ok(ret), + (Err(err), _) | (_, Err(err)) => Err(err), + } + } + _ => Err(self.peek_invalid_type(&visitor)), + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.fix_position(err)), + } + } + + fn deserialize_struct( + self, + _name: &'static str, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + let peek = match tri!(self.parse_whitespace()) { + Some(b) => b, + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + let value = match peek { + b'[' => { + check_recursion! { + self.eat_char(); + let ret = visitor.visit_seq(SeqAccess::new(self)); + } + + match (ret, self.end_seq()) { + (Ok(ret), Ok(())) => Ok(ret), + (Err(err), _) | (_, Err(err)) => Err(err), + } + } + b'{' => { + check_recursion! { + self.eat_char(); + let ret = visitor.visit_map(MapAccess::new(self)); + } + + match (ret, self.end_map()) { + (Ok(ret), Ok(())) => Ok(ret), + (Err(err), _) | (_, Err(err)) => Err(err), + } + } + _ => Err(self.peek_invalid_type(&visitor)), + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.fix_position(err)), + } + } + + /// Parses an enum as an object like `{"$KEY":$VALUE}`, where $VALUE is either a straight + /// value, a `[..]`, or a `{..}`. + #[inline] + fn deserialize_enum( + self, + _name: &str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + match tri!(self.parse_whitespace()) { + Some(b'{') => { + check_recursion! { + self.eat_char(); + let ret = visitor.visit_enum(VariantAccess::new(self)); + } + let value = tri!(ret); + + match tri!(self.parse_whitespace()) { + Some(b'}') => { + self.eat_char(); + Ok(value) + } + Some(_) => Err(self.error(ErrorCode::ExpectedSomeValue)), + None => Err(self.error(ErrorCode::EofWhileParsingObject)), + } + } + Some(b'"') => visitor.visit_enum(UnitVariantAccess::new(self)), + Some(_) => Err(self.peek_error(ErrorCode::ExpectedSomeValue)), + None => Err(self.peek_error(ErrorCode::EofWhileParsingValue)), + } + } + + fn deserialize_identifier(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + tri!(self.ignore_value()); + visitor.visit_unit() + } +} + +struct SeqAccess<'a, R: 'a> { + de: &'a mut Deserializer, + first: bool, +} + +impl<'a, R: 'a> SeqAccess<'a, R> { + fn new(de: &'a mut Deserializer) -> Self { + SeqAccess { de, first: true } + } +} + +impl<'de, 'a, R: Read<'de> + 'a> de::SeqAccess<'de> for SeqAccess<'a, R> { + type Error = Error; + + fn next_element_seed(&mut self, seed: T) -> Result> + where + T: de::DeserializeSeed<'de>, + { + fn has_next_element<'de, 'a, R: Read<'de> + 'a>( + seq: &mut SeqAccess<'a, R>, + ) -> Result { + let peek = match tri!(seq.de.parse_whitespace()) { + Some(b) => b, + None => { + return Err(seq.de.peek_error(ErrorCode::EofWhileParsingList)); + } + }; + + if peek == b']' { + Ok(false) + } else if seq.first { + seq.first = false; + Ok(true) + } else if peek == b',' { + seq.de.eat_char(); + match tri!(seq.de.parse_whitespace()) { + Some(b']') => Err(seq.de.peek_error(ErrorCode::TrailingComma)), + Some(_) => Ok(true), + None => Err(seq.de.peek_error(ErrorCode::EofWhileParsingValue)), + } + } else { + Err(seq.de.peek_error(ErrorCode::ExpectedListCommaOrEnd)) + } + } + + if tri!(has_next_element(self)) { + Ok(Some(tri!(seed.deserialize(&mut *self.de)))) + } else { + Ok(None) + } + } +} + +struct MapAccess<'a, R: 'a> { + de: &'a mut Deserializer, + first: bool, +} + +impl<'a, R: 'a> MapAccess<'a, R> { + fn new(de: &'a mut Deserializer) -> Self { + MapAccess { de, first: true } + } +} + +impl<'de, 'a, R: Read<'de> + 'a> de::MapAccess<'de> for MapAccess<'a, R> { + type Error = Error; + + fn next_key_seed(&mut self, seed: K) -> Result> + where + K: de::DeserializeSeed<'de>, + { + fn has_next_key<'de, 'a, R: Read<'de> + 'a>(map: &mut MapAccess<'a, R>) -> Result { + let peek = match tri!(map.de.parse_whitespace()) { + Some(b) => b, + None => { + return Err(map.de.peek_error(ErrorCode::EofWhileParsingObject)); + } + }; + + if peek == b'}' { + Ok(false) + } else if map.first { + map.first = false; + if peek == b'"' { + Ok(true) + } else { + Err(map.de.peek_error(ErrorCode::KeyMustBeAString)) + } + } else if peek == b',' { + map.de.eat_char(); + match tri!(map.de.parse_whitespace()) { + Some(b'"') => Ok(true), + Some(b'}') => Err(map.de.peek_error(ErrorCode::TrailingComma)), + Some(_) => Err(map.de.peek_error(ErrorCode::KeyMustBeAString)), + None => Err(map.de.peek_error(ErrorCode::EofWhileParsingValue)), + } + } else { + Err(map.de.peek_error(ErrorCode::ExpectedObjectCommaOrEnd)) + } + } + + if tri!(has_next_key(self)) { + Ok(Some(tri!(seed.deserialize(MapKey { de: &mut *self.de })))) + } else { + Ok(None) + } + } + + fn next_value_seed(&mut self, seed: V) -> Result + where + V: de::DeserializeSeed<'de>, + { + tri!(self.de.parse_object_colon()); + + seed.deserialize(&mut *self.de) + } +} + +struct VariantAccess<'a, R: 'a> { + de: &'a mut Deserializer, +} + +impl<'a, R: 'a> VariantAccess<'a, R> { + fn new(de: &'a mut Deserializer) -> Self { + VariantAccess { de } + } +} + +impl<'de, 'a, R: Read<'de> + 'a> de::EnumAccess<'de> for VariantAccess<'a, R> { + type Error = Error; + type Variant = Self; + + fn variant_seed(self, seed: V) -> Result<(V::Value, Self)> + where + V: de::DeserializeSeed<'de>, + { + match tri!(self.de.parse_whitespace()) { + Some(b'"') => {} + Some(b'}') => return Err(self.de.peek_error(ErrorCode::ExpectedSomeValue)), + Some(_) => return Err(self.de.peek_error(ErrorCode::KeyMustBeAString)), + None => return Err(self.de.peek_error(ErrorCode::EofWhileParsingObject)), + } + + let val = match seed.deserialize(MapKey { de: &mut *self.de }) { + Ok(value) => value, + Err(err) => return Err(self.de.fix_position(err)), + }; + tri!(self.de.parse_object_colon()); + Ok((val, self)) + } +} + +impl<'de, 'a, R: Read<'de> + 'a> de::VariantAccess<'de> for VariantAccess<'a, R> { + type Error = Error; + + fn unit_variant(self) -> Result<()> { + de::Deserialize::deserialize(self.de) + } + + fn newtype_variant_seed(self, seed: T) -> Result + where + T: de::DeserializeSeed<'de>, + { + seed.deserialize(self.de) + } + + fn tuple_variant(self, _len: usize, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + de::Deserializer::deserialize_seq(self.de, visitor) + } + + fn struct_variant(self, fields: &'static [&'static str], visitor: V) -> Result + where + V: de::Visitor<'de>, + { + de::Deserializer::deserialize_struct(self.de, "", fields, visitor) + } +} + +struct UnitVariantAccess<'a, R: 'a> { + de: &'a mut Deserializer, +} + +impl<'a, R: 'a> UnitVariantAccess<'a, R> { + fn new(de: &'a mut Deserializer) -> Self { + UnitVariantAccess { de } + } +} + +impl<'de, 'a, R: Read<'de> + 'a> de::EnumAccess<'de> for UnitVariantAccess<'a, R> { + type Error = Error; + type Variant = Self; + + fn variant_seed(self, seed: V) -> Result<(V::Value, Self)> + where + V: de::DeserializeSeed<'de>, + { + let variant = tri!(seed.deserialize(&mut *self.de)); + Ok((variant, self)) + } +} + +impl<'de, 'a, R: Read<'de> + 'a> de::VariantAccess<'de> for UnitVariantAccess<'a, R> { + type Error = Error; + + fn unit_variant(self) -> Result<()> { + Ok(()) + } + + fn newtype_variant_seed(self, _seed: T) -> Result + where + T: de::DeserializeSeed<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"newtype variant", + )) + } + + fn tuple_variant(self, _len: usize, _visitor: V) -> Result + where + V: de::Visitor<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"tuple variant", + )) + } + + fn struct_variant(self, _fields: &'static [&'static str], _visitor: V) -> Result + where + V: de::Visitor<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"struct variant", + )) + } +} + +/// Only deserialize from this after peeking a '"' byte! Otherwise it may +/// deserialize invalid JSON successfully. +struct MapKey<'a, R: 'a> { + de: &'a mut Deserializer, +} + +macro_rules! deserialize_numeric_key { + ($method:ident) => { + fn $method(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + self.deserialize_number(visitor) + } + }; + + ($method:ident, $delegate:ident) => { + fn $method(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + self.de.eat_char(); + + match tri!(self.de.peek()) { + Some(b'0'..=b'9' | b'-') => {} + _ => return Err(self.de.error(ErrorCode::ExpectedNumericKey)), + } + + let value = tri!(self.de.$delegate(visitor)); + + match tri!(self.de.peek()) { + Some(b'"') => self.de.eat_char(), + _ => return Err(self.de.peek_error(ErrorCode::ExpectedDoubleQuote)), + } + + Ok(value) + } + }; +} + +impl<'de, 'a, R> MapKey<'a, R> +where + R: Read<'de>, +{ + deserialize_numeric_key!(deserialize_number, deserialize_number); +} + +impl<'de, 'a, R> de::Deserializer<'de> for MapKey<'a, R> +where + R: Read<'de>, +{ + type Error = Error; + + #[inline] + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + self.de.eat_char(); + self.de.scratch.clear(); + match tri!(self.de.read.parse_str(&mut self.de.scratch)) { + Reference::Borrowed(s) => visitor.visit_borrowed_str(s), + Reference::Copied(s) => visitor.visit_str(s), + } + } + + deserialize_numeric_key!(deserialize_i8); + deserialize_numeric_key!(deserialize_i16); + deserialize_numeric_key!(deserialize_i32); + deserialize_numeric_key!(deserialize_i64); + deserialize_numeric_key!(deserialize_i128, deserialize_i128); + deserialize_numeric_key!(deserialize_u8); + deserialize_numeric_key!(deserialize_u16); + deserialize_numeric_key!(deserialize_u32); + deserialize_numeric_key!(deserialize_u64); + deserialize_numeric_key!(deserialize_u128, deserialize_u128); + #[cfg(not(feature = "float_roundtrip"))] + deserialize_numeric_key!(deserialize_f32); + #[cfg(feature = "float_roundtrip")] + deserialize_numeric_key!(deserialize_f32, deserialize_f32); + deserialize_numeric_key!(deserialize_f64); + + fn deserialize_bool(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + self.de.eat_char(); + + let peek = match tri!(self.de.next_char()) { + Some(b) => b, + None => { + return Err(self.de.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + let value = match peek { + b't' => { + tri!(self.de.parse_ident(b"rue\"")); + visitor.visit_bool(true) + } + b'f' => { + tri!(self.de.parse_ident(b"alse\"")); + visitor.visit_bool(false) + } + _ => { + self.de.scratch.clear(); + let s = tri!(self.de.read.parse_str(&mut self.de.scratch)); + Err(de::Error::invalid_type(Unexpected::Str(&s), &visitor)) + } + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.de.fix_position(err)), + } + } + + #[inline] + fn deserialize_option(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + // Map keys cannot be null. + visitor.visit_some(self) + } + + #[inline] + fn deserialize_newtype_struct(self, name: &'static str, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + #[cfg(feature = "raw_value")] + { + if name == crate::raw::TOKEN { + return self.de.deserialize_raw_value(visitor); + } + } + + let _ = name; + visitor.visit_newtype_struct(self) + } + + #[inline] + fn deserialize_enum( + self, + name: &'static str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + self.de.deserialize_enum(name, variants, visitor) + } + + #[inline] + fn deserialize_bytes(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + self.de.deserialize_bytes(visitor) + } + + #[inline] + fn deserialize_byte_buf(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + self.de.deserialize_bytes(visitor) + } + + forward_to_deserialize_any! { + char str string unit unit_struct seq tuple tuple_struct map struct + identifier ignored_any + } +} + +////////////////////////////////////////////////////////////////////////////// + +/// Iterator that deserializes a stream into multiple JSON values. +/// +/// A stream deserializer can be created from any JSON deserializer using the +/// `Deserializer::into_iter` method. +/// +/// The data can consist of any JSON value. Values need to be a self-delineating value e.g. +/// arrays, objects, or strings, or be followed by whitespace or a self-delineating value. +/// +/// ``` +/// use serde_json::{Deserializer, Value}; +/// +/// fn main() { +/// let data = "{\"k\": 3}1\"cool\"\"stuff\" 3{} [0, 1, 2]"; +/// +/// let stream = Deserializer::from_str(data).into_iter::(); +/// +/// for value in stream { +/// println!("{}", value.unwrap()); +/// } +/// } +/// ``` +pub struct StreamDeserializer<'de, R, T> { + de: Deserializer, + offset: usize, + failed: bool, + output: PhantomData, + lifetime: PhantomData<&'de ()>, +} + +impl<'de, R, T> StreamDeserializer<'de, R, T> +where + R: read::Read<'de>, + T: de::Deserialize<'de>, +{ + /// Create a JSON stream deserializer from one of the possible serde_json + /// input sources. + /// + /// Typically it is more convenient to use one of these methods instead: + /// + /// - Deserializer::from_str(...).into_iter() + /// - Deserializer::from_slice(...).into_iter() + /// - Deserializer::from_reader(...).into_iter() + pub fn new(read: R) -> Self { + let offset = read.byte_offset(); + StreamDeserializer { + de: Deserializer::new(read), + offset, + failed: false, + output: PhantomData, + lifetime: PhantomData, + } + } + + /// Returns the number of bytes so far deserialized into a successful `T`. + /// + /// If a stream deserializer returns an EOF error, new data can be joined to + /// `old_data[stream.byte_offset()..]` to try again. + /// + /// ``` + /// let data = b"[0] [1] ["; + /// + /// let de = serde_json::Deserializer::from_slice(data); + /// let mut stream = de.into_iter::>(); + /// assert_eq!(0, stream.byte_offset()); + /// + /// println!("{:?}", stream.next()); // [0] + /// assert_eq!(3, stream.byte_offset()); + /// + /// println!("{:?}", stream.next()); // [1] + /// assert_eq!(7, stream.byte_offset()); + /// + /// println!("{:?}", stream.next()); // error + /// assert_eq!(8, stream.byte_offset()); + /// + /// // If err.is_eof(), can join the remaining data to new data and continue. + /// let remaining = &data[stream.byte_offset()..]; + /// ``` + /// + /// *Note:* In the future this method may be changed to return the number of + /// bytes so far deserialized into a successful T *or* syntactically valid + /// JSON skipped over due to a type error. See [serde-rs/json#70] for an + /// example illustrating this. + /// + /// [serde-rs/json#70]: https://github.com/serde-rs/json/issues/70 + pub fn byte_offset(&self) -> usize { + self.offset + } + + fn peek_end_of_value(&mut self) -> Result<()> { + match tri!(self.de.peek()) { + Some(b' ' | b'\n' | b'\t' | b'\r' | b'"' | b'[' | b']' | b'{' | b'}' | b',' | b':') + | None => Ok(()), + Some(_) => { + let position = self.de.read.peek_position(); + Err(Error::syntax( + ErrorCode::TrailingCharacters, + position.line, + position.column, + )) + } + } + } +} + +impl<'de, R, T> Iterator for StreamDeserializer<'de, R, T> +where + R: Read<'de>, + T: de::Deserialize<'de>, +{ + type Item = Result; + + fn next(&mut self) -> Option> { + if R::should_early_return_if_failed && self.failed { + return None; + } + + // skip whitespaces, if any + // this helps with trailing whitespaces, since whitespaces between + // values are handled for us. + match self.de.parse_whitespace() { + Ok(None) => { + self.offset = self.de.read.byte_offset(); + None + } + Ok(Some(b)) => { + // If the value does not have a clear way to show the end of the value + // (like numbers, null, true etc.) we have to look for whitespace or + // the beginning of a self-delineated value. + let self_delineated_value = match b { + b'[' | b'"' | b'{' => true, + _ => false, + }; + self.offset = self.de.read.byte_offset(); + let result = de::Deserialize::deserialize(&mut self.de); + + Some(match result { + Ok(value) => { + self.offset = self.de.read.byte_offset(); + if self_delineated_value { + Ok(value) + } else { + self.peek_end_of_value().map(|()| value) + } + } + Err(e) => { + self.de.read.set_failed(&mut self.failed); + Err(e) + } + }) + } + Err(e) => { + self.de.read.set_failed(&mut self.failed); + Some(Err(e)) + } + } + } +} + +impl<'de, R, T> FusedIterator for StreamDeserializer<'de, R, T> +where + R: Read<'de> + Fused, + T: de::Deserialize<'de>, +{ +} + +////////////////////////////////////////////////////////////////////////////// + +fn from_trait<'de, R, T>(read: R) -> Result +where + R: Read<'de>, + T: de::Deserialize<'de>, +{ + let mut de = Deserializer::new(read); + let value = tri!(de::Deserialize::deserialize(&mut de)); + + // Make sure the whole stream has been consumed. + tri!(de.end()); + Ok(value) +} + +/// Deserialize an instance of type `T` from an I/O stream of JSON. +/// +/// The content of the I/O stream is deserialized directly from the stream +/// without being buffered in memory by serde_json. +/// +/// When reading from a source against which short reads are not efficient, such +/// as a [`File`], you will want to apply your own buffering because serde_json +/// will not buffer the input. See [`std::io::BufReader`]. +/// +/// It is expected that the input stream ends after the deserialized object. +/// If the stream does not end, such as in the case of a persistent socket connection, +/// this function will not return. It is possible instead to deserialize from a prefix of an input +/// stream without looking for EOF by managing your own [`Deserializer`]. +/// +/// Note that counter to intuition, this function is usually slower than +/// reading a file completely into memory and then applying [`from_str`] +/// or [`from_slice`] on it. See [issue #160]. +/// +/// [`File`]: std::fs::File +/// [issue #160]: https://github.com/serde-rs/json/issues/160 +/// +/// # Example +/// +/// Reading the contents of a file. +/// +/// ``` +/// use serde::Deserialize; +/// +/// use std::error::Error; +/// use std::fs::File; +/// use std::io::BufReader; +/// use std::path::Path; +/// +/// #[derive(Deserialize, Debug)] +/// struct User { +/// fingerprint: String, +/// location: String, +/// } +/// +/// fn read_user_from_file>(path: P) -> Result> { +/// // Open the file in read-only mode with buffer. +/// let file = File::open(path)?; +/// let reader = BufReader::new(file); +/// +/// // Read the JSON contents of the file as an instance of `User`. +/// let u = serde_json::from_reader(reader)?; +/// +/// // Return the `User`. +/// Ok(u) +/// } +/// +/// fn main() { +/// # } +/// # fn fake_main() { +/// let u = read_user_from_file("test.json").unwrap(); +/// println!("{:#?}", u); +/// } +/// ``` +/// +/// Reading from a persistent socket connection. +/// +/// ``` +/// use serde::Deserialize; +/// +/// use std::error::Error; +/// use std::io::BufReader; +/// use std::net::{TcpListener, TcpStream}; +/// +/// #[derive(Deserialize, Debug)] +/// struct User { +/// fingerprint: String, +/// location: String, +/// } +/// +/// fn read_user_from_stream(stream: &mut BufReader) -> Result> { +/// let mut de = serde_json::Deserializer::from_reader(stream); +/// let u = User::deserialize(&mut de)?; +/// +/// Ok(u) +/// } +/// +/// fn main() { +/// # } +/// # fn fake_main() { +/// let listener = TcpListener::bind("127.0.0.1:4000").unwrap(); +/// +/// for tcp_stream in listener.incoming() { +/// let mut buffered = BufReader::new(tcp_stream.unwrap()); +/// println!("{:#?}", read_user_from_stream(&mut buffered)); +/// } +/// } +/// ``` +/// +/// # Errors +/// +/// This conversion can fail if the structure of the input does not match the +/// structure expected by `T`, for example if `T` is a struct type but the input +/// contains something other than a JSON map. It can also fail if the structure +/// is correct but `T`'s implementation of `Deserialize` decides that something +/// is wrong with the data, for example required struct fields are missing from +/// the JSON map or some number is too big to fit in the expected primitive +/// type. +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +pub fn from_reader(rdr: R) -> Result +where + R: crate::io::Read, + T: de::DeserializeOwned, +{ + from_trait(read::IoRead::new(rdr)) +} + +/// Deserialize an instance of type `T` from bytes of JSON text. +/// +/// # Example +/// +/// ``` +/// use serde::Deserialize; +/// +/// #[derive(Deserialize, Debug)] +/// struct User { +/// fingerprint: String, +/// location: String, +/// } +/// +/// fn main() { +/// // The type of `j` is `&[u8]` +/// let j = b" +/// { +/// \"fingerprint\": \"0xF9BA143B95FF6D82\", +/// \"location\": \"Menlo Park, CA\" +/// }"; +/// +/// let u: User = serde_json::from_slice(j).unwrap(); +/// println!("{:#?}", u); +/// } +/// ``` +/// +/// # Errors +/// +/// This conversion can fail if the structure of the input does not match the +/// structure expected by `T`, for example if `T` is a struct type but the input +/// contains something other than a JSON map. It can also fail if the structure +/// is correct but `T`'s implementation of `Deserialize` decides that something +/// is wrong with the data, for example required struct fields are missing from +/// the JSON map or some number is too big to fit in the expected primitive +/// type. +pub fn from_slice<'a, T>(v: &'a [u8]) -> Result +where + T: de::Deserialize<'a>, +{ + from_trait(read::SliceRead::new(v)) +} + +/// Deserialize an instance of type `T` from a string of JSON text. +/// +/// # Example +/// +/// ``` +/// use serde::Deserialize; +/// +/// #[derive(Deserialize, Debug)] +/// struct User { +/// fingerprint: String, +/// location: String, +/// } +/// +/// fn main() { +/// // The type of `j` is `&str` +/// let j = " +/// { +/// \"fingerprint\": \"0xF9BA143B95FF6D82\", +/// \"location\": \"Menlo Park, CA\" +/// }"; +/// +/// let u: User = serde_json::from_str(j).unwrap(); +/// println!("{:#?}", u); +/// } +/// ``` +/// +/// # Errors +/// +/// This conversion can fail if the structure of the input does not match the +/// structure expected by `T`, for example if `T` is a struct type but the input +/// contains something other than a JSON map. It can also fail if the structure +/// is correct but `T`'s implementation of `Deserialize` decides that something +/// is wrong with the data, for example required struct fields are missing from +/// the JSON map or some number is too big to fit in the expected primitive +/// type. +pub fn from_str<'a, T>(s: &'a str) -> Result +where + T: de::Deserialize<'a>, +{ + from_trait(read::StrRead::new(s)) +} diff --git a/third_party/crates/serde_json-1.0.151/src/error.rs b/third_party/crates/serde_json-1.0.151/src/error.rs new file mode 100644 index 0000000..b74f444 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/error.rs @@ -0,0 +1,541 @@ +//! When serializing or deserializing JSON goes wrong. + +use crate::io; +use alloc::boxed::Box; +use alloc::string::{String, ToString}; +use core::fmt::{self, Debug, Display}; +use core::result; +use core::str::FromStr; +use serde::{de, ser}; +#[cfg(feature = "std")] +use std::error; +#[cfg(feature = "std")] +use std::io::ErrorKind; + +/// This type represents all possible errors that can occur when serializing or +/// deserializing JSON data. +pub struct Error { + /// This `Box` allows us to keep the size of `Error` as small as possible. A + /// larger `Error` type was substantially slower due to all the functions + /// that pass around `Result`. + err: Box, +} + +/// Alias for a `Result` with the error type `serde_json::Error`. +pub type Result = result::Result; + +impl Error { + /// One-based line number at which the error was detected. + /// + /// Characters in the first line of the input (before the first newline + /// character) are in line 1. + pub fn line(&self) -> usize { + self.err.line + } + + /// One-based column number at which the error was detected. + /// + /// The first character in the input and any characters immediately + /// following a newline character are in column 1. + /// + /// Note that errors may occur in column 0, for example if a read from an + /// I/O stream fails immediately following a previously read newline + /// character. + pub fn column(&self) -> usize { + self.err.column + } + + /// Categorizes the cause of this error. + /// + /// - `Category::Io` - failure to read or write bytes on an I/O stream + /// - `Category::Syntax` - input that is not syntactically valid JSON + /// - `Category::Data` - input data that is semantically incorrect + /// - `Category::Eof` - unexpected end of the input data + pub fn classify(&self) -> Category { + match self.err.code { + ErrorCode::Message(_) => Category::Data, + ErrorCode::Io(_) => Category::Io, + ErrorCode::EofWhileParsingList + | ErrorCode::EofWhileParsingObject + | ErrorCode::EofWhileParsingString + | ErrorCode::EofWhileParsingValue => Category::Eof, + ErrorCode::ExpectedColon + | ErrorCode::ExpectedListCommaOrEnd + | ErrorCode::ExpectedObjectCommaOrEnd + | ErrorCode::ExpectedSomeIdent + | ErrorCode::ExpectedSomeValue + | ErrorCode::ExpectedDoubleQuote + | ErrorCode::InvalidEscape + | ErrorCode::InvalidNumber + | ErrorCode::NumberOutOfRange + | ErrorCode::InvalidUnicodeCodePoint + | ErrorCode::ControlCharacterWhileParsingString + | ErrorCode::KeyMustBeAString + | ErrorCode::ExpectedNumericKey + | ErrorCode::FloatKeyMustBeFinite + | ErrorCode::LoneLeadingSurrogateInHexEscape + | ErrorCode::TrailingComma + | ErrorCode::TrailingCharacters + | ErrorCode::UnexpectedEndOfHexEscape + | ErrorCode::RecursionLimitExceeded => Category::Syntax, + } + } + + /// Returns true if this error was caused by a failure to read or write + /// bytes on an I/O stream. + pub fn is_io(&self) -> bool { + self.classify() == Category::Io + } + + /// Returns true if this error was caused by input that was not + /// syntactically valid JSON. + pub fn is_syntax(&self) -> bool { + self.classify() == Category::Syntax + } + + /// Returns true if this error was caused by input data that was + /// semantically incorrect. + /// + /// For example, JSON containing a number is semantically incorrect when the + /// type being deserialized into holds a String. + pub fn is_data(&self) -> bool { + self.classify() == Category::Data + } + + /// Returns true if this error was caused by prematurely reaching the end of + /// the input data. + /// + /// Callers that process streaming input may be interested in retrying the + /// deserialization once more data is available. + pub fn is_eof(&self) -> bool { + self.classify() == Category::Eof + } + + /// The kind reported by the underlying standard library I/O error, if this + /// error was caused by a failure to read or write bytes on an I/O stream. + /// + /// # Example + /// + /// ``` + /// use serde_json::Value; + /// use std::io::{self, ErrorKind, Read}; + /// use std::process; + /// + /// struct ReaderThatWillTimeOut<'a>(&'a [u8]); + /// + /// impl<'a> Read for ReaderThatWillTimeOut<'a> { + /// fn read(&mut self, buf: &mut [u8]) -> io::Result { + /// if self.0.is_empty() { + /// Err(io::Error::new(ErrorKind::TimedOut, "timed out")) + /// } else { + /// self.0.read(buf) + /// } + /// } + /// } + /// + /// fn main() { + /// let reader = ReaderThatWillTimeOut(br#" {"k": "#); + /// + /// let _: Value = match serde_json::from_reader(reader) { + /// Ok(value) => value, + /// Err(error) => { + /// if error.io_error_kind() == Some(ErrorKind::TimedOut) { + /// // Maybe this application needs to retry certain kinds of errors. + /// + /// # return; + /// } else { + /// eprintln!("error: {}", error); + /// process::exit(1); + /// } + /// } + /// }; + /// } + /// ``` + #[cfg(feature = "std")] + pub fn io_error_kind(&self) -> Option { + if let ErrorCode::Io(io_error) = &self.err.code { + Some(io_error.kind()) + } else { + None + } + } +} + +/// Categorizes the cause of a `serde_json::Error`. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum Category { + /// The error was caused by a failure to read or write bytes on an I/O + /// stream. + Io, + + /// The error was caused by input that was not syntactically valid JSON. + Syntax, + + /// The error was caused by input data that was semantically incorrect. + /// + /// For example, JSON containing a number is semantically incorrect when the + /// type being deserialized into holds a String. + Data, + + /// The error was caused by prematurely reaching the end of the input data. + /// + /// Callers that process streaming input may be interested in retrying the + /// deserialization once more data is available. + Eof, +} + +#[cfg(feature = "std")] +#[allow(clippy::fallible_impl_from)] +impl From for io::Error { + /// Convert a `serde_json::Error` into an `io::Error`. + /// + /// JSON syntax and data errors are turned into `InvalidData` I/O errors. + /// EOF errors are turned into `UnexpectedEof` I/O errors. + /// + /// ``` + /// use std::io; + /// + /// enum MyError { + /// Io(io::Error), + /// Json(serde_json::Error), + /// } + /// + /// impl From for MyError { + /// fn from(err: serde_json::Error) -> MyError { + /// use serde_json::error::Category; + /// match err.classify() { + /// Category::Io => { + /// MyError::Io(err.into()) + /// } + /// Category::Syntax | Category::Data | Category::Eof => { + /// MyError::Json(err) + /// } + /// } + /// } + /// } + /// ``` + fn from(j: Error) -> Self { + if let ErrorCode::Io(err) = j.err.code { + err + } else { + match j.classify() { + Category::Io => unreachable!(), + Category::Syntax | Category::Data => io::Error::new(ErrorKind::InvalidData, j), + Category::Eof => io::Error::new(ErrorKind::UnexpectedEof, j), + } + } + } +} + +struct ErrorImpl { + code: ErrorCode, + line: usize, + column: usize, +} + +pub(crate) enum ErrorCode { + /// Catchall for syntax error messages + Message(Box), + + /// Some I/O error occurred while serializing or deserializing. + Io(io::Error), + + /// EOF while parsing a list. + EofWhileParsingList, + + /// EOF while parsing an object. + EofWhileParsingObject, + + /// EOF while parsing a string. + EofWhileParsingString, + + /// EOF while parsing a JSON value. + EofWhileParsingValue, + + /// Expected this character to be a `':'`. + ExpectedColon, + + /// Expected this character to be either a `','` or a `']'`. + ExpectedListCommaOrEnd, + + /// Expected this character to be either a `','` or a `'}'`. + ExpectedObjectCommaOrEnd, + + /// Expected to parse either a `true`, `false`, or a `null`. + ExpectedSomeIdent, + + /// Expected this character to start a JSON value. + ExpectedSomeValue, + + /// Expected this character to be a `"`. + ExpectedDoubleQuote, + + /// Invalid hex escape code. + InvalidEscape, + + /// Invalid number. + InvalidNumber, + + /// Number is bigger than the maximum value of its type. + NumberOutOfRange, + + /// Invalid unicode code point. + InvalidUnicodeCodePoint, + + /// Control character found while parsing a string. + ControlCharacterWhileParsingString, + + /// Object key is not a string. + KeyMustBeAString, + + /// Contents of key were supposed to be a number. + ExpectedNumericKey, + + /// Object key is a non-finite float value. + FloatKeyMustBeFinite, + + /// Lone leading surrogate in hex escape. + LoneLeadingSurrogateInHexEscape, + + /// JSON has a comma after the last value in an array or map. + TrailingComma, + + /// JSON has non-whitespace trailing characters after the value. + TrailingCharacters, + + /// Unexpected end of hex escape. + UnexpectedEndOfHexEscape, + + /// Encountered nesting of JSON maps and arrays more than 128 layers deep. + RecursionLimitExceeded, +} + +impl Error { + #[cold] + pub(crate) fn syntax(code: ErrorCode, line: usize, column: usize) -> Self { + Error { + err: Box::new(ErrorImpl { code, line, column }), + } + } + + // Not public API. Should be pub(crate). + // + // Update `eager_json` crate when this function changes. + #[doc(hidden)] + #[cold] + pub fn io(error: io::Error) -> Self { + Error { + err: Box::new(ErrorImpl { + code: ErrorCode::Io(error), + line: 0, + column: 0, + }), + } + } + + #[cold] + pub(crate) fn fix_position(self, f: F) -> Self + where + F: FnOnce(ErrorCode) -> Error, + { + if self.err.line == 0 { + f(self.err.code) + } else { + self + } + } +} + +impl Display for ErrorCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + ErrorCode::Message(msg) => f.write_str(msg), + ErrorCode::Io(err) => Display::fmt(err, f), + ErrorCode::EofWhileParsingList => f.write_str("EOF while parsing a list"), + ErrorCode::EofWhileParsingObject => f.write_str("EOF while parsing an object"), + ErrorCode::EofWhileParsingString => f.write_str("EOF while parsing a string"), + ErrorCode::EofWhileParsingValue => f.write_str("EOF while parsing a value"), + ErrorCode::ExpectedColon => f.write_str("expected `:`"), + ErrorCode::ExpectedListCommaOrEnd => f.write_str("expected `,` or `]`"), + ErrorCode::ExpectedObjectCommaOrEnd => f.write_str("expected `,` or `}`"), + ErrorCode::ExpectedSomeIdent => f.write_str("expected ident"), + ErrorCode::ExpectedSomeValue => f.write_str("expected value"), + ErrorCode::ExpectedDoubleQuote => f.write_str("expected `\"`"), + ErrorCode::InvalidEscape => f.write_str("invalid escape"), + ErrorCode::InvalidNumber => f.write_str("invalid number"), + ErrorCode::NumberOutOfRange => f.write_str("number out of range"), + ErrorCode::InvalidUnicodeCodePoint => f.write_str("invalid unicode code point"), + ErrorCode::ControlCharacterWhileParsingString => { + f.write_str("control character (\\u0000-\\u001F) found while parsing a string") + } + ErrorCode::KeyMustBeAString => f.write_str("key must be a string"), + ErrorCode::ExpectedNumericKey => { + f.write_str("invalid value: expected key to be a number in quotes") + } + ErrorCode::FloatKeyMustBeFinite => { + f.write_str("float key must be finite (got NaN or +/-inf)") + } + ErrorCode::LoneLeadingSurrogateInHexEscape => { + f.write_str("lone leading surrogate in hex escape") + } + ErrorCode::TrailingComma => f.write_str("trailing comma"), + ErrorCode::TrailingCharacters => f.write_str("trailing characters"), + ErrorCode::UnexpectedEndOfHexEscape => f.write_str("unexpected end of hex escape"), + ErrorCode::RecursionLimitExceeded => f.write_str("recursion limit exceeded"), + } + } +} + +impl serde::de::StdError for Error { + #[cfg(feature = "std")] + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + match &self.err.code { + ErrorCode::Io(err) => err.source(), + _ => None, + } + } +} + +impl Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&*self.err, f) + } +} + +impl Display for ErrorImpl { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.line == 0 { + Display::fmt(&self.code, f) + } else { + write!( + f, + "{} at line {} column {}", + self.code, self.line, self.column + ) + } + } +} + +// Remove two layers of verbosity from the debug representation. Humans often +// end up seeing this representation because it is what unwrap() shows. +impl Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "Error({:?}, line: {}, column: {})", + self.err.code.to_string(), + self.err.line, + self.err.column + ) + } +} + +impl de::Error for Error { + #[cold] + fn custom(msg: T) -> Error { + make_error(msg.to_string()) + } + + #[cold] + fn invalid_type(unexp: de::Unexpected, exp: &dyn de::Expected) -> Self { + Error::custom(format_args!( + "invalid type: {}, expected {}", + JsonUnexpected(unexp), + exp, + )) + } + + #[cold] + fn invalid_value(unexp: de::Unexpected, exp: &dyn de::Expected) -> Self { + Error::custom(format_args!( + "invalid value: {}, expected {}", + JsonUnexpected(unexp), + exp, + )) + } +} + +impl ser::Error for Error { + #[cold] + fn custom(msg: T) -> Error { + make_error(msg.to_string()) + } +} + +struct JsonUnexpected<'a>(de::Unexpected<'a>); + +impl<'a> Display for JsonUnexpected<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + de::Unexpected::Unit => formatter.write_str("null"), + de::Unexpected::Float(value) => write!( + formatter, + "floating point `{}`", + zmij::Buffer::new().format(value), + ), + unexp => Display::fmt(&unexp, formatter), + } + } +} + +// Parse our own error message that looks like "{} at line {} column {}" to work +// around erased-serde round-tripping the error through de::Error::custom. +fn make_error(mut msg: String) -> Error { + let (line, column) = parse_line_col(&mut msg).unwrap_or((0, 0)); + Error { + err: Box::new(ErrorImpl { + code: ErrorCode::Message(msg.into_boxed_str()), + line, + column, + }), + } +} + +fn parse_line_col(msg: &mut String) -> Option<(usize, usize)> { + let start_of_suffix = match msg.rfind(" at line ") { + Some(index) => index, + None => return None, + }; + + // Find start and end of line number. + let start_of_line = start_of_suffix + " at line ".len(); + let mut end_of_line = start_of_line; + while starts_with_digit(&msg[end_of_line..]) { + end_of_line += 1; + } + + if !msg[end_of_line..].starts_with(" column ") { + return None; + } + + // Find start and end of column number. + let start_of_column = end_of_line + " column ".len(); + let mut end_of_column = start_of_column; + while starts_with_digit(&msg[end_of_column..]) { + end_of_column += 1; + } + + if end_of_column < msg.len() { + return None; + } + + // Parse numbers. + let line = match usize::from_str(&msg[start_of_line..end_of_line]) { + Ok(line) => line, + Err(_) => return None, + }; + let column = match usize::from_str(&msg[start_of_column..end_of_column]) { + Ok(column) => column, + Err(_) => return None, + }; + + msg.truncate(start_of_suffix); + Some((line, column)) +} + +fn starts_with_digit(slice: &str) -> bool { + match slice.as_bytes().first() { + None => false, + Some(&byte) => byte >= b'0' && byte <= b'9', + } +} diff --git a/third_party/crates/serde_json-1.0.151/src/io/core.rs b/third_party/crates/serde_json-1.0.151/src/io/core.rs new file mode 100644 index 0000000..54c8ddf --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/io/core.rs @@ -0,0 +1,79 @@ +//! Reimplements core logic and types from `std::io` in an `alloc`-friendly +//! fashion. + +use alloc::vec::Vec; +use core::fmt::{self, Display}; +use core::result; + +pub enum ErrorKind { + Other, +} + +// I/O errors can never occur in no-std mode. All our no-std I/O implementations +// are infallible. +pub struct Error; + +impl Display for Error { + fn fmt(&self, _formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + unreachable!() + } +} + +impl Error { + pub(crate) fn new(_kind: ErrorKind, _error: &'static str) -> Error { + Error + } +} + +pub type Result = result::Result; + +pub trait Write { + fn write(&mut self, buf: &[u8]) -> Result; + + fn write_all(&mut self, buf: &[u8]) -> Result<()> { + // All our Write impls in no_std mode always write the whole buffer in + // one call infallibly. + let result = self.write(buf); + debug_assert!(result.is_ok()); + debug_assert_eq!(result.unwrap_or(0), buf.len()); + Ok(()) + } + + fn flush(&mut self) -> Result<()>; +} + +impl Write for &mut W { + #[inline] + fn write(&mut self, buf: &[u8]) -> Result { + (*self).write(buf) + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> Result<()> { + (*self).write_all(buf) + } + + #[inline] + fn flush(&mut self) -> Result<()> { + (*self).flush() + } +} + +impl Write for Vec { + #[inline] + fn write(&mut self, buf: &[u8]) -> Result { + self.extend_from_slice(buf); + Ok(buf.len()) + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> Result<()> { + self.extend_from_slice(buf); + Ok(()) + } + + #[inline] + fn flush(&mut self) -> Result<()> { + Ok(()) + } +} diff --git a/third_party/crates/serde_json-1.0.151/src/io/mod.rs b/third_party/crates/serde_json-1.0.151/src/io/mod.rs new file mode 100644 index 0000000..9dee4a0 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/io/mod.rs @@ -0,0 +1,20 @@ +//! A tiny, `no_std`-friendly facade around `std::io`. +//! Reexports types from `std` when available; otherwise reimplements and +//! provides some of the core logic. +//! +//! The main reason that `std::io` hasn't found itself reexported as part of +//! the `core` crate is the `std::io::{Read, Write}` traits' reliance on +//! `std::io::Error`, which may contain internally a heap-allocated `Box` +//! and/or now relying on OS-specific `std::backtrace::Backtrace`. + +pub use self::imp::{Error, ErrorKind, Result, Write}; + +#[cfg(not(feature = "std"))] +#[path = "core.rs"] +mod imp; + +#[cfg(feature = "std")] +use std::io as imp; + +#[cfg(feature = "std")] +pub use std::io::{Bytes, Read}; diff --git a/third_party/crates/serde_json-1.0.151/src/iter.rs b/third_party/crates/serde_json-1.0.151/src/iter.rs new file mode 100644 index 0000000..9792916 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/iter.rs @@ -0,0 +1,70 @@ +use crate::io; + +pub struct LineColIterator { + iter: I, + + /// Index of the current line. Characters in the first line of the input + /// (before the first newline character) are in line 1. + line: usize, + + /// Index of the current column. The first character in the input and any + /// characters immediately following a newline character are in column 1. + /// The column is 0 immediately after a newline character has been read. + col: usize, + + /// Byte offset of the start of the current line. This is the sum of lengths + /// of all previous lines. Keeping track of things this way allows efficient + /// computation of the current line, column, and byte offset while only + /// updating one of the counters in `next()` in the common case. + start_of_line: usize, +} + +impl LineColIterator +where + I: Iterator>, +{ + pub fn new(iter: I) -> LineColIterator { + LineColIterator { + iter, + line: 1, + col: 0, + start_of_line: 0, + } + } + + pub fn line(&self) -> usize { + self.line + } + + pub fn col(&self) -> usize { + self.col + } + + pub fn byte_offset(&self) -> usize { + self.start_of_line + self.col + } +} + +impl Iterator for LineColIterator +where + I: Iterator>, +{ + type Item = io::Result; + + fn next(&mut self) -> Option> { + match self.iter.next() { + None => None, + Some(Ok(b'\n')) => { + self.start_of_line += self.col + 1; + self.line += 1; + self.col = 0; + Some(Ok(b'\n')) + } + Some(Ok(c)) => { + self.col += 1; + Some(Ok(c)) + } + Some(Err(e)) => Some(Err(e)), + } + } +} diff --git a/third_party/crates/serde_json-1.0.151/src/lexical/algorithm.rs b/third_party/crates/serde_json-1.0.151/src/lexical/algorithm.rs new file mode 100644 index 0000000..2148ad5 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/lexical/algorithm.rs @@ -0,0 +1,195 @@ +// Adapted from https://github.com/Alexhuszagh/rust-lexical. + +//! Algorithms to efficiently convert strings to floats. + +use super::bhcomp::*; +use super::cached::*; +use super::errors::*; +use super::float::ExtendedFloat; +use super::num::*; +use super::small_powers::*; + +// FAST +// ---- + +/// Convert mantissa to exact value for a non-base2 power. +/// +/// Returns the resulting float and if the value can be represented exactly. +pub(crate) fn fast_path(mantissa: u64, exponent: i32) -> Option +where + F: Float, +{ + // `mantissa >> (F::MANTISSA_SIZE+1) != 0` effectively checks if the + // value has a no bits above the hidden bit, which is what we want. + let (min_exp, max_exp) = F::exponent_limit(); + let shift_exp = F::mantissa_limit(); + let mantissa_size = F::MANTISSA_SIZE + 1; + if mantissa == 0 { + Some(F::ZERO) + } else if mantissa >> mantissa_size != 0 { + // Would require truncation of the mantissa. + None + } else if exponent == 0 { + // 0 exponent, same as value, exact representation. + let float = F::as_cast(mantissa); + Some(float) + } else if exponent >= min_exp && exponent <= max_exp { + // Value can be exactly represented, return the value. + // Do not use powi, since powi can incrementally introduce + // error. + let float = F::as_cast(mantissa); + Some(float.pow10(exponent)) + } else if exponent >= 0 && exponent <= max_exp + shift_exp { + // Check to see if we have a disguised fast-path, where the + // number of digits in the mantissa is very small, but and + // so digits can be shifted from the exponent to the mantissa. + // https://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ + let small_powers = POW10_64; + let shift = exponent - max_exp; + let power = small_powers[shift as usize]; + + // Compute the product of the power, if it overflows, + // prematurely return early, otherwise, if we didn't overshoot, + // we can get an exact value. + let Some(value) = mantissa.checked_mul(power) else { + return None; + }; + if value >> mantissa_size != 0 { + None + } else { + // Use powi, since it's correct, and faster on + // the fast-path. + let float = F::as_cast(value); + Some(float.pow10(max_exp)) + } + } else { + // Cannot be exactly represented, exponent too small or too big, + // would require truncation. + None + } +} + +// MODERATE +// -------- + +/// Multiply the floating-point by the exponent. +/// +/// Multiply by pre-calculated powers of the base, modify the extended- +/// float, and return if new value and if the value can be represented +/// accurately. +fn multiply_exponent_extended(fp: &mut ExtendedFloat, exponent: i32, truncated: bool) -> bool +where + F: Float, +{ + let powers = ExtendedFloat::get_powers(); + let exponent = exponent.saturating_add(powers.bias); + let small_index = exponent % powers.step; + let large_index = exponent / powers.step; + if exponent < 0 { + // Guaranteed underflow (assign 0). + fp.mant = 0; + true + } else if large_index as usize >= powers.large.len() { + // Overflow (assign infinity) + fp.mant = 1 << 63; + fp.exp = 0x7FF; + true + } else { + // Within the valid exponent range, multiply by the large and small + // exponents and return the resulting value. + + // Track errors to as a factor of unit in last-precision. + let mut errors: u32 = 0; + if truncated { + errors += u64::error_halfscale(); + } + + // Multiply by the small power. + // Check if we can directly multiply by an integer, if not, + // use extended-precision multiplication. + match fp + .mant + .overflowing_mul(powers.get_small_int(small_index as usize)) + { + // Overflow, multiplication unsuccessful, go slow path. + (_, true) => { + fp.normalize(); + fp.imul(&powers.get_small(small_index as usize)); + errors += u64::error_halfscale(); + } + // No overflow, multiplication successful. + (mant, false) => { + fp.mant = mant; + fp.normalize(); + } + } + + // Multiply by the large power + fp.imul(&powers.get_large(large_index as usize)); + if errors > 0 { + errors += 1; + } + errors += u64::error_halfscale(); + + // Normalize the floating point (and the errors). + let shift = fp.normalize(); + errors <<= shift; + + u64::error_is_accurate::(errors, fp) + } +} + +/// Create a precise native float using an intermediate extended-precision float. +/// +/// Return the float approximation and if the value can be accurately +/// represented with mantissa bits of precision. +#[inline] +pub(crate) fn moderate_path( + mantissa: u64, + exponent: i32, + truncated: bool, +) -> (ExtendedFloat, bool) +where + F: Float, +{ + let mut fp = ExtendedFloat { + mant: mantissa, + exp: 0, + }; + let valid = multiply_exponent_extended::(&mut fp, exponent, truncated); + (fp, valid) +} + +// FALLBACK +// -------- + +/// Fallback path when the fast path does not work. +/// +/// Uses the moderate path, if applicable, otherwise, uses the slow path +/// as required. +pub(crate) fn fallback_path( + integer: &[u8], + fraction: &[u8], + mantissa: u64, + exponent: i32, + mantissa_exponent: i32, + truncated: bool, +) -> F +where + F: Float, +{ + // Moderate path (use an extended 80-bit representation). + let (fp, valid) = moderate_path::(mantissa, mantissa_exponent, truncated); + if valid { + return fp.into_float::(); + } + + // Slow path, fast path didn't work. + let b = fp.into_downward_float::(); + if b.is_special() { + // We have a non-finite number, we get to leave early. + b + } else { + bhcomp(b, integer, fraction, exponent) + } +} diff --git a/third_party/crates/serde_json-1.0.151/src/lexical/bhcomp.rs b/third_party/crates/serde_json-1.0.151/src/lexical/bhcomp.rs new file mode 100644 index 0000000..e52b1c9 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/lexical/bhcomp.rs @@ -0,0 +1,218 @@ +// Adapted from https://github.com/Alexhuszagh/rust-lexical. + +//! Compare the mantissa to the halfway representation of the float. +//! +//! Compares the actual significant digits of the mantissa to the +//! theoretical digits from `b+h`, scaled into the proper range. + +use super::bignum::*; +use super::digit::*; +use super::exponent::*; +use super::float::*; +use super::math::*; +use super::num::*; +use super::rounding::*; +use core::{cmp, mem}; + +// MANTISSA + +/// Parse the full mantissa into a big integer. +/// +/// Max digits is the maximum number of digits plus one. +fn parse_mantissa(integer: &[u8], fraction: &[u8]) -> Bigint +where + F: Float, +{ + // Main loop + let small_powers = POW10_LIMB; + let step = small_powers.len() - 2; + let max_digits = F::MAX_DIGITS - 1; + let mut counter = 0; + let mut value: Limb = 0; + let mut i: usize = 0; + let mut result = Bigint::default(); + + // Iteratively process all the data in the mantissa. + for &digit in integer.iter().chain(fraction) { + // We've parsed the max digits using small values, add to bignum + if counter == step { + result.imul_small(small_powers[counter]); + result.iadd_small(value); + counter = 0; + value = 0; + } + + value *= 10; + value += as_limb(to_digit(digit).unwrap()); + + i += 1; + counter += 1; + if i == max_digits { + break; + } + } + + // We will always have a remainder, as long as we entered the loop + // once, or counter % step is 0. + if counter != 0 { + result.imul_small(small_powers[counter]); + result.iadd_small(value); + } + + // If we have any remaining digits after the last value, we need + // to add a 1 after the rest of the array, it doesn't matter where, + // just move it up. This is good for the worst-possible float + // representation. We also need to return an index. + // Since we already trimmed trailing zeros, we know there has + // to be a non-zero digit if there are any left. + if i < integer.len() + fraction.len() { + result.imul_small(10); + result.iadd_small(1); + } + + result +} + +// FLOAT OPS + +/// Calculate `b` from a representation of `b` as a float. +#[inline] +pub(super) fn b_extended(f: F) -> ExtendedFloat { + ExtendedFloat::from_float(f) +} + +/// Calculate `b+h` from a representation of `b` as a float. +#[inline] +pub(super) fn bh_extended(f: F) -> ExtendedFloat { + // None of these can overflow. + let b = b_extended(f); + ExtendedFloat { + mant: (b.mant << 1) + 1, + exp: b.exp - 1, + } +} + +// ROUNDING + +/// Custom round-nearest, tie-event algorithm for bhcomp. +#[inline] +fn round_nearest_tie_even(fp: &mut ExtendedFloat, shift: i32, is_truncated: bool) { + let (mut is_above, mut is_halfway) = round_nearest(fp, shift); + if is_halfway && is_truncated { + is_above = true; + is_halfway = false; + } + tie_even(fp, is_above, is_halfway); +} + +// BHCOMP + +/// Calculate the mantissa for a big integer with a positive exponent. +fn large_atof(mantissa: Bigint, exponent: i32) -> F +where + F: Float, +{ + let bits = mem::size_of::() * 8; + + // Simple, we just need to multiply by the power of the radix. + // Now, we can calculate the mantissa and the exponent from this. + // The binary exponent is the binary exponent for the mantissa + // shifted to the hidden bit. + let mut bigmant = mantissa; + bigmant.imul_pow10(exponent as u32); + + // Get the exact representation of the float from the big integer. + let (mant, is_truncated) = bigmant.hi64(); + let exp = bigmant.bit_length() as i32 - bits as i32; + let mut fp = ExtendedFloat { mant, exp }; + fp.round_to_native::(|fp, shift| round_nearest_tie_even(fp, shift, is_truncated)); + into_float(fp) +} + +/// Calculate the mantissa for a big integer with a negative exponent. +/// +/// This invokes the comparison with `b+h`. +fn small_atof(mantissa: Bigint, exponent: i32, f: F) -> F +where + F: Float, +{ + // Get the significant digits and radix exponent for the real digits. + let mut real_digits = mantissa; + let real_exp = exponent; + debug_assert!(real_exp < 0); + + // Get the significant digits and the binary exponent for `b+h`. + let theor = bh_extended(f); + let mut theor_digits = Bigint::from_u64(theor.mant); + let theor_exp = theor.exp; + + // We need to scale the real digits and `b+h` digits to be the same + // order. We currently have `real_exp`, in `radix`, that needs to be + // shifted to `theor_digits` (since it is negative), and `theor_exp` + // to either `theor_digits` or `real_digits` as a power of 2 (since it + // may be positive or negative). Try to remove as many powers of 2 + // as possible. All values are relative to `theor_digits`, that is, + // reflect the power you need to multiply `theor_digits` by. + + // Can remove a power-of-two, since the radix is 10. + // Both are on opposite-sides of equation, can factor out a + // power of two. + // + // Example: 10^-10, 2^-10 -> ( 0, 10, 0) + // Example: 10^-10, 2^-15 -> (-5, 10, 0) + // Example: 10^-10, 2^-5 -> ( 5, 10, 0) + // Example: 10^-10, 2^5 -> (15, 10, 0) + let binary_exp = theor_exp - real_exp; + let halfradix_exp = -real_exp; + let radix_exp = 0; + + // Carry out our multiplication. + if halfradix_exp != 0 { + theor_digits.imul_pow5(halfradix_exp as u32); + } + if radix_exp != 0 { + theor_digits.imul_pow10(radix_exp as u32); + } + if binary_exp > 0 { + theor_digits.imul_pow2(binary_exp as u32); + } else if binary_exp < 0 { + real_digits.imul_pow2(-binary_exp as u32); + } + + // Compare real digits to theoretical digits and round the float. + match real_digits.compare(&theor_digits) { + cmp::Ordering::Greater => f.next_positive(), + cmp::Ordering::Less => f, + cmp::Ordering::Equal => f.round_positive_even(), + } +} + +/// Calculate the exact value of the float. +/// +/// Note: fraction must not have trailing zeros. +pub(crate) fn bhcomp(b: F, integer: &[u8], mut fraction: &[u8], exponent: i32) -> F +where + F: Float, +{ + // Calculate the number of integer digits and use that to determine + // where the significant digits start in the fraction. + let integer_digits = integer.len(); + let fraction_digits = fraction.len(); + let digits_start = if integer_digits == 0 { + let start = fraction.iter().take_while(|&x| *x == b'0').count(); + fraction = &fraction[start..]; + start + } else { + 0 + }; + let sci_exp = scientific_exponent(exponent, integer_digits, digits_start); + let count = F::MAX_DIGITS.min(integer_digits + fraction_digits - digits_start); + let scaled_exponent = sci_exp + 1 - count as i32; + + let mantissa = parse_mantissa::(integer, fraction); + if scaled_exponent >= 0 { + large_atof(mantissa, scaled_exponent) + } else { + small_atof(mantissa, scaled_exponent, b) + } +} diff --git a/third_party/crates/serde_json-1.0.151/src/lexical/bignum.rs b/third_party/crates/serde_json-1.0.151/src/lexical/bignum.rs new file mode 100644 index 0000000..4fa7eed --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/lexical/bignum.rs @@ -0,0 +1,34 @@ +// Adapted from https://github.com/Alexhuszagh/rust-lexical. + +//! Big integer type definition. + +use super::math::*; +#[allow(unused_imports)] +use alloc::vec::Vec; + +/// Storage for a big integer type. +#[derive(Clone, PartialEq, Eq)] +pub(crate) struct Bigint { + /// Internal storage for the Bigint, in little-endian order. + pub(crate) data: Vec, +} + +impl Default for Bigint { + fn default() -> Self { + Bigint { + data: Vec::with_capacity(20), + } + } +} + +impl Math for Bigint { + #[inline] + fn data(&self) -> &Vec { + &self.data + } + + #[inline] + fn data_mut(&mut self) -> &mut Vec { + &mut self.data + } +} diff --git a/third_party/crates/serde_json-1.0.151/src/lexical/cached.rs b/third_party/crates/serde_json-1.0.151/src/lexical/cached.rs new file mode 100644 index 0000000..ef5a9fe --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/lexical/cached.rs @@ -0,0 +1,82 @@ +// Adapted from https://github.com/Alexhuszagh/rust-lexical. + +//! Cached powers trait for extended-precision floats. + +use super::cached_float80; +use super::float::ExtendedFloat; + +// POWERS + +/// Precalculated powers that uses two-separate arrays for memory-efficiency. +#[doc(hidden)] +pub(crate) struct ExtendedFloatArray { + // Pre-calculated mantissa for the powers. + pub mant: &'static [u64], + // Pre-calculated binary exponents for the powers. + pub exp: &'static [i32], +} + +/// Allow indexing of values without bounds checking +impl ExtendedFloatArray { + #[inline] + pub fn get_extended_float(&self, index: usize) -> ExtendedFloat { + let mant = self.mant[index]; + let exp = self.exp[index]; + ExtendedFloat { mant, exp } + } + + #[inline] + pub fn len(&self) -> usize { + self.mant.len() + } +} + +// MODERATE PATH POWERS + +/// Precalculated powers of base N for the moderate path. +#[doc(hidden)] +pub(crate) struct ModeratePathPowers { + // Pre-calculated small powers. + pub small: ExtendedFloatArray, + // Pre-calculated large powers. + pub large: ExtendedFloatArray, + /// Pre-calculated small powers as 64-bit integers + pub small_int: &'static [u64], + // Step between large powers and number of small powers. + pub step: i32, + // Exponent bias for the large powers. + pub bias: i32, +} + +/// Allow indexing of values without bounds checking +impl ModeratePathPowers { + #[inline] + pub fn get_small(&self, index: usize) -> ExtendedFloat { + self.small.get_extended_float(index) + } + + #[inline] + pub fn get_large(&self, index: usize) -> ExtendedFloat { + self.large.get_extended_float(index) + } + + #[inline] + pub fn get_small_int(&self, index: usize) -> u64 { + self.small_int[index] + } +} + +// CACHED EXTENDED POWERS + +/// Cached powers as a trait for a floating-point type. +pub(crate) trait ModeratePathCache { + /// Get cached powers. + fn get_powers() -> &'static ModeratePathPowers; +} + +impl ModeratePathCache for ExtendedFloat { + #[inline] + fn get_powers() -> &'static ModeratePathPowers { + cached_float80::get_powers() + } +} diff --git a/third_party/crates/serde_json-1.0.151/src/lexical/cached_float80.rs b/third_party/crates/serde_json-1.0.151/src/lexical/cached_float80.rs new file mode 100644 index 0000000..9beda3d --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/lexical/cached_float80.rs @@ -0,0 +1,206 @@ +// Adapted from https://github.com/Alexhuszagh/rust-lexical. + +//! Cached exponents for basen values with 80-bit extended floats. +//! +//! Exact versions of base**n as an extended-precision float, with both +//! large and small powers. Use the large powers to minimize the amount +//! of compounded error. +//! +//! These values were calculated using Python, using the arbitrary-precision +//! integer to calculate exact extended-representation of each value. +//! These values are all normalized. + +use super::cached::{ExtendedFloatArray, ModeratePathPowers}; + +// LOW-LEVEL +// --------- + +// BASE10 + +const BASE10_SMALL_MANTISSA: [u64; 10] = [ + 9223372036854775808, // 10^0 + 11529215046068469760, // 10^1 + 14411518807585587200, // 10^2 + 18014398509481984000, // 10^3 + 11258999068426240000, // 10^4 + 14073748835532800000, // 10^5 + 17592186044416000000, // 10^6 + 10995116277760000000, // 10^7 + 13743895347200000000, // 10^8 + 17179869184000000000, // 10^9 +]; +const BASE10_SMALL_EXPONENT: [i32; 10] = [ + -63, // 10^0 + -60, // 10^1 + -57, // 10^2 + -54, // 10^3 + -50, // 10^4 + -47, // 10^5 + -44, // 10^6 + -40, // 10^7 + -37, // 10^8 + -34, // 10^9 +]; +const BASE10_LARGE_MANTISSA: [u64; 66] = [ + 11555125961253852697, // 10^-350 + 13451937075301367670, // 10^-340 + 15660115838168849784, // 10^-330 + 18230774251475056848, // 10^-320 + 10611707258198326947, // 10^-310 + 12353653155963782858, // 10^-300 + 14381545078898527261, // 10^-290 + 16742321987285426889, // 10^-280 + 9745314011399999080, // 10^-270 + 11345038669416679861, // 10^-260 + 13207363278391631158, // 10^-250 + 15375394465392026070, // 10^-240 + 17899314949046850752, // 10^-230 + 10418772551374772303, // 10^-220 + 12129047596099288555, // 10^-210 + 14120069793541087484, // 10^-200 + 16437924692338667210, // 10^-190 + 9568131466127621947, // 10^-180 + 11138771039116687545, // 10^-170 + 12967236152753102995, // 10^-160 + 15095849699286165408, // 10^-150 + 17573882009934360870, // 10^-140 + 10229345649675443343, // 10^-130 + 11908525658859223294, // 10^-120 + 13863348470604074297, // 10^-110 + 16139061738043178685, // 10^-100 + 9394170331095332911, // 10^-90 + 10936253623915059621, // 10^-80 + 12731474852090538039, // 10^-70 + 14821387422376473014, // 10^-60 + 17254365866976409468, // 10^-50 + 10043362776618689222, // 10^-40 + 11692013098647223345, // 10^-30 + 13611294676837538538, // 10^-20 + 15845632502852867518, // 10^-10 + 9223372036854775808, // 10^0 + 10737418240000000000, // 10^10 + 12500000000000000000, // 10^20 + 14551915228366851806, // 10^30 + 16940658945086006781, // 10^40 + 9860761315262647567, // 10^50 + 11479437019748901445, // 10^60 + 13363823550460978230, // 10^70 + 15557538194652854267, // 10^80 + 18111358157653424735, // 10^90 + 10542197943230523224, // 10^100 + 12272733663244316382, // 10^110 + 14287342391028437277, // 10^120 + 16632655625031838749, // 10^130 + 9681479787123295682, // 10^140 + 11270725851789228247, // 10^150 + 13120851772591970218, // 10^160 + 15274681817498023410, // 10^170 + 17782069995880619867, // 10^180 + 10350527006597618960, // 10^190 + 12049599325514420588, // 10^200 + 14027579833653779454, // 10^210 + 16330252207878254650, // 10^220 + 9505457831475799117, // 10^230 + 11065809325636130661, // 10^240 + 12882297539194266616, // 10^250 + 14996968138956309548, // 10^260 + 17458768723248864463, // 10^270 + 10162340898095201970, // 10^280 + 11830521861667747109, // 10^290 + 13772540099066387756, // 10^300 +]; +const BASE10_LARGE_EXPONENT: [i32; 66] = [ + -1226, // 10^-350 + -1193, // 10^-340 + -1160, // 10^-330 + -1127, // 10^-320 + -1093, // 10^-310 + -1060, // 10^-300 + -1027, // 10^-290 + -994, // 10^-280 + -960, // 10^-270 + -927, // 10^-260 + -894, // 10^-250 + -861, // 10^-240 + -828, // 10^-230 + -794, // 10^-220 + -761, // 10^-210 + -728, // 10^-200 + -695, // 10^-190 + -661, // 10^-180 + -628, // 10^-170 + -595, // 10^-160 + -562, // 10^-150 + -529, // 10^-140 + -495, // 10^-130 + -462, // 10^-120 + -429, // 10^-110 + -396, // 10^-100 + -362, // 10^-90 + -329, // 10^-80 + -296, // 10^-70 + -263, // 10^-60 + -230, // 10^-50 + -196, // 10^-40 + -163, // 10^-30 + -130, // 10^-20 + -97, // 10^-10 + -63, // 10^0 + -30, // 10^10 + 3, // 10^20 + 36, // 10^30 + 69, // 10^40 + 103, // 10^50 + 136, // 10^60 + 169, // 10^70 + 202, // 10^80 + 235, // 10^90 + 269, // 10^100 + 302, // 10^110 + 335, // 10^120 + 368, // 10^130 + 402, // 10^140 + 435, // 10^150 + 468, // 10^160 + 501, // 10^170 + 534, // 10^180 + 568, // 10^190 + 601, // 10^200 + 634, // 10^210 + 667, // 10^220 + 701, // 10^230 + 734, // 10^240 + 767, // 10^250 + 800, // 10^260 + 833, // 10^270 + 867, // 10^280 + 900, // 10^290 + 933, // 10^300 +]; +const BASE10_SMALL_INT_POWERS: [u64; 10] = [ + 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, +]; +const BASE10_STEP: i32 = 10; +const BASE10_BIAS: i32 = 350; + +// HIGH LEVEL +// ---------- + +const BASE10_POWERS: ModeratePathPowers = ModeratePathPowers { + small: ExtendedFloatArray { + mant: &BASE10_SMALL_MANTISSA, + exp: &BASE10_SMALL_EXPONENT, + }, + large: ExtendedFloatArray { + mant: &BASE10_LARGE_MANTISSA, + exp: &BASE10_LARGE_EXPONENT, + }, + small_int: &BASE10_SMALL_INT_POWERS, + step: BASE10_STEP, + bias: BASE10_BIAS, +}; + +/// Get powers from base. +pub(crate) fn get_powers() -> &'static ModeratePathPowers { + &BASE10_POWERS +} diff --git a/third_party/crates/serde_json-1.0.151/src/lexical/digit.rs b/third_party/crates/serde_json-1.0.151/src/lexical/digit.rs new file mode 100644 index 0000000..3d150a1 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/lexical/digit.rs @@ -0,0 +1,18 @@ +// Adapted from https://github.com/Alexhuszagh/rust-lexical. + +//! Helpers to convert and add digits from characters. + +// Convert u8 to digit. +#[inline] +pub(crate) fn to_digit(c: u8) -> Option { + (c as char).to_digit(10) +} + +// Add digit to mantissa. +#[inline] +pub(crate) fn add_digit(value: u64, digit: u32) -> Option { + match value.checked_mul(10) { + None => None, + Some(n) => n.checked_add(digit as u64), + } +} diff --git a/third_party/crates/serde_json-1.0.151/src/lexical/errors.rs b/third_party/crates/serde_json-1.0.151/src/lexical/errors.rs new file mode 100644 index 0000000..f4f41cd --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/lexical/errors.rs @@ -0,0 +1,132 @@ +// Adapted from https://github.com/Alexhuszagh/rust-lexical. + +//! Estimate the error in an 80-bit approximation of a float. +//! +//! This estimates the error in a floating-point representation. +//! +//! This implementation is loosely based off the Golang implementation, +//! found here: + +use super::float::*; +use super::num::*; +use super::rounding::*; + +pub(crate) trait FloatErrors { + /// Get the full error scale. + fn error_scale() -> u32; + /// Get the half error scale. + fn error_halfscale() -> u32; + /// Determine if the number of errors is tolerable for float precision. + fn error_is_accurate(count: u32, fp: &ExtendedFloat) -> bool; +} + +/// Check if the error is accurate with a round-nearest rounding scheme. +#[inline] +fn nearest_error_is_accurate(errors: u64, fp: &ExtendedFloat, extrabits: u64) -> bool { + // Round-to-nearest, need to use the halfway point. + if extrabits == 65 { + // Underflow, we have a shift larger than the mantissa. + // Representation is valid **only** if the value is close enough + // overflow to the next bit within errors. If it overflows, + // the representation is **not** valid. + !fp.mant.overflowing_add(errors).1 + } else { + let mask: u64 = lower_n_mask(extrabits); + let extra: u64 = fp.mant & mask; + + // Round-to-nearest, need to check if we're close to halfway. + // IE, b10100 | 100000, where `|` signifies the truncation point. + let halfway: u64 = lower_n_halfway(extrabits); + let cmp1 = halfway.wrapping_sub(errors) < extra; + let cmp2 = extra < halfway.wrapping_add(errors); + + // If both comparisons are true, we have significant rounding error, + // and the value cannot be exactly represented. Otherwise, the + // representation is valid. + !(cmp1 && cmp2) + } +} + +impl FloatErrors for u64 { + #[inline] + fn error_scale() -> u32 { + 8 + } + + #[inline] + fn error_halfscale() -> u32 { + u64::error_scale() / 2 + } + + #[inline] + fn error_is_accurate(count: u32, fp: &ExtendedFloat) -> bool { + // Determine if extended-precision float is a good approximation. + // If the error has affected too many units, the float will be + // inaccurate, or if the representation is too close to halfway + // that any operations could affect this halfway representation. + // See the documentation for dtoa for more information. + let bias = -(F::EXPONENT_BIAS - F::MANTISSA_SIZE); + let denormal_exp = bias - 63; + // This is always a valid u32, since (denormal_exp - fp.exp) + // will always be positive and the significand size is {23, 52}. + let extrabits = if fp.exp <= denormal_exp { + 64 - F::MANTISSA_SIZE + denormal_exp - fp.exp + } else { + 63 - F::MANTISSA_SIZE + }; + + // Our logic is as follows: we want to determine if the actual + // mantissa and the errors during calculation differ significantly + // from the rounding point. The rounding point for round-nearest + // is the halfway point, IE, this when the truncated bits start + // with b1000..., while the rounding point for the round-toward + // is when the truncated bits are equal to 0. + // To do so, we can check whether the rounding point +/- the error + // are >/< the actual lower n bits. + // + // For whether we need to use signed or unsigned types for this + // analysis, see this example, using u8 rather than u64 to simplify + // things. + // + // # Comparisons + // cmp1 = (halfway - errors) < extra + // cmp1 = extra < (halfway + errors) + // + // # Large Extrabits, Low Errors + // + // extrabits = 8 + // halfway = 0b10000000 + // extra = 0b10000010 + // errors = 0b00000100 + // halfway - errors = 0b01111100 + // halfway + errors = 0b10000100 + // + // Unsigned: + // halfway - errors = 124 + // halfway + errors = 132 + // extra = 130 + // cmp1 = true + // cmp2 = true + // Signed: + // halfway - errors = 124 + // halfway + errors = -124 + // extra = -126 + // cmp1 = false + // cmp2 = true + // + // # Conclusion + // + // Since errors will always be small, and since we want to detect + // if the representation is accurate, we need to use an **unsigned** + // type for comparisons. + + let extrabits = extrabits as u64; + let errors = count as u64; + if extrabits > 65 { + // Underflow, we have a literal 0. + return true; + } + + nearest_error_is_accurate(errors, fp, extrabits) + } +} diff --git a/third_party/crates/serde_json-1.0.151/src/lexical/exponent.rs b/third_party/crates/serde_json-1.0.151/src/lexical/exponent.rs new file mode 100644 index 0000000..5e27de8 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/lexical/exponent.rs @@ -0,0 +1,50 @@ +// Adapted from https://github.com/Alexhuszagh/rust-lexical. + +//! Utilities to calculate exponents. + +/// Convert usize into i32 without overflow. +/// +/// This is needed to ensure when adjusting the exponent relative to +/// the mantissa we do not overflow for comically-long exponents. +#[inline] +fn into_i32(value: usize) -> i32 { + if value > i32::MAX as usize { + i32::MAX + } else { + value as i32 + } +} + +// EXPONENT CALCULATION + +// Calculate the scientific notation exponent without overflow. +// +// For example, 0.1 would be -1, and 10 would be 1 in base 10. +#[inline] +pub(crate) fn scientific_exponent( + exponent: i32, + integer_digits: usize, + fraction_start: usize, +) -> i32 { + if integer_digits == 0 { + let fraction_start = into_i32(fraction_start); + exponent.saturating_sub(fraction_start).saturating_sub(1) + } else { + let integer_shift = into_i32(integer_digits - 1); + exponent.saturating_add(integer_shift) + } +} + +// Calculate the mantissa exponent without overflow. +// +// Remove the number of digits that contributed to the mantissa past +// the dot, and add the number of truncated digits from the mantissa, +// to calculate the scaling factor for the mantissa from a raw exponent. +#[inline] +pub(crate) fn mantissa_exponent(exponent: i32, fraction_digits: usize, truncated: usize) -> i32 { + if fraction_digits > truncated { + exponent.saturating_sub(into_i32(fraction_digits - truncated)) + } else { + exponent.saturating_add(into_i32(truncated - fraction_digits)) + } +} diff --git a/third_party/crates/serde_json-1.0.151/src/lexical/float.rs b/third_party/crates/serde_json-1.0.151/src/lexical/float.rs new file mode 100644 index 0000000..2d434a2 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/lexical/float.rs @@ -0,0 +1,183 @@ +// Adapted from https://github.com/Alexhuszagh/rust-lexical. + +// FLOAT TYPE + +use super::num::*; +use super::rounding::*; +use super::shift::*; + +/// Extended precision floating-point type. +/// +/// Private implementation, exposed only for testing purposes. +#[doc(hidden)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) struct ExtendedFloat { + /// Mantissa for the extended-precision float. + pub mant: u64, + /// Binary exponent for the extended-precision float. + pub exp: i32, +} + +impl ExtendedFloat { + // PROPERTIES + + // OPERATIONS + + /// Multiply two normalized extended-precision floats, as if by `a*b`. + /// + /// The precision is maximal when the numbers are normalized, however, + /// decent precision will occur as long as both values have high bits + /// set. The result is not normalized. + /// + /// Algorithm: + /// 1. Non-signed multiplication of mantissas (requires 2x as many bits as input). + /// 2. Normalization of the result (not done here). + /// 3. Addition of exponents. + pub(crate) fn mul(&self, b: &ExtendedFloat) -> ExtendedFloat { + // Logic check, values must be decently normalized prior to multiplication. + debug_assert!((self.mant & u64::HIMASK != 0) && (b.mant & u64::HIMASK != 0)); + + // Extract high-and-low masks. + let ah = self.mant >> u64::HALF; + let al = self.mant & u64::LOMASK; + let bh = b.mant >> u64::HALF; + let bl = b.mant & u64::LOMASK; + + // Get our products + let ah_bl = ah * bl; + let al_bh = al * bh; + let al_bl = al * bl; + let ah_bh = ah * bh; + + let mut tmp = (ah_bl & u64::LOMASK) + (al_bh & u64::LOMASK) + (al_bl >> u64::HALF); + // round up + tmp += 1 << (u64::HALF - 1); + + ExtendedFloat { + mant: ah_bh + (ah_bl >> u64::HALF) + (al_bh >> u64::HALF) + (tmp >> u64::HALF), + exp: self.exp + b.exp + u64::FULL, + } + } + + /// Multiply in-place, as if by `a*b`. + /// + /// The result is not normalized. + #[inline] + pub(crate) fn imul(&mut self, b: &ExtendedFloat) { + *self = self.mul(b); + } + + // NORMALIZE + + /// Normalize float-point number. + /// + /// Shift the mantissa so the number of leading zeros is 0, or the value + /// itself is 0. + /// + /// Get the number of bytes shifted. + #[inline] + pub(crate) fn normalize(&mut self) -> u32 { + // Note: + // Using the cltz intrinsic via leading_zeros is way faster (~10x) + // than shifting 1-bit at a time, via while loop, and also way + // faster (~2x) than an unrolled loop that checks at 32, 16, 4, + // 2, and 1 bit. + // + // Using a modulus of pow2 (which will get optimized to a bitwise + // and with 0x3F or faster) is slightly slower than an if/then, + // however, removing the if/then will likely optimize more branched + // code as it removes conditional logic. + + // Calculate the number of leading zeros, and then zero-out + // any overflowing bits, to avoid shl overflow when self.mant == 0. + let shift = if self.mant == 0 { + 0 + } else { + self.mant.leading_zeros() + }; + shl(self, shift as i32); + shift + } + + // ROUND + + /// Lossy round float-point number to native mantissa boundaries. + #[inline] + pub(crate) fn round_to_native(&mut self, algorithm: Algorithm) + where + F: Float, + Algorithm: FnOnce(&mut ExtendedFloat, i32), + { + round_to_native::(self, algorithm); + } + + // FROM + + /// Create extended float from native float. + #[inline] + pub fn from_float(f: F) -> ExtendedFloat { + from_float(f) + } + + // INTO + + /// Convert into default-rounded, lower-precision native float. + #[inline] + pub(crate) fn into_float(mut self) -> F { + self.round_to_native::(round_nearest_tie_even); + into_float(self) + } + + /// Convert into downward-rounded, lower-precision native float. + #[inline] + pub(crate) fn into_downward_float(mut self) -> F { + self.round_to_native::(round_downward); + into_float(self) + } +} + +// FROM FLOAT + +// Import ExtendedFloat from native float. +#[inline] +pub(crate) fn from_float(f: F) -> ExtendedFloat +where + F: Float, +{ + ExtendedFloat { + mant: u64::as_cast(f.mantissa()), + exp: f.exponent(), + } +} + +// INTO FLOAT + +// Export extended-precision float to native float. +// +// The extended-precision float must be in native float representation, +// with overflow/underflow appropriately handled. +#[inline] +pub(crate) fn into_float(fp: ExtendedFloat) -> F +where + F: Float, +{ + // Export floating-point number. + if fp.mant == 0 || fp.exp < F::DENORMAL_EXPONENT { + // sub-denormal, underflow + F::ZERO + } else if fp.exp >= F::MAX_EXPONENT { + // overflow + F::from_bits(F::INFINITY_BITS) + } else { + // calculate the exp and fraction bits, and return a float from bits. + let exp: u64; + if (fp.exp == F::DENORMAL_EXPONENT) && (fp.mant & F::HIDDEN_BIT_MASK.as_u64()) == 0 { + exp = 0; + } else { + exp = (fp.exp + F::EXPONENT_BIAS) as u64; + } + let exp = exp << F::MANTISSA_SIZE; + let mant = fp.mant & F::MANTISSA_MASK.as_u64(); + F::from_bits(F::Unsigned::as_cast(mant | exp)) + } +} diff --git a/third_party/crates/serde_json-1.0.151/src/lexical/large_powers.rs b/third_party/crates/serde_json-1.0.151/src/lexical/large_powers.rs new file mode 100644 index 0000000..af2c8a6 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/lexical/large_powers.rs @@ -0,0 +1,9 @@ +// Adapted from https://github.com/Alexhuszagh/rust-lexical. + +//! Precalculated large powers for limbs. + +#[cfg(fast_arithmetic = "32")] +pub(crate) use super::large_powers32::*; + +#[cfg(fast_arithmetic = "64")] +pub(crate) use super::large_powers64::*; diff --git a/third_party/crates/serde_json-1.0.151/src/lexical/large_powers32.rs b/third_party/crates/serde_json-1.0.151/src/lexical/large_powers32.rs new file mode 100644 index 0000000..eb8582f --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/lexical/large_powers32.rs @@ -0,0 +1,183 @@ +// Adapted from https://github.com/Alexhuszagh/rust-lexical. + +//! Precalculated large powers for 32-bit limbs. + +/// Large powers (`&[u32]`) for base5 operations. +const POW5_1: [u32; 1] = [5]; +const POW5_2: [u32; 1] = [25]; +const POW5_3: [u32; 1] = [625]; +const POW5_4: [u32; 1] = [390625]; +const POW5_5: [u32; 2] = [2264035265, 35]; +const POW5_6: [u32; 3] = [2242703233, 762134875, 1262]; +const POW5_7: [u32; 5] = [3211403009, 1849224548, 3668416493, 3913284084, 1593091]; +const POW5_8: [u32; 10] = [ + 781532673, 64985353, 253049085, 594863151, 3553621484, 3288652808, 3167596762, 2788392729, + 3911132675, 590, +]; +const POW5_9: [u32; 19] = [ + 2553183233, 3201533787, 3638140786, 303378311, 1809731782, 3477761648, 3583367183, 649228654, + 2915460784, 487929380, 1011012442, 1677677582, 3428152256, 1710878487, 1438394610, 2161952759, + 4100910556, 1608314830, 349175, +]; +const POW5_10: [u32; 38] = [ + 4234999809, 2012377703, 2408924892, 1570150255, 3090844311, 3273530073, 1187251475, 2498123591, + 3364452033, 1148564857, 687371067, 2854068671, 1883165473, 505794538, 2988060450, 3159489326, + 2531348317, 3215191468, 849106862, 3892080979, 3288073877, 2242451748, 4183778142, 2995818208, + 2477501924, 325481258, 2487842652, 1774082830, 1933815724, 2962865281, 1168579910, 2724829000, + 2360374019, 2315984659, 2360052375, 3251779801, 1664357844, 28, +]; +const POW5_11: [u32; 75] = [ + 689565697, 4116392818, 1853628763, 516071302, 2568769159, 365238920, 336250165, 1283268122, + 3425490969, 248595470, 2305176814, 2111925499, 507770399, 2681111421, 589114268, 591287751, + 1708941527, 4098957707, 475844916, 3378731398, 2452339615, 2817037361, 2678008327, 1656645978, + 2383430340, 73103988, 448667107, 2329420453, 3124020241, 3625235717, 3208634035, 2412059158, + 2981664444, 4117622508, 838560765, 3069470027, 270153238, 1802868219, 3692709886, 2161737865, + 2159912357, 2585798786, 837488486, 4237238160, 2540319504, 3798629246, 3748148874, 1021550776, + 2386715342, 1973637538, 1823520457, 1146713475, 833971519, 3277251466, 905620390, 26278816, + 2680483154, 2294040859, 373297482, 5996609, 4109575006, 512575049, 917036550, 1942311753, + 2816916778, 3248920332, 1192784020, 3537586671, 2456567643, 2925660628, 759380297, 888447942, + 3559939476, 3654687237, 805, +]; +const POW5_12: [u32; 149] = [ + 322166785, 3809044581, 2994556223, 1239584207, 3962455841, 4001882964, 3053876612, 915114683, + 2783289745, 785739093, 4253185907, 3931164994, 1370983858, 2553556126, 3360742076, 2255410929, + 422849554, 2457422215, 3539495362, 1720790602, 1908931983, 1470596141, 592794347, 4219465164, + 4085652704, 941661409, 2534650953, 885063988, 2355909854, 2812815516, 767256131, 3821757683, + 2155151105, 3817418473, 281116564, 2834395026, 2821201622, 2524625843, 1511330880, 2572352493, + 330571332, 2951088579, 2730271766, 4044456479, 4212286644, 2444937588, 3603420843, 2387148597, + 1142537539, 3299235429, 1751012624, 861228086, 2873722519, 230498814, 1023297821, 2553128038, + 3421129895, 2651917435, 2042981258, 1606787143, 2228751918, 447345732, 1930371132, 1784132011, + 3612538790, 2275925090, 2487567871, 1080427616, 2009179183, 3383506781, 3899054063, 1950782960, + 2168622213, 2717674390, 3616636027, 2079341593, 1530129217, 1461057425, 2406264415, 3674671357, + 2972036238, 2019354295, 1455849819, 1866918619, 1324269294, 424891864, 2722422332, 2641594816, + 1400249021, 3482963993, 3734946379, 225889849, 1891545473, 777383150, 3589824633, 4117601611, + 4220028667, 334453379, 1083130821, 1060342180, 4208163139, 1489826908, 4163762246, 1096580926, + 689301528, 2336054516, 1782865703, 4175148410, 3398369392, 2329412588, 3001580596, 59740741, + 3202189932, 3351895776, 246185302, 718535188, 3772647488, 4151666556, 4055698133, 2461934110, + 2281316281, 3466396836, 3536023465, 1064267812, 2955456354, 2423805422, 3627960790, 1325057500, + 3876919979, 2009959531, 175455101, 184092852, 2358785571, 3842977831, 2485266289, 487121622, + 4159252710, 4075707558, 459389244, 300652075, 2521346588, 3458976673, 888631636, 2076098096, + 3844514585, 2363697580, 3729421522, 3051115477, 649395, +]; +const POW5_13: [u32; 298] = [ + 711442433, 3564261005, 2399042279, 4170849936, 4010295575, 1423987028, 330414929, 1349249065, + 4213813618, 3852031822, 4040843590, 2154565331, 3094013374, 1159028371, 3227065538, 2115927092, + 2085102554, 488590542, 2609619432, 3602898805, 3812736528, 3269439096, 23816114, 253984538, + 1035905997, 2942969204, 3400787671, 338562688, 1637191975, 740509713, 2264962817, 3410753922, + 4162231428, 2282041228, 1759373012, 3155367777, 4278913285, 1420532801, 1981002276, 438054990, + 1006507643, 1142697287, 1332538012, 2029019521, 3949305784, 818392641, 2491288846, 2716584663, + 3648886102, 556814413, 444795339, 4071412999, 1066321706, 4253169466, 2510832316, 672091442, + 4083256000, 2165985028, 1841538484, 3549854235, 364431512, 3707648143, 1162785440, 2268641545, + 281340310, 735693841, 848809228, 1700785200, 2919703985, 4094234344, 58530286, 965505005, + 1000010347, 3381961808, 3040089923, 1973852082, 2890971585, 1019960210, 4292895237, 2821887841, + 3756675650, 3951282907, 3885870583, 1008791145, 503998487, 1881258362, 1949332730, 392996726, + 2012973814, 3970014187, 2461725150, 2942547730, 3728066699, 2766901132, 3778532841, 1085564064, + 2278673896, 1116879805, 3448726271, 774279411, 157211670, 1506320155, 531168605, 1362654525, + 956967721, 2148871960, 769186085, 4186232894, 2055679604, 3248365487, 3981268013, 3975787984, + 2489510517, 3309046495, 212771124, 933418041, 3371839114, 562115198, 1853601831, 757336096, + 1354633440, 1486083256, 2872126393, 522920738, 1141587749, 3210903262, 1926940553, 3054024853, + 2021162538, 2262742000, 1877899947, 3147002868, 669840763, 4158174590, 4238502559, 1023731922, + 3386840011, 829588074, 3449720188, 2835142880, 2999162007, 813056473, 482949569, 638108879, + 3067201471, 1026714238, 4004452838, 2383667807, 3999477803, 771648919, 630660440, 3827121348, + 176185980, 2878191002, 2666149832, 3909811063, 2429163983, 2665690412, 907266128, 4269332098, + 2022665808, 1527122180, 3072053668, 1072477492, 3006022924, 549664855, 2800340954, 37352654, + 1212772743, 2711280533, 3029527946, 2511120040, 1305308377, 3474662224, 4226330922, 442988428, + 954940108, 3274548099, 4212288177, 2688499880, 3982226758, 3922609956, 1279948029, 1939943640, + 3650489901, 2733364929, 2494263275, 1864579964, 1225941120, 2390465139, 1267503249, 3533240729, + 904410805, 2842550015, 2517736241, 1796069820, 3335274381, 673539835, 1924694759, 3598098235, + 2792633405, 16535707, 3703535497, 3592841791, 2929082877, 1317622811, 294990855, 1396706563, + 2383271770, 3853857605, 277813677, 277580220, 1101318484, 3761974115, 1132150143, 2544692622, + 3419825776, 743770306, 1695464553, 1548693232, 2421159615, 2575672031, 2678971806, 1591267897, + 626546738, 3823443129, 267710932, 1455435162, 2353985540, 3248523795, 335348168, 3872552561, + 2814522612, 2634118860, 3503767026, 1301019273, 1414467789, 722985138, 3070909565, 4253482569, + 3744939841, 558142907, 2229819389, 13833173, 77003966, 2763671364, 3905603970, 2931990126, + 2280419384, 1879090457, 2934846267, 4284933164, 2331863845, 62191163, 3178861020, 1522063815, + 785672270, 1215568492, 2936443917, 802972489, 2956820173, 3916732783, 2893572089, 1391232801, + 3168640330, 2396859648, 894950918, 1103583736, 961991865, 2807302642, 305977505, 3054505899, + 1048256994, 781017659, 2459278754, 3164823415, 537658277, 905753687, 464963300, 4149131560, + 1029507924, 2278300961, 1231291503, 414073408, 3630740085, 2345841814, 475358196, 3258243317, + 4167625072, 4178911231, 2927355042, 655438830, 3138378018, 623200562, 2785714112, 273403236, + 807993669, 98, +]; +const POW5_14: [u32; 595] = [ + 1691320321, 2671006246, 1682531301, 2072858707, 1240508969, 3108358191, 1125119096, 2470144952, + 1610099978, 1690632660, 1941696884, 2663506355, 1006364675, 3909158537, 4147711374, 1072663936, + 4078768933, 745751659, 4123687570, 471458681, 655028926, 4113407388, 3945524552, 985625313, + 1254424514, 2127508744, 570530434, 945388122, 3194649404, 2589065070, 2731705399, 202030749, + 2090780394, 3348662271, 1481754777, 1130635472, 4025144705, 1924486271, 2578567861, 125491448, + 1558036315, 994248173, 3817216711, 763950077, 1030439870, 959586474, 3845661701, 483795093, + 1637944470, 2275463649, 3398804829, 1758016486, 2665513698, 2004912571, 1094885097, 4223064276, + 3307819021, 651121777, 1757003305, 3603542336, 129917786, 2215974994, 3042386306, 2205352757, + 3944939700, 3710987569, 97967515, 1217242524, 930630949, 3660328512, 1787663098, 1784141600, + 2500542892, 4034561586, 3444961378, 785043562, 3869499367, 885623728, 2625011087, 3053789617, + 1965731793, 3900511934, 2648823592, 3851062028, 3321968688, 799195417, 1011847510, 1369129160, + 1348009103, 2876796955, 2915408967, 3305284948, 263399535, 1715990604, 2645821294, 1587844552, + 2624912049, 3035631499, 2306636348, 3499275462, 675152704, 854794152, 4004972748, 1739996642, + 1333476491, 4012621867, 3658792931, 3297985728, 2864481726, 3066357406, 785287846, 1671499798, + 433044045, 1919608025, 264833858, 3999983367, 1116778570, 1301982149, 4213901070, 4081649357, + 536169226, 1389008649, 188923873, 373495152, 2551132278, 1800758715, 3951840330, 2632334454, + 3118778225, 1034046547, 1862428410, 3037609062, 1994608505, 29051798, 2571685694, 264151332, + 2260643090, 2717535964, 3508441116, 3283713017, 1903365635, 923575694, 1219598101, 2288281570, + 3676533911, 1014136356, 555142354, 2389170030, 4185108175, 884862419, 836141292, 2957159173, + 1997444768, 4233903127, 2876184692, 3089125070, 1480848293, 1097600237, 299700527, 2507669891, + 2982628312, 2114881043, 2529576251, 2812279824, 2987750993, 4241938954, 2204775591, 1037094060, + 829315638, 1231047149, 52608178, 3735136637, 3455232602, 962039123, 488286513, 50685385, + 3516451821, 843975207, 1572355722, 675489076, 2428445672, 1555117248, 3708476086, 10375249, + 4172112346, 2117510871, 2227658327, 3187664554, 3050656558, 328034318, 3179601324, 1247769761, + 3439263953, 1431538938, 2962525068, 1213366289, 3813013550, 2651093719, 1860661503, 3933716208, + 264320617, 789980519, 2257856172, 102000748, 977269860, 1113845122, 3008928583, 1461738106, + 557786285, 2926560363, 1038106190, 3643478847, 828004507, 457818698, 1933056971, 373408056, + 2076808229, 3160935130, 2781854874, 2519636100, 177606000, 4237103862, 3977834316, 1621936232, + 2599050516, 319893558, 3343370366, 765044144, 976657331, 7026264, 294277429, 3829376742, + 3029627280, 2705178718, 3614653880, 230519152, 3288033233, 293525479, 3805751881, 3227511198, + 2520308544, 3648103003, 1111086184, 437622105, 2232033852, 3239146386, 584244184, 1450926016, + 2462430443, 3226534010, 298582169, 4214576928, 1762099469, 964985185, 1585788148, 1641127666, + 787006566, 2315956284, 3258232694, 2275058964, 2541003317, 1508235863, 2613339827, 4080647514, + 1152057965, 3149266279, 731345410, 914737650, 65395712, 1884566942, 1379520432, 2611027720, + 4163073378, 2619704967, 2746552541, 1388822415, 3005141199, 843440249, 4288674003, 3136174279, + 4051522914, 4144149433, 3427566947, 3419023197, 3758479825, 3893877676, 96899594, 1657725776, + 253618880, 434129337, 1499045748, 2996992534, 4036042074, 2110713869, 906222950, 928326225, + 2541827893, 1604330202, 226792470, 4022228930, 815850898, 1466012310, 3377712199, 292769859, + 2822055597, 3225701344, 3052947004, 385831222, 705324593, 4030158636, 3540280538, 2982120874, + 2136414455, 255762046, 3852783591, 3262064164, 2358991588, 3756586117, 4143612643, 3326743817, + 2897365738, 807711264, 3719310016, 3721264861, 3627337076, 944539331, 3640975513, 3712525681, + 1162911839, 2008243316, 2179489649, 2867584109, 261861553, 3570253908, 2062868357, 2220328623, + 3857004679, 3744109002, 4138041873, 1451860932, 2364975637, 2802161722, 2680106834, 753401584, + 1223182946, 1245401957, 4163377735, 3565815922, 2216942838, 4036140094, 71979081, 3924559643, + 400477238, 551750683, 1174153235, 859969898, 1185921017, 1711399735, 812991545, 4051735761, + 3549118738, 1631653329, 3631835958, 3648867800, 1206500363, 2155893137, 361030362, 3454286017, + 2505909489, 1083595169, 453595313, 1510564703, 1706163902, 1632924345, 1381875722, 1661526119, + 1082778324, 3571910052, 1140625929, 851544870, 1145546234, 2938573139, 907528924, 1304752338, + 1764668294, 1788942063, 1700368828, 104979467, 1413911959, 3327497828, 1956384744, 1272712474, + 2815637534, 3307809377, 1320574940, 1111968962, 4073107827, 434096622, 169451929, 3201183459, + 3331028877, 2852366972, 3369830128, 2924794558, 3106537952, 3739481231, 1612955817, 4138608722, + 2721281595, 2755775390, 843505117, 982234295, 1157276611, 814674632, 4246504726, 3532006708, + 992340967, 1647538031, 204696133, 193866982, 3899126129, 300851698, 1379496684, 1759463683, + 1354782756, 1374637239, 3410883240, 1073406229, 3038431791, 1053909855, 3607043270, 173719711, + 3733903830, 171820911, 1573050589, 932781534, 4183534770, 2158849555, 372245998, 3573073830, + 841339264, 2759200520, 1610547277, 2603293319, 3890906486, 1557138278, 3964109906, 677238797, + 537994297, 1124184993, 4287078344, 4207654540, 2943022776, 2977947524, 3255359985, 4098397558, + 2274666217, 2915862060, 243524940, 2467726756, 2869020032, 507521339, 3403121914, 522051455, + 1803903108, 3471254194, 473535371, 1948602036, 3352095732, 3116527002, 1795743673, 775867940, + 2551469548, 3757442064, 3162525227, 3765412747, 3040105484, 1927625810, 48214767, 2997207130, + 1342349989, 2536583992, 1501320191, 3592287317, 887432730, 967585477, 3334212779, 948663609, + 1064513472, 15386372, 2465931737, 3230242590, 3036652803, 2063155087, 1927500726, 2821790499, + 2187774383, 501520074, 3688568496, 3606711121, 2576459247, 3176542345, 378322447, 156541411, + 1400607301, 1406179107, 677848877, 2253753529, 193196070, 4207435024, 4166396241, 509467541, + 2906024136, 1221753746, 3375413222, 431327897, 2749265123, 2848827671, 3412997614, 2051920238, + 1283516885, 1300498239, 1957256104, 2634010560, 3531900395, 360276850, 1461184973, 2012063967, + 2873572430, 2914608609, 4289554777, 1539331673, 1859532928, 4213441063, 538215691, 3512720863, + 4258743698, 3040408445, 982396546, 343095663, 4138069496, 1021581857, 214185242, 1968079460, + 2864275059, 3347192726, 4096783459, 3259169450, 3707808869, 142485006, 399610869, 230556456, + 2219467721, 4191227798, 2242548189, 3136366572, 179755707, 3464881829, 452317775, 3887426070, + 3446430233, 1473370015, 1576807208, 3964523248, 419325089, 2373067114, 1596072055, 1928415752, + 3635452689, 1005598891, 3335462724, 3290848636, 3669078247, 1178176812, 2110774376, 3068593619, + 1253036518, 908857731, 3631223047, 4138506423, 2903592318, 3596915748, 3289036113, 3721512676, + 2704409359, 3386016968, 3676268074, 2185259502, 1096257611, 3360076717, 3548676554, 170167319, + 3360064287, 3899940843, 9640, +]; + +pub(crate) const POW5: [&'static [u32]; 14] = [ + &POW5_1, &POW5_2, &POW5_3, &POW5_4, &POW5_5, &POW5_6, &POW5_7, &POW5_8, &POW5_9, &POW5_10, + &POW5_11, &POW5_12, &POW5_13, &POW5_14, +]; diff --git a/third_party/crates/serde_json-1.0.151/src/lexical/large_powers64.rs b/third_party/crates/serde_json-1.0.151/src/lexical/large_powers64.rs new file mode 100644 index 0000000..96554ea --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/lexical/large_powers64.rs @@ -0,0 +1,625 @@ +// Adapted from https://github.com/Alexhuszagh/rust-lexical. + +//! Precalculated large powers for 64-bit limbs. + +/// Large powers (`&[u64]`) for base5 operations. +const POW5_1: [u64; 1] = [5]; +const POW5_2: [u64; 1] = [25]; +const POW5_3: [u64; 1] = [625]; +const POW5_4: [u64; 1] = [390625]; +const POW5_5: [u64; 1] = [152587890625]; +const POW5_6: [u64; 2] = [3273344365508751233, 1262]; +const POW5_7: [u64; 3] = [7942358959831785217, 16807427164405733357, 1593091]; +const POW5_8: [u64; 5] = [ + 279109966635548161, + 2554917779393558781, + 14124656261812188652, + 11976055582626787546, + 2537941837315, +]; +const POW5_9: [u64; 10] = [ + 13750482914757213185, + 1302999927698857842, + 14936872543252795590, + 2788415840139466767, + 2095640732773017264, + 7205570348933370714, + 7348167152523113408, + 9285516396840364274, + 6907659600622710236, + 349175, +]; +const POW5_10: [u64; 19] = [ + 8643096425819600897, + 6743743997439985372, + 14059704609098336919, + 10729359125898331411, + 4933048501514368705, + 12258131603170554683, + 2172371001088594721, + 13569903330219142946, + 13809142207969578845, + 16716360519037769646, + 9631256923806107285, + 12866941232305103710, + 1397931361048440292, + 7619627737732970332, + 12725409486282665900, + 11703051443360963910, + 9947078370803086083, + 13966287901448440471, + 121923442132, +]; +const POW5_11: [u64; 38] = [ + 17679772531488845825, + 2216509366347768155, + 1568689219195129479, + 5511594616325588277, + 1067709417009240089, + 9070650952098657518, + 11515285870634858015, + 2539561553659505564, + 17604889300961091799, + 14511540856854204724, + 12099083339557485471, + 7115240299237943815, + 313979240050606788, + 10004784664717172195, + 15570268847930131473, + 10359715202835930803, + 17685054012115162812, + 13183273382855797757, + 7743260039872919062, + 9284593436392572926, + 11105921222066415013, + 18198799323400703846, + 16314988383739458320, + 4387527177871570570, + 8476708682254672590, + 4925096874831034057, + 14075687868072027455, + 112866656203221926, + 9852830467773230418, + 25755239915196746, + 2201493076310172510, + 8342165458688466438, + 13954006576066379050, + 15193819059903295636, + 12565616718911389531, + 3815854855847885129, + 15696762163583540628, + 805, +]; +const POW5_12: [u64; 75] = [ + 16359721904723189761, + 5323973632697650495, + 17187956456762001185, + 3930387638628283780, + 3374723710406992273, + 16884225088663222131, + 10967440051041439154, + 9686916182456720060, + 10554548046311730194, + 7390739362393647554, + 6316162333127736719, + 18122464886584070891, + 4044404959645932768, + 3801320885861987401, + 12080950653257274590, + 16414324262488991299, + 16395687498836410113, + 12173633940896186260, + 10843185433142632150, + 11048169832730399808, + 12674828934734683716, + 17370808310130582550, + 10500926985433408692, + 10252725158410704555, + 14170108270502067523, + 3698946465517688080, + 989984870770509463, + 10965601426733943069, + 11389898658438335655, + 6901098232861256586, + 1921335291173932590, + 7662788640922083388, + 9775023833308395430, + 4640401278902814207, + 14532050972198413359, + 8378549018693130223, + 11672322628395371653, + 8930704142764178555, + 6275193859483102017, + 15782593304269205087, + 8673060659034172558, + 8018354414354334043, + 1824896661540749038, + 11345563346725559868, + 14959216444480821949, + 970189517688324683, + 3338835207603007873, + 17684964260791738489, + 1436466329061721851, + 4554134986752476101, + 6398757850768963907, + 4709779218751158342, + 10033277748582410264, + 17932125878679265063, + 10004750887749091440, + 256584531835386932, + 14396282740722731628, + 3086085133731396950, + 17831272085689600064, + 10573926491412564693, + 14888061047859191737, + 4570995450261499817, + 10410165022312935266, + 5691078631447480790, + 8632710455805418155, + 790672778942823293, + 16505464105756800547, + 2092171438149740401, + 17505030673829275878, + 1291290830058928444, + 14856191690683232796, + 8916773426496500052, + 10152003807578858265, + 13104441193763861714, + 649395, +]; +const POW5_13: [u64; 149] = [ + 15308384451594534913, + 17913664074042735335, + 6115977719198531863, + 5794980608663993169, + 16544350702855106930, + 9253787637781258566, + 4977988951675168190, + 9087837664087448770, + 2098480401110016986, + 15474332540882100712, + 14042133997396540944, + 1090855284423485362, + 12639956485351058381, + 1454115676006639319, + 3180465001342538023, + 14649076551958697729, + 9801292446545910916, + 13552201410826594004, + 6101141927469189381, + 1881431857880609316, + 4907847477899433595, + 8714572486973123228, + 3514969632331374520, + 11667642286891470094, + 2391499697425323350, + 17486585679659076043, + 18267223761882105642, + 2886610765822313148, + 9302834862968900288, + 15246507846733637044, + 15924227519624562840, + 9743741243284697760, + 3159780987244964246, + 7304816812369628428, + 17584602612559717809, + 4146812420657846766, + 14525415362681041515, + 8477630142371600195, + 4380695748062263745, + 12119915994367943173, + 16970630866565485122, + 4332724980155264503, + 8079943140620527639, + 1687908087554405626, + 17051081099834002166, + 12638146269730763230, + 11883749876933445771, + 4662462156371383785, + 4796962238316531176, + 3325504751659868927, + 6469595803187862550, + 5852556621152583005, + 9229334792448387881, + 17979733373938620709, + 13951623534175792756, + 17075879371091039277, + 14212246479457938037, + 4008999959804158260, + 2414266395366403722, + 3252733766253918247, + 6382678985007829216, + 2245927470982310841, + 13790724502051307301, + 13116936866733148041, + 9718402891306794538, + 13516274400356104875, + 17859223875778049403, + 4396895129099725471, + 3563053650368467915, + 12176845952536972668, + 3492050964335269015, + 2740656767075170753, + 4409704077614761919, + 10237775279597492710, + 3314206875098230827, + 16437361028114095448, + 12361736225407656572, + 16792510651790145480, + 11449053143229929935, + 18336641737580333136, + 6558939822118891088, + 4606255756908155300, + 2360792578991605004, + 160428430149144538, + 11644861220729221511, + 10785178451159739786, + 14923560618031934681, + 1902620814992781610, + 14064076995338910412, + 11547019064112212657, + 16847481479966225734, + 8331994491163145469, + 11739712981738851885, + 8008309968651120619, + 10266969595459035264, + 15175153381217702033, + 12208659352573720245, + 7714061140750342961, + 2892831567213510541, + 15453714249045017319, + 71020323573871677, + 15431137995750602633, + 5659146884637671933, + 5998809010488554503, + 16552192379299157850, + 1192197967194298797, + 16157555793424861524, + 10929371590994640255, + 3194469143425738352, + 6651586784672005225, + 11062427140788057791, + 6834443579468668318, + 16421563197797455922, + 6251046422506172884, + 13952303462156793860, + 16632486601871393224, + 11313454360291325172, + 5587835232504462834, + 3105197524618514637, + 18268568531031972989, + 2397205535804309313, + 59413027864729597, + 11869878125348715710, + 12592801707270523266, + 8070632061321113656, + 18403647807860650811, + 267109013517069093, + 6537214311028855260, + 5220826919973709902, + 3448740582779163661, + 16822239213112884941, + 5975299384311048185, + 10294433804430712138, + 4739856055412448774, + 12057273038326387897, + 13119002941950056609, + 3354445304051737058, + 13592813067499314594, + 3890182464434078629, + 17820384357466425060, + 9785228118969879380, + 1778431746734556271, + 10075313876350055029, + 13994048489400919028, + 17948287074199726448, + 2815088342305858722, + 2676626035777198370, + 1174257960026283968, + 421714788677, +]; +const POW5_14: [u64; 298] = [ + 11471884475673051137, + 8902860357476377573, + 13350296775839230505, + 10609191786344608888, + 7261211985859587338, + 11439672689354862964, + 16789708072300570627, + 4607056528866348430, + 3202978990421512997, + 2024899620433984146, + 17666950207239811774, + 4233228489390288200, + 9137580478688460738, + 4060411066587388546, + 11119949806060600124, + 867715462473090103, + 14382394941384869610, + 4856042377419278489, + 8265605599571137921, + 538981667666252469, + 4270263388700786523, + 3281140600308898503, + 4121392524544394174, + 2077884106245940229, + 9773041957329767574, + 7550623316597646685, + 8611033926449791714, + 18137922955420802793, + 2796546741236224013, + 15477096484628446761, + 9517540128113714010, + 9471917970500821378, + 15938570248662483124, + 5228016831978462619, + 15720991252586974501, + 7662829825220776698, + 17328310068068434348, + 3371736428170309730, + 3803724952191098855, + 13115926536504376719, + 16752571196153442257, + 16540185467776259880, + 3432518182450051120, + 5880364967211798870, + 12355748840305392783, + 14196090758536469575, + 7370123524686686319, + 6819740424617592686, + 13037938013537368753, + 15029273671291927100, + 3671312928327205696, + 7473228676544792780, + 17234079691312938123, + 14164740848093544419, + 13169904779481875902, + 7179036968465894054, + 8244653688947194445, + 17179797746073799490, + 5591970751047577674, + 17530550506268329742, + 5965746721852312330, + 1604149463243472865, + 7734199791463116918, + 11305790396015856714, + 4441196105025505137, + 13046431581185664762, + 124776524294606713, + 1134521334706523966, + 11671728093344476434, + 14103440020972933148, + 3966727403013869059, + 9828094508409132821, + 4355682486381147287, + 10261407143988481234, + 3800455155249557199, + 12700901937937547500, + 18184475466894579360, + 13267691151779895412, + 4714157123477697445, + 10770360171308585263, + 9083344917597998040, + 12078649873810212155, + 18218989082046199377, + 4454285072780637351, + 5287307245618354742, + 16042289702059031730, + 4131926574212754010, + 217692071448455473, + 3624845916216282093, + 2901203491797614218, + 6679177724033967080, + 44561358851332790, + 9094639944041587162, + 13690915012276084311, + 1408896670826320686, + 5359130319612337580, + 6148412925099835601, + 5211368532286409612, + 11386360825549027374, + 16895182466965795071, + 3392940493846427241, + 438089879085393580, + 4783928372776399972, + 6278117363595909959, + 12569481049412674733, + 15648622492570893902, + 1966316336235305115, + 1603775390515993547, + 13576113010204316709, + 10821754650102840474, + 18198222517222903152, + 6966163076615302988, + 1373932372410129684, + 3285839581819684990, + 30177575069719475, + 16447047871247307061, + 11618654126674833808, + 990072222556306872, + 1260682336135768017, + 13862055046689532489, + 15668483092844698432, + 1879572630092764264, + 13912027797058626108, + 6231679788219816920, + 13857858054844167403, + 18101470072534728857, + 4144579812461609229, + 7048589655616599284, + 9946956499532694630, + 9771303850109874038, + 6477823708780339765, + 17526247621747041971, + 13525995675852669549, + 3928768291901239810, + 8094153383078124544, + 11214278667728965552, + 11251547162596832610, + 5964946855123292381, + 3622548288590237903, + 13469765967150053587, + 17798986288523466082, + 14684592818807932259, + 16724077276802963921, + 7119877993753121290, + 1864571304902781632, + 12871984921385213812, + 9065447042604670298, + 3987130777300360550, + 6890545752116901685, + 17275341711601865750, + 6296474927799264658, + 1257436973037243463, + 13854281781965301421, + 1657132483318662716, + 17309399540017292849, + 12808111630089217242, + 1098489625264462071, + 14010458905686364135, + 16134414519481621220, + 14288255900328821475, + 3469093466388187882, + 15982710881468295872, + 4056765540058056052, + 15945176389096104089, + 8625339365793505375, + 12316179968863788913, + 15334123773538054321, + 9536238824220581765, + 16080825720106203271, + 6235695225418121745, + 12035192956458019349, + 3235835166714703698, + 5348960676912581218, + 15315062772709464647, + 17335089708021308662, + 16855855317958414409, + 2369751139431140406, + 3693542588628609043, + 7350405893393987577, + 17402072586341663801, + 7007897690013647122, + 15671767872059304758, + 9259490518292347915, + 14836045474406130394, + 4654005815464502513, + 6487825998330548401, + 7013356660323385022, + 7136200343936679946, + 15341236858676437716, + 3657357368867197449, + 12621075530054608378, + 5603868621997066972, + 7683447656788439942, + 450883379216880060, + 14291494350184945047, + 5466258454997635048, + 14206933098432772126, + 4775870327277641692, + 1864430798867181939, + 13748978265070608793, + 12250822864261576589, + 12561896977498605296, + 16060949594257359328, + 17775189113543311529, + 11835965177892927035, + 4218664174878121437, + 3499000902478111683, + 15169853304359126294, + 7076121963053575143, + 832652347668916805, + 1292148207755194737, + 7556838978364207852, + 5904021986723518500, + 4610244652288570024, + 4526508363195533871, + 746120481022614726, + 737965197247830486, + 4006266184415762653, + 9272188239892688050, + 15346235246415709678, + 11850675997347533184, + 11181059668610842701, + 6687857983250662774, + 2908718488661492818, + 4828337780126983225, + 18071738646453002184, + 12790187227727197880, + 17602483480871623153, + 12523532189621855977, + 10598805712727696716, + 2179787555896149376, + 2242193929457337594, + 14908923241136742532, + 8369182018012550027, + 13385381554043022324, + 3332327430110633913, + 16138090784046208492, + 16172324607469047339, + 8279089815915615244, + 12872906602736235247, + 10894545290539475621, + 15428756545851905023, + 4155747980686992922, + 4074479178894544043, + 66083965608603584, + 13873786284662268377, + 8861183628277687555, + 12119497911296021430, + 2154012318305274287, + 15490706314503067312, + 13643145488710608367, + 672340241093017103, + 6039493278284091973, + 9679797700977436461, + 18070795828318171174, + 2188146431134935377, + 5247392385741514952, + 1852539214842869734, + 12235621681634112739, + 8812930319623534062, + 5585597406294108629, + 11312989214475901864, + 1547377291787797995, + 8641748937186208205, + 12518148659168623694, + 6611379197521520985, + 18096591571068008576, + 15087021227100112139, + 13058454842015958418, + 1473584652966833794, + 4387660670140018168, + 8452836916843525402, + 14376083294443363955, + 13998026203969090659, + 611968444648172645, + 990232438801273845, + 18001186324715561929, + 13470591857250177501, + 14881554140239420091, + 16696367836720124495, + 6328076032778459673, + 17027497695968504616, + 10192245646262428833, + 8282482589527318647, + 4319014353374321425, + 14134087271041670980, + 5060230880114618599, + 13179509240430058600, + 3903514232614801894, + 17774749744702165255, + 15448635507030969726, + 15983775238358480209, + 14542832143965487887, + 9385618098039514666, + 14431419612662304843, + 730863073501675978, + 16750118380379734815, + 9640, +]; + +pub(crate) const POW5: [&[u64]; 14] = [ + &POW5_1, &POW5_2, &POW5_3, &POW5_4, &POW5_5, &POW5_6, &POW5_7, &POW5_8, &POW5_9, &POW5_10, + &POW5_11, &POW5_12, &POW5_13, &POW5_14, +]; diff --git a/third_party/crates/serde_json-1.0.151/src/lexical/math.rs b/third_party/crates/serde_json-1.0.151/src/lexical/math.rs new file mode 100644 index 0000000..8e30720 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/lexical/math.rs @@ -0,0 +1,884 @@ +// Adapted from https://github.com/Alexhuszagh/rust-lexical. + +//! Building-blocks for arbitrary-precision math. +//! +//! These algorithms assume little-endian order for the large integer +//! buffers, so for a `vec![0, 1, 2, 3]`, `3` is the most significant limb, +//! and `0` is the least significant limb. + +use super::large_powers; +use super::num::*; +use super::small_powers::*; +use alloc::vec::Vec; +use core::{cmp, iter, mem}; + +// ALIASES +// ------- + +// Type for a single limb of the big integer. +// +// A limb is analogous to a digit in base10, except, it stores 32-bit +// or 64-bit numbers instead. +// +// This should be all-known 64-bit platforms supported by Rust. +// https://forge.rust-lang.org/platform-support.html +// +// Platforms where native 128-bit multiplication is explicitly supported: +// - x86_64 (Supported via `MUL`). +// - mips64 (Supported via `DMULTU`, which `HI` and `LO` can be read-from). +// +// Platforms where native 64-bit multiplication is supported and +// you can extract hi-lo for 64-bit multiplications. +// aarch64 (Requires `UMULH` and `MUL` to capture high and low bits). +// powerpc64 (Requires `MULHDU` and `MULLD` to capture high and low bits). +// +// Platforms where native 128-bit multiplication is not supported, +// requiring software emulation. +// sparc64 (`UMUL` only supported double-word arguments). + +// 32-BIT LIMB +#[cfg(fast_arithmetic = "32")] +pub type Limb = u32; + +#[cfg(fast_arithmetic = "32")] +pub const POW5_LIMB: &[Limb] = &POW5_32; + +#[cfg(fast_arithmetic = "32")] +pub const POW10_LIMB: &[Limb] = &POW10_32; + +#[cfg(fast_arithmetic = "32")] +type Wide = u64; + +// 64-BIT LIMB +#[cfg(fast_arithmetic = "64")] +pub type Limb = u64; + +#[cfg(fast_arithmetic = "64")] +pub const POW5_LIMB: &[Limb] = &POW5_64; + +#[cfg(fast_arithmetic = "64")] +pub const POW10_LIMB: &[Limb] = &POW10_64; + +#[cfg(fast_arithmetic = "64")] +type Wide = u128; + +/// Cast to limb type. +#[inline] +pub(crate) fn as_limb(t: T) -> Limb { + Limb::as_cast(t) +} + +/// Cast to wide type. +#[inline] +fn as_wide(t: T) -> Wide { + Wide::as_cast(t) +} + +// SPLIT +// ----- + +/// Split u64 into limbs, in little-endian order. +#[inline] +#[cfg(fast_arithmetic = "32")] +fn split_u64(x: u64) -> [Limb; 2] { + [as_limb(x), as_limb(x >> 32)] +} + +/// Split u64 into limbs, in little-endian order. +#[inline] +#[cfg(fast_arithmetic = "64")] +fn split_u64(x: u64) -> [Limb; 1] { + [as_limb(x)] +} + +// HI64 +// ---- + +// NONZERO + +/// Check if any of the remaining bits are non-zero. +#[inline] +pub fn nonzero(x: &[T], rindex: usize) -> bool { + let len = x.len(); + let slc = &x[..len - rindex]; + slc.iter().rev().any(|&x| x != T::ZERO) +} + +/// Shift 64-bit integer to high 64-bits. +#[inline] +fn u64_to_hi64_1(r0: u64) -> (u64, bool) { + debug_assert!(r0 != 0); + let ls = r0.leading_zeros(); + (r0 << ls, false) +} + +/// Shift 2 64-bit integers to high 64-bits. +#[inline] +fn u64_to_hi64_2(r0: u64, r1: u64) -> (u64, bool) { + debug_assert!(r0 != 0); + let ls = r0.leading_zeros(); + let rs = 64 - ls; + let v = match ls { + 0 => r0, + _ => (r0 << ls) | (r1 >> rs), + }; + let n = r1 << ls != 0; + (v, n) +} + +/// Trait to export the high 64-bits from a little-endian slice. +trait Hi64: AsRef<[T]> { + /// Get the hi64 bits from a 1-limb slice. + fn hi64_1(&self) -> (u64, bool); + + /// Get the hi64 bits from a 2-limb slice. + fn hi64_2(&self) -> (u64, bool); + + /// Get the hi64 bits from a 3-limb slice. + fn hi64_3(&self) -> (u64, bool); + + /// High-level exporter to extract the high 64 bits from a little-endian slice. + #[inline] + fn hi64(&self) -> (u64, bool) { + match self.as_ref().len() { + 0 => (0, false), + 1 => self.hi64_1(), + 2 => self.hi64_2(), + _ => self.hi64_3(), + } + } +} + +impl Hi64 for [u32] { + #[inline] + fn hi64_1(&self) -> (u64, bool) { + debug_assert_eq!(self.len(), 1); + let r0 = self[0] as u64; + u64_to_hi64_1(r0) + } + + #[inline] + fn hi64_2(&self) -> (u64, bool) { + debug_assert_eq!(self.len(), 2); + let r0 = (self[1] as u64) << 32; + let r1 = self[0] as u64; + u64_to_hi64_1(r0 | r1) + } + + #[inline] + fn hi64_3(&self) -> (u64, bool) { + debug_assert!(self.len() >= 3); + let r0 = self[self.len() - 1] as u64; + let r1 = (self[self.len() - 2] as u64) << 32; + let r2 = self[self.len() - 3] as u64; + let (v, n) = u64_to_hi64_2(r0, r1 | r2); + (v, n || nonzero(self, 3)) + } +} + +impl Hi64 for [u64] { + #[inline] + fn hi64_1(&self) -> (u64, bool) { + debug_assert_eq!(self.len(), 1); + let r0 = self[0]; + u64_to_hi64_1(r0) + } + + #[inline] + fn hi64_2(&self) -> (u64, bool) { + debug_assert!(self.len() >= 2); + let r0 = self[self.len() - 1]; + let r1 = self[self.len() - 2]; + let (v, n) = u64_to_hi64_2(r0, r1); + (v, n || nonzero(self, 2)) + } + + #[inline] + fn hi64_3(&self) -> (u64, bool) { + self.hi64_2() + } +} + +// SCALAR +// ------ + +// Scalar-to-scalar operations, for building-blocks for arbitrary-precision +// operations. + +mod scalar { + use super::*; + + // ADDITION + + /// Add two small integers and return the resulting value and if overflow happens. + #[inline] + pub fn add(x: Limb, y: Limb) -> (Limb, bool) { + x.overflowing_add(y) + } + + /// AddAssign two small integers and return if overflow happens. + #[inline] + pub fn iadd(x: &mut Limb, y: Limb) -> bool { + let t = add(*x, y); + *x = t.0; + t.1 + } + + // SUBTRACTION + + /// Subtract two small integers and return the resulting value and if overflow happens. + #[inline] + pub fn sub(x: Limb, y: Limb) -> (Limb, bool) { + x.overflowing_sub(y) + } + + /// SubAssign two small integers and return if overflow happens. + #[inline] + pub fn isub(x: &mut Limb, y: Limb) -> bool { + let t = sub(*x, y); + *x = t.0; + t.1 + } + + // MULTIPLICATION + + /// Multiply two small integers (with carry) (and return the overflow contribution). + /// + /// Returns the (low, high) components. + #[inline] + pub fn mul(x: Limb, y: Limb, carry: Limb) -> (Limb, Limb) { + // Cannot overflow, as long as wide is 2x as wide. This is because + // the following is always true: + // `Wide::max_value() - (Narrow::max_value() * Narrow::max_value()) >= Narrow::max_value()` + let z: Wide = as_wide(x) * as_wide(y) + as_wide(carry); + let bits = mem::size_of::() * 8; + (as_limb(z), as_limb(z >> bits)) + } + + /// Multiply two small integers (with carry) (and return if overflow happens). + #[inline] + pub fn imul(x: &mut Limb, y: Limb, carry: Limb) -> Limb { + let t = mul(*x, y, carry); + *x = t.0; + t.1 + } +} // scalar + +// SMALL +// ----- + +// Large-to-small operations, to modify a big integer from a native scalar. + +mod small { + use super::*; + + // ADDITION + + /// Implied AddAssign implementation for adding a small integer to bigint. + /// + /// Allows us to choose a start-index in x to store, to allow incrementing + /// from a non-zero start. + #[inline] + pub fn iadd_impl(x: &mut Vec, y: Limb, xstart: usize) { + if x.len() <= xstart { + x.push(y); + } else { + // Initial add + let mut carry = scalar::iadd(&mut x[xstart], y); + + // Increment until overflow stops occurring. + let mut size = xstart + 1; + while carry && size < x.len() { + carry = scalar::iadd(&mut x[size], 1); + size += 1; + } + + // If we overflowed the buffer entirely, need to add 1 to the end + // of the buffer. + if carry { + x.push(1); + } + } + } + + /// AddAssign small integer to bigint. + #[inline] + pub fn iadd(x: &mut Vec, y: Limb) { + iadd_impl(x, y, 0); + } + + // SUBTRACTION + + /// SubAssign small integer to bigint. + /// Does not do overflowing subtraction. + #[inline] + pub fn isub_impl(x: &mut Vec, y: Limb, xstart: usize) { + debug_assert!(x.len() > xstart && (x[xstart] >= y || x.len() > xstart + 1)); + + // Initial subtraction + let mut carry = scalar::isub(&mut x[xstart], y); + + // Increment until overflow stops occurring. + let mut size = xstart + 1; + while carry && size < x.len() { + carry = scalar::isub(&mut x[size], 1); + size += 1; + } + normalize(x); + } + + // MULTIPLICATION + + /// MulAssign small integer to bigint. + #[inline] + pub fn imul(x: &mut Vec, y: Limb) { + // Multiply iteratively over all elements, adding the carry each time. + let mut carry: Limb = 0; + for xi in &mut *x { + carry = scalar::imul(xi, y, carry); + } + + // Overflow of value, add to end. + if carry != 0 { + x.push(carry); + } + } + + /// Mul small integer to bigint. + #[inline] + pub fn mul(x: &[Limb], y: Limb) -> Vec { + let mut z = Vec::::default(); + z.extend_from_slice(x); + imul(&mut z, y); + z + } + + /// MulAssign by a power. + /// + /// Theoretically... + /// + /// Use an exponentiation by squaring method, since it reduces the time + /// complexity of the multiplication to ~`O(log(n))` for the squaring, + /// and `O(n*m)` for the result. Since `m` is typically a lower-order + /// factor, this significantly reduces the number of multiplications + /// we need to do. Iteratively multiplying by small powers follows + /// the nth triangular number series, which scales as `O(p^2)`, but + /// where `p` is `n+m`. In short, it scales very poorly. + /// + /// Practically.... + /// + /// Exponentiation by Squaring: + /// running 2 tests + /// test bigcomp_f32_lexical ... bench: 1,018 ns/iter (+/- 78) + /// test bigcomp_f64_lexical ... bench: 3,639 ns/iter (+/- 1,007) + /// + /// Exponentiation by Iterative Small Powers: + /// running 2 tests + /// test bigcomp_f32_lexical ... bench: 518 ns/iter (+/- 31) + /// test bigcomp_f64_lexical ... bench: 583 ns/iter (+/- 47) + /// + /// Exponentiation by Iterative Large Powers (of 2): + /// running 2 tests + /// test bigcomp_f32_lexical ... bench: 671 ns/iter (+/- 31) + /// test bigcomp_f64_lexical ... bench: 1,394 ns/iter (+/- 47) + /// + /// Even using worst-case scenarios, exponentiation by squaring is + /// significantly slower for our workloads. Just multiply by small powers, + /// in simple cases, and use precalculated large powers in other cases. + pub fn imul_pow5(x: &mut Vec, n: u32) { + use super::large::KARATSUBA_CUTOFF; + + let small_powers = POW5_LIMB; + let large_powers = large_powers::POW5; + + if n == 0 { + // No exponent, just return. + // The 0-index of the large powers is `2^0`, which is 1, so we want + // to make sure we don't take that path with a literal 0. + return; + } + + // We want to use the asymptotically faster algorithm if we're going + // to be using Karabatsu multiplication sometime during the result, + // otherwise, just use exponentiation by squaring. + let bit_length = 32 - n.leading_zeros() as usize; + debug_assert!(bit_length != 0 && bit_length <= large_powers.len()); + if x.len() + large_powers[bit_length - 1].len() < 2 * KARATSUBA_CUTOFF { + // We can use iterative small powers to make this faster for the + // easy cases. + + // Multiply by the largest small power until n < step. + let step = small_powers.len() - 1; + let power = small_powers[step]; + let mut n = n as usize; + while n >= step { + imul(x, power); + n -= step; + } + + // Multiply by the remainder. + imul(x, small_powers[n]); + } else { + // In theory, this code should be asymptotically a lot faster, + // in practice, our small::imul seems to be the limiting step, + // and large imul is slow as well. + + // Multiply by higher order powers. + let mut idx: usize = 0; + let mut bit: usize = 1; + let mut n = n as usize; + while n != 0 { + if n & bit != 0 { + debug_assert!(idx < large_powers.len()); + large::imul(x, large_powers[idx]); + n ^= bit; + } + idx += 1; + bit <<= 1; + } + } + } + + // BIT LENGTH + + /// Get number of leading zero bits in the storage. + #[inline] + pub fn leading_zeros(x: &[Limb]) -> usize { + x.last().map_or(0, |x| x.leading_zeros() as usize) + } + + /// Calculate the bit-length of the big-integer. + #[inline] + pub fn bit_length(x: &[Limb]) -> usize { + let bits = mem::size_of::() * 8; + // Avoid overflowing, calculate via total number of bits + // minus leading zero bits. + let nlz = leading_zeros(x); + bits.checked_mul(x.len()) + .map_or_else(usize::max_value, |v| v - nlz) + } + + // SHL + + /// Shift-left bits inside a buffer. + /// + /// Assumes `n < Limb::BITS`, IE, internally shifting bits. + #[inline] + pub fn ishl_bits(x: &mut Vec, n: usize) { + // Need to shift by the number of `bits % Limb::BITS)`. + let bits = mem::size_of::() * 8; + debug_assert!(n < bits); + if n == 0 { + return; + } + + // Internally, for each item, we shift left by n, and add the previous + // right shifted limb-bits. + // For example, we transform (for u8) shifted left 2, to: + // b10100100 b01000010 + // b10 b10010001 b00001000 + let rshift = bits - n; + let lshift = n; + let mut prev: Limb = 0; + for xi in &mut *x { + let tmp = *xi; + *xi <<= lshift; + *xi |= prev >> rshift; + prev = tmp; + } + + // Always push the carry, even if it creates a non-normal result. + let carry = prev >> rshift; + if carry != 0 { + x.push(carry); + } + } + + /// Shift-left `n` digits inside a buffer. + /// + /// Assumes `n` is not 0. + #[inline] + pub fn ishl_limbs(x: &mut Vec, n: usize) { + debug_assert!(n != 0); + if !x.is_empty() { + x.reserve(n); + x.splice(..0, iter::repeat(0).take(n)); + } + } + + /// Shift-left buffer by n bits. + #[inline] + pub fn ishl(x: &mut Vec, n: usize) { + let bits = mem::size_of::() * 8; + // Need to pad with zeros for the number of `bits / Limb::BITS`, + // and shift-left with carry for `bits % Limb::BITS`. + let rem = n % bits; + let div = n / bits; + ishl_bits(x, rem); + if div != 0 { + ishl_limbs(x, div); + } + } + + // NORMALIZE + + /// Normalize the container by popping any leading zeros. + #[inline] + pub fn normalize(x: &mut Vec) { + // Remove leading zero if we cause underflow. Since we're dividing + // by a small power, we have at max 1 int removed. + while x.last() == Some(&0) { + x.pop(); + } + } +} // small + +// LARGE +// ----- + +// Large-to-large operations, to modify a big integer from a native scalar. + +mod large { + use super::*; + + // RELATIVE OPERATORS + + /// Compare `x` to `y`, in little-endian order. + #[inline] + pub fn compare(x: &[Limb], y: &[Limb]) -> cmp::Ordering { + if x.len() > y.len() { + cmp::Ordering::Greater + } else if x.len() < y.len() { + cmp::Ordering::Less + } else { + let iter = x.iter().rev().zip(y.iter().rev()); + for (&xi, &yi) in iter { + if xi > yi { + return cmp::Ordering::Greater; + } else if xi < yi { + return cmp::Ordering::Less; + } + } + // Equal case. + cmp::Ordering::Equal + } + } + + /// Check if x is less than y. + #[inline] + pub fn less(x: &[Limb], y: &[Limb]) -> bool { + compare(x, y) == cmp::Ordering::Less + } + + /// Check if x is greater than or equal to y. + #[inline] + pub fn greater_equal(x: &[Limb], y: &[Limb]) -> bool { + !less(x, y) + } + + // ADDITION + + /// Implied AddAssign implementation for bigints. + /// + /// Allows us to choose a start-index in x to store, so we can avoid + /// padding the buffer with zeros when not needed, optimized for vectors. + pub fn iadd_impl(x: &mut Vec, y: &[Limb], xstart: usize) { + // The effective x buffer is from `xstart..x.len()`, so we need to treat + // that as the current range. If the effective y buffer is longer, need + // to resize to that, + the start index. + if y.len() > x.len() - xstart { + x.resize(y.len() + xstart, 0); + } + + // Iteratively add elements from y to x. + let mut carry = false; + for (xi, yi) in x[xstart..].iter_mut().zip(y.iter()) { + // Only one op of the two can overflow, since we added at max + // Limb::max_value() + Limb::max_value(). Add the previous carry, + // and store the current carry for the next. + let mut tmp = scalar::iadd(xi, *yi); + if carry { + tmp |= scalar::iadd(xi, 1); + } + carry = tmp; + } + + // Overflow from the previous bit. + if carry { + small::iadd_impl(x, 1, y.len() + xstart); + } + } + + /// AddAssign bigint to bigint. + #[inline] + pub fn iadd(x: &mut Vec, y: &[Limb]) { + iadd_impl(x, y, 0); + } + + /// Add bigint to bigint. + #[inline] + pub fn add(x: &[Limb], y: &[Limb]) -> Vec { + let mut z = Vec::::default(); + z.extend_from_slice(x); + iadd(&mut z, y); + z + } + + // SUBTRACTION + + /// SubAssign bigint to bigint. + pub fn isub(x: &mut Vec, y: &[Limb]) { + // Basic underflow checks. + debug_assert!(greater_equal(x, y)); + + // Iteratively add elements from y to x. + let mut carry = false; + for (xi, yi) in x.iter_mut().zip(y.iter()) { + // Only one op of the two can overflow, since we added at max + // Limb::max_value() + Limb::max_value(). Add the previous carry, + // and store the current carry for the next. + let mut tmp = scalar::isub(xi, *yi); + if carry { + tmp |= scalar::isub(xi, 1); + } + carry = tmp; + } + + if carry { + small::isub_impl(x, 1, y.len()); + } else { + small::normalize(x); + } + } + + // MULTIPLICATION + + /// Number of digits to bottom-out to asymptotically slow algorithms. + /// + /// Karatsuba tends to out-perform long-multiplication at ~320-640 bits, + /// so we go halfway, while Newton division tends to out-perform + /// Algorithm D at ~1024 bits. We can toggle this for optimal performance. + pub const KARATSUBA_CUTOFF: usize = 32; + + /// Grade-school multiplication algorithm. + /// + /// Slow, naive algorithm, using limb-bit bases and just shifting left for + /// each iteration. This could be optimized with numerous other algorithms, + /// but it's extremely simple, and works in O(n*m) time, which is fine + /// by me. Each iteration, of which there are `m` iterations, requires + /// `n` multiplications, and `n` additions, or grade-school multiplication. + fn long_mul(x: &[Limb], y: &[Limb]) -> Vec { + // Using the immutable value, multiply by all the scalars in y, using + // the algorithm defined above. Use a single buffer to avoid + // frequent reallocations. Handle the first case to avoid a redundant + // addition, since we know y.len() >= 1. + let mut z: Vec = small::mul(x, y[0]); + z.resize(x.len() + y.len(), 0); + + // Handle the iterative cases. + for (i, &yi) in y[1..].iter().enumerate() { + let zi: Vec = small::mul(x, yi); + iadd_impl(&mut z, &zi, i + 1); + } + + small::normalize(&mut z); + + z + } + + /// Split two buffers into halfway, into (lo, hi). + #[inline] + pub fn karatsuba_split(z: &[Limb], m: usize) -> (&[Limb], &[Limb]) { + (&z[..m], &z[m..]) + } + + /// Karatsuba multiplication algorithm with roughly equal input sizes. + /// + /// Assumes `y.len() >= x.len()`. + fn karatsuba_mul(x: &[Limb], y: &[Limb]) -> Vec { + if y.len() <= KARATSUBA_CUTOFF { + // Bottom-out to long division for small cases. + long_mul(x, y) + } else if x.len() < y.len() / 2 { + karatsuba_uneven_mul(x, y) + } else { + // Do our 3 multiplications. + let m = y.len() / 2; + let (xl, xh) = karatsuba_split(x, m); + let (yl, yh) = karatsuba_split(y, m); + let sumx = add(xl, xh); + let sumy = add(yl, yh); + let z0 = karatsuba_mul(xl, yl); + let mut z1 = karatsuba_mul(&sumx, &sumy); + let z2 = karatsuba_mul(xh, yh); + // Properly scale z1, which is `z1 - z2 - zo`. + isub(&mut z1, &z2); + isub(&mut z1, &z0); + + // Create our result, which is equal to, in little-endian order: + // [z0, z1 - z2 - z0, z2] + // z1 must be shifted m digits (2^(32m)) over. + // z2 must be shifted 2*m digits (2^(64m)) over. + let len = z0.len().max(m + z1.len()).max(2 * m + z2.len()); + let mut result = z0; + result.reserve_exact(len - result.len()); + iadd_impl(&mut result, &z1, m); + iadd_impl(&mut result, &z2, 2 * m); + + result + } + } + + /// Karatsuba multiplication algorithm where y is substantially larger than x. + /// + /// Assumes `y.len() >= x.len()`. + fn karatsuba_uneven_mul(x: &[Limb], mut y: &[Limb]) -> Vec { + let mut result = Vec::::default(); + result.resize(x.len() + y.len(), 0); + + // This effectively is like grade-school multiplication between + // two numbers, except we're using splits on `y`, and the intermediate + // step is a Karatsuba multiplication. + let mut start = 0; + while !y.is_empty() { + let m = x.len().min(y.len()); + let (yl, yh) = karatsuba_split(y, m); + let prod = karatsuba_mul(x, yl); + iadd_impl(&mut result, &prod, start); + y = yh; + start += m; + } + small::normalize(&mut result); + + result + } + + /// Forwarder to the proper Karatsuba algorithm. + #[inline] + fn karatsuba_mul_fwd(x: &[Limb], y: &[Limb]) -> Vec { + if x.len() < y.len() { + karatsuba_mul(x, y) + } else { + karatsuba_mul(y, x) + } + } + + /// MulAssign bigint to bigint. + #[inline] + pub fn imul(x: &mut Vec, y: &[Limb]) { + if y.len() == 1 { + small::imul(x, y[0]); + } else { + // We're not really in a condition where using Karatsuba + // multiplication makes sense, so we're just going to use long + // division. ~20% speedup compared to: + // *x = karatsuba_mul_fwd(x, y); + *x = karatsuba_mul_fwd(x, y); + } + } +} // large + +// TRAITS +// ------ + +/// Traits for shared operations for big integers. +/// +/// None of these are implemented using normal traits, since these +/// are very expensive operations, and we want to deliberately +/// and explicitly use these functions. +pub(crate) trait Math: Clone + Sized + Default { + // DATA + + /// Get access to the underlying data + fn data(&self) -> &Vec; + + /// Get access to the underlying data + fn data_mut(&mut self) -> &mut Vec; + + // RELATIVE OPERATIONS + + /// Compare self to y. + #[inline] + fn compare(&self, y: &Self) -> cmp::Ordering { + large::compare(self.data(), y.data()) + } + + // PROPERTIES + + /// Get the high 64-bits from the bigint and if there are remaining bits. + #[inline] + fn hi64(&self) -> (u64, bool) { + self.data().as_slice().hi64() + } + + /// Calculate the bit-length of the big-integer. + /// Returns usize::max_value() if the value overflows, + /// IE, if `self.data().len() > usize::max_value() / 8`. + #[inline] + fn bit_length(&self) -> usize { + small::bit_length(self.data()) + } + + // INTEGER CONVERSIONS + + /// Create new big integer from u64. + #[inline] + fn from_u64(x: u64) -> Self { + let mut v = Self::default(); + let slc = split_u64(x); + v.data_mut().extend_from_slice(&slc); + v.normalize(); + v + } + + // NORMALIZE + + /// Normalize the integer, so any leading zero values are removed. + #[inline] + fn normalize(&mut self) { + small::normalize(self.data_mut()); + } + + // ADDITION + + /// AddAssign small integer. + #[inline] + fn iadd_small(&mut self, y: Limb) { + small::iadd(self.data_mut(), y); + } + + // MULTIPLICATION + + /// MulAssign small integer. + #[inline] + fn imul_small(&mut self, y: Limb) { + small::imul(self.data_mut(), y); + } + + /// Multiply by a power of 2. + #[inline] + fn imul_pow2(&mut self, n: u32) { + self.ishl(n as usize); + } + + /// Multiply by a power of 5. + #[inline] + fn imul_pow5(&mut self, n: u32) { + small::imul_pow5(self.data_mut(), n); + } + + /// MulAssign by a power of 10. + #[inline] + fn imul_pow10(&mut self, n: u32) { + self.imul_pow5(n); + self.imul_pow2(n); + } + + // SHIFTS + + /// Shift-left the entire buffer n bits. + #[inline] + fn ishl(&mut self, n: usize) { + small::ishl(self.data_mut(), n); + } +} diff --git a/third_party/crates/serde_json-1.0.151/src/lexical/mod.rs b/third_party/crates/serde_json-1.0.151/src/lexical/mod.rs new file mode 100644 index 0000000..aeed406 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/lexical/mod.rs @@ -0,0 +1,38 @@ +// The code in this module is derived from the `lexical` crate by @Alexhuszagh +// which the author condensed into this minimal subset for use in serde_json. +// For the serde_json use case we care more about reliably round tripping all +// possible floating point values than about parsing any arbitrarily long string +// of digits with perfect accuracy, as the latter would take a high cost in +// compile time and performance. +// +// Dual licensed as MIT and Apache 2.0 just like the rest of serde_json, but +// copyright Alexander Huszagh. + +//! Fast, minimal float-parsing algorithm. + +// MODULES +pub(crate) mod algorithm; +mod bhcomp; +mod bignum; +mod cached; +mod cached_float80; +mod digit; +mod errors; +pub(crate) mod exponent; +pub(crate) mod float; +mod large_powers; +pub(crate) mod math; +pub(crate) mod num; +pub(crate) mod parse; +pub(crate) mod rounding; +mod shift; +mod small_powers; + +#[cfg(fast_arithmetic = "32")] +mod large_powers32; + +#[cfg(fast_arithmetic = "64")] +mod large_powers64; + +// API +pub use self::parse::{parse_concise_float, parse_truncated_float}; diff --git a/third_party/crates/serde_json-1.0.151/src/lexical/num.rs b/third_party/crates/serde_json-1.0.151/src/lexical/num.rs new file mode 100644 index 0000000..3f39140 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/lexical/num.rs @@ -0,0 +1,421 @@ +// Adapted from https://github.com/Alexhuszagh/rust-lexical. + +//! Utilities for Rust numbers. + +use core::ops; + +/// Precalculated values of radix**i for i in range [0, arr.len()-1]. +/// Each value can be **exactly** represented as that type. +const F32_POW10: [f32; 11] = [ + 1.0, + 10.0, + 100.0, + 1000.0, + 10000.0, + 100000.0, + 1000000.0, + 10000000.0, + 100000000.0, + 1000000000.0, + 10000000000.0, +]; + +/// Precalculated values of radix**i for i in range [0, arr.len()-1]. +/// Each value can be **exactly** represented as that type. +const F64_POW10: [f64; 23] = [ + 1.0, + 10.0, + 100.0, + 1000.0, + 10000.0, + 100000.0, + 1000000.0, + 10000000.0, + 100000000.0, + 1000000000.0, + 10000000000.0, + 100000000000.0, + 1000000000000.0, + 10000000000000.0, + 100000000000000.0, + 1000000000000000.0, + 10000000000000000.0, + 100000000000000000.0, + 1000000000000000000.0, + 10000000000000000000.0, + 100000000000000000000.0, + 1000000000000000000000.0, + 10000000000000000000000.0, +]; + +/// Type that can be converted to primitive with `as`. +pub trait AsPrimitive: Sized + Copy + PartialOrd { + fn as_u32(self) -> u32; + fn as_u64(self) -> u64; + fn as_u128(self) -> u128; + fn as_usize(self) -> usize; + fn as_f32(self) -> f32; + fn as_f64(self) -> f64; +} + +macro_rules! as_primitive_impl { + ($($ty:ident)*) => { + $( + impl AsPrimitive for $ty { + #[inline] + fn as_u32(self) -> u32 { + self as u32 + } + + #[inline] + fn as_u64(self) -> u64 { + self as u64 + } + + #[inline] + fn as_u128(self) -> u128 { + self as u128 + } + + #[inline] + fn as_usize(self) -> usize { + self as usize + } + + #[inline] + fn as_f32(self) -> f32 { + self as f32 + } + + #[inline] + fn as_f64(self) -> f64 { + self as f64 + } + } + )* + }; +} + +as_primitive_impl! { u32 u64 u128 usize f32 f64 } + +/// An interface for casting between machine scalars. +pub trait AsCast: AsPrimitive { + /// Creates a number from another value that can be converted into + /// a primitive via the `AsPrimitive` trait. + fn as_cast(n: N) -> Self; +} + +macro_rules! as_cast_impl { + ($ty:ident, $method:ident) => { + impl AsCast for $ty { + #[inline] + fn as_cast(n: N) -> Self { + n.$method() + } + } + }; +} + +as_cast_impl!(u32, as_u32); +as_cast_impl!(u64, as_u64); +as_cast_impl!(u128, as_u128); +as_cast_impl!(usize, as_usize); +as_cast_impl!(f32, as_f32); +as_cast_impl!(f64, as_f64); + +/// Numerical type trait. +pub trait Number: AsCast + ops::Add {} + +macro_rules! number_impl { + ($($ty:ident)*) => { + $( + impl Number for $ty {} + )* + }; +} + +number_impl! { u32 u64 u128 usize f32 f64 } + +/// Defines a trait that supports integral operations. +pub trait Integer: Number + ops::BitAnd + ops::Shr { + const ZERO: Self; +} + +macro_rules! integer_impl { + ($($ty:tt)*) => { + $( + impl Integer for $ty { + const ZERO: Self = 0; + } + )* + }; +} + +integer_impl! { u32 u64 u128 usize } + +/// Type trait for the mantissa type. +pub trait Mantissa: Integer { + /// Mask to extract the high bits from the integer. + const HIMASK: Self; + /// Mask to extract the low bits from the integer. + const LOMASK: Self; + /// Full size of the integer, in bits. + const FULL: i32; + /// Half size of the integer, in bits. + const HALF: i32 = Self::FULL / 2; +} + +impl Mantissa for u64 { + const HIMASK: u64 = 0xFFFFFFFF00000000; + const LOMASK: u64 = 0x00000000FFFFFFFF; + const FULL: i32 = 64; +} + +/// Get exact exponent limit for radix. +pub trait Float: Number { + /// Unsigned type of the same size. + type Unsigned: Integer; + + /// Literal zero. + const ZERO: Self; + /// Maximum number of digits that can contribute in the mantissa. + /// + /// We can exactly represent a float in radix `b` from radix 2 if + /// `b` is divisible by 2. This function calculates the exact number of + /// digits required to exactly represent that float. + /// + /// According to the "Handbook of Floating Point Arithmetic", + /// for IEEE754, with emin being the min exponent, p2 being the + /// precision, and b being the radix, the number of digits follows as: + /// + /// `−emin + p2 + ⌊(emin + 1) log(2, b) − log(1 − 2^(−p2), b)⌋` + /// + /// For f32, this follows as: + /// emin = -126 + /// p2 = 24 + /// + /// For f64, this follows as: + /// emin = -1022 + /// p2 = 53 + /// + /// In Python: + /// `-emin + p2 + math.floor((emin+1)*math.log(2, b) - math.log(1-2**(-p2), b))` + /// + /// This was used to calculate the maximum number of digits for [2, 36]. + const MAX_DIGITS: usize; + + // MASKS + + /// Bitmask for the exponent, including the hidden bit. + const EXPONENT_MASK: Self::Unsigned; + /// Bitmask for the hidden bit in exponent, which is an implicit 1 in the fraction. + const HIDDEN_BIT_MASK: Self::Unsigned; + /// Bitmask for the mantissa (fraction), excluding the hidden bit. + const MANTISSA_MASK: Self::Unsigned; + + // PROPERTIES + + /// Positive infinity as bits. + const INFINITY_BITS: Self::Unsigned; + /// Size of the significand (mantissa) without hidden bit. + const MANTISSA_SIZE: i32; + /// Bias of the exponent + const EXPONENT_BIAS: i32; + /// Exponent portion of a denormal float. + const DENORMAL_EXPONENT: i32; + /// Maximum exponent value in float. + const MAX_EXPONENT: i32; + + // ROUNDING + + /// Default number of bits to shift (or 64 - mantissa size - 1). + const DEFAULT_SHIFT: i32; + /// Mask to determine if a full-carry occurred (1 in bit above hidden bit). + const CARRY_MASK: u64; + + /// Get min and max exponent limits (exact) from radix. + fn exponent_limit() -> (i32, i32); + + /// Get the number of digits that can be shifted from exponent to mantissa. + fn mantissa_limit() -> i32; + + // Re-exported methods from std. + fn pow10(self, n: i32) -> Self; + fn from_bits(u: Self::Unsigned) -> Self; + fn to_bits(self) -> Self::Unsigned; + fn is_sign_positive(self) -> bool; + + /// Returns true if the float is a denormal. + #[inline] + fn is_denormal(self) -> bool { + self.to_bits() & Self::EXPONENT_MASK == Self::Unsigned::ZERO + } + + /// Returns true if the float is a NaN or Infinite. + #[inline] + fn is_special(self) -> bool { + self.to_bits() & Self::EXPONENT_MASK == Self::EXPONENT_MASK + } + + /// Returns true if the float is infinite. + #[inline] + fn is_inf(self) -> bool { + self.is_special() && (self.to_bits() & Self::MANTISSA_MASK) == Self::Unsigned::ZERO + } + + /// Get exponent component from the float. + #[inline] + fn exponent(self) -> i32 { + if self.is_denormal() { + return Self::DENORMAL_EXPONENT; + } + + let bits = self.to_bits(); + let biased_e = ((bits & Self::EXPONENT_MASK) >> Self::MANTISSA_SIZE).as_u32(); + biased_e as i32 - Self::EXPONENT_BIAS + } + + /// Get mantissa (significand) component from float. + #[inline] + fn mantissa(self) -> Self::Unsigned { + let bits = self.to_bits(); + let s = bits & Self::MANTISSA_MASK; + if !self.is_denormal() { + s + Self::HIDDEN_BIT_MASK + } else { + s + } + } + + /// Get next greater float for a positive float. + /// Value must be >= 0.0 and < INFINITY. + #[inline] + fn next_positive(self) -> Self { + debug_assert!(self.is_sign_positive() && !self.is_inf()); + Self::from_bits(self.to_bits() + Self::Unsigned::as_cast(1u32)) + } + + /// Round a positive number to even. + #[inline] + fn round_positive_even(self) -> Self { + if self.mantissa() & Self::Unsigned::as_cast(1u32) == Self::Unsigned::as_cast(1u32) { + self.next_positive() + } else { + self + } + } +} + +impl Float for f32 { + type Unsigned = u32; + + const ZERO: f32 = 0.0; + const MAX_DIGITS: usize = 114; + const EXPONENT_MASK: u32 = 0x7F800000; + const HIDDEN_BIT_MASK: u32 = 0x00800000; + const MANTISSA_MASK: u32 = 0x007FFFFF; + const INFINITY_BITS: u32 = 0x7F800000; + const MANTISSA_SIZE: i32 = 23; + const EXPONENT_BIAS: i32 = 127 + Self::MANTISSA_SIZE; + const DENORMAL_EXPONENT: i32 = 1 - Self::EXPONENT_BIAS; + const MAX_EXPONENT: i32 = 0xFF - Self::EXPONENT_BIAS; + const DEFAULT_SHIFT: i32 = u64::FULL - f32::MANTISSA_SIZE - 1; + const CARRY_MASK: u64 = 0x1000000; + + #[inline] + fn exponent_limit() -> (i32, i32) { + (-10, 10) + } + + #[inline] + fn mantissa_limit() -> i32 { + 7 + } + + #[inline] + fn pow10(self, n: i32) -> f32 { + // Check the exponent is within bounds in debug builds. + debug_assert!({ + let (min, max) = Self::exponent_limit(); + n >= min && n <= max + }); + + if n > 0 { + self * F32_POW10[n as usize] + } else { + self / F32_POW10[-n as usize] + } + } + + #[inline] + fn from_bits(u: u32) -> f32 { + f32::from_bits(u) + } + + #[inline] + fn to_bits(self) -> u32 { + f32::to_bits(self) + } + + #[inline] + fn is_sign_positive(self) -> bool { + f32::is_sign_positive(self) + } +} + +impl Float for f64 { + type Unsigned = u64; + + const ZERO: f64 = 0.0; + const MAX_DIGITS: usize = 769; + const EXPONENT_MASK: u64 = 0x7FF0000000000000; + const HIDDEN_BIT_MASK: u64 = 0x0010000000000000; + const MANTISSA_MASK: u64 = 0x000FFFFFFFFFFFFF; + const INFINITY_BITS: u64 = 0x7FF0000000000000; + const MANTISSA_SIZE: i32 = 52; + const EXPONENT_BIAS: i32 = 1023 + Self::MANTISSA_SIZE; + const DENORMAL_EXPONENT: i32 = 1 - Self::EXPONENT_BIAS; + const MAX_EXPONENT: i32 = 0x7FF - Self::EXPONENT_BIAS; + const DEFAULT_SHIFT: i32 = u64::FULL - f64::MANTISSA_SIZE - 1; + const CARRY_MASK: u64 = 0x20000000000000; + + #[inline] + fn exponent_limit() -> (i32, i32) { + (-22, 22) + } + + #[inline] + fn mantissa_limit() -> i32 { + 15 + } + + #[inline] + fn pow10(self, n: i32) -> f64 { + // Check the exponent is within bounds in debug builds. + debug_assert!({ + let (min, max) = Self::exponent_limit(); + n >= min && n <= max + }); + + if n > 0 { + self * F64_POW10[n as usize] + } else { + self / F64_POW10[-n as usize] + } + } + + #[inline] + fn from_bits(u: u64) -> f64 { + f64::from_bits(u) + } + + #[inline] + fn to_bits(self) -> u64 { + f64::to_bits(self) + } + + #[inline] + fn is_sign_positive(self) -> bool { + f64::is_sign_positive(self) + } +} diff --git a/third_party/crates/serde_json-1.0.151/src/lexical/parse.rs b/third_party/crates/serde_json-1.0.151/src/lexical/parse.rs new file mode 100644 index 0000000..e3d7f1e --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/lexical/parse.rs @@ -0,0 +1,83 @@ +// Adapted from https://github.com/Alexhuszagh/rust-lexical. + +use super::algorithm::*; +use super::bhcomp::*; +use super::digit::*; +use super::exponent::*; +use super::num::*; + +// PARSERS +// ------- + +/// Parse float for which the entire integer and fraction parts fit into a 64 +/// bit mantissa. +pub fn parse_concise_float(mantissa: u64, mant_exp: i32) -> F +where + F: Float, +{ + if let Some(float) = fast_path(mantissa, mant_exp) { + return float; + } + + // Moderate path (use an extended 80-bit representation). + let truncated = false; + let (fp, valid) = moderate_path::(mantissa, mant_exp, truncated); + if valid { + return fp.into_float::(); + } + + let b = fp.into_downward_float::(); + if b.is_special() { + // We have a non-finite number, we get to leave early. + return b; + } + + // Slow path, fast path didn't work. + let mut buffer = itoa::Buffer::new(); + let integer = buffer.format(mantissa).as_bytes(); + let fraction = &[]; + bhcomp(b, integer, fraction, mant_exp) +} + +/// Parse float from extracted float components. +/// +/// * `integer` - Slice containing the integer digits. +/// * `fraction` - Slice containing the fraction digits. +/// * `exponent` - Parsed, 32-bit exponent. +/// +/// Precondition: The integer must not have leading zeros. +pub fn parse_truncated_float(integer: &[u8], mut fraction: &[u8], exponent: i32) -> F +where + F: Float, +{ + // Trim trailing zeroes from the fraction part. + while fraction.last() == Some(&b'0') { + fraction = &fraction[..fraction.len() - 1]; + } + + // Calculate the number of truncated digits. + let mut truncated = 0; + let mut mantissa: u64 = 0; + let mut iter = integer.iter().chain(fraction); + for &c in &mut iter { + mantissa = match add_digit(mantissa, to_digit(c).unwrap()) { + Some(v) => v, + None => { + truncated = 1 + iter.count(); + break; + } + }; + } + + let mant_exp = mantissa_exponent(exponent, fraction.len(), truncated); + let is_truncated = true; + + fallback_path( + integer, + fraction, + mantissa, + exponent, + mant_exp, + is_truncated, + ) +} diff --git a/third_party/crates/serde_json-1.0.151/src/lexical/rounding.rs b/third_party/crates/serde_json-1.0.151/src/lexical/rounding.rs new file mode 100644 index 0000000..6344875 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/lexical/rounding.rs @@ -0,0 +1,231 @@ +// Adapted from https://github.com/Alexhuszagh/rust-lexical. + +//! Defines rounding schemes for floating-point numbers. + +use super::float::ExtendedFloat; +use super::num::*; +use super::shift::*; +use core::mem; + +// MASKS + +/// Calculate a scalar factor of 2 above the halfway point. +#[inline] +pub(crate) fn nth_bit(n: u64) -> u64 { + let bits: u64 = mem::size_of::() as u64 * 8; + debug_assert!(n < bits, "nth_bit() overflow in shl."); + + 1 << n +} + +/// Generate a bitwise mask for the lower `n` bits. +#[inline] +pub(crate) fn lower_n_mask(n: u64) -> u64 { + let bits: u64 = mem::size_of::() as u64 * 8; + debug_assert!(n <= bits, "lower_n_mask() overflow in shl."); + + if n == bits { + u64::MAX + } else { + (1 << n) - 1 + } +} + +/// Calculate the halfway point for the lower `n` bits. +#[inline] +pub(crate) fn lower_n_halfway(n: u64) -> u64 { + let bits: u64 = mem::size_of::() as u64 * 8; + debug_assert!(n <= bits, "lower_n_halfway() overflow in shl."); + + if n == 0 { + 0 + } else { + nth_bit(n - 1) + } +} + +/// Calculate a bitwise mask with `n` 1 bits starting at the `bit` position. +#[inline] +pub(crate) fn internal_n_mask(bit: u64, n: u64) -> u64 { + let bits: u64 = mem::size_of::() as u64 * 8; + debug_assert!(bit <= bits, "internal_n_halfway() overflow in shl."); + debug_assert!(n <= bits, "internal_n_halfway() overflow in shl."); + debug_assert!(bit >= n, "internal_n_halfway() overflow in sub."); + + lower_n_mask(bit) ^ lower_n_mask(bit - n) +} + +// NEAREST ROUNDING + +// Shift right N-bytes and round to the nearest. +// +// Return if we are above halfway and if we are halfway. +#[inline] +pub(crate) fn round_nearest(fp: &mut ExtendedFloat, shift: i32) -> (bool, bool) { + // Extract the truncated bits using mask. + // Calculate if the value of the truncated bits are either above + // the mid-way point, or equal to it. + // + // For example, for 4 truncated bytes, the mask would be b1111 + // and the midway point would be b1000. + let mask: u64 = lower_n_mask(shift as u64); + let halfway: u64 = lower_n_halfway(shift as u64); + + let truncated_bits = fp.mant & mask; + let is_above = truncated_bits > halfway; + let is_halfway = truncated_bits == halfway; + + // Bit shift so the leading bit is in the hidden bit. + overflowing_shr(fp, shift); + + (is_above, is_halfway) +} + +// Tie rounded floating point to event. +#[inline] +pub(crate) fn tie_even(fp: &mut ExtendedFloat, is_above: bool, is_halfway: bool) { + // Extract the last bit after shifting (and determine if it is odd). + let is_odd = fp.mant & 1 == 1; + + // Calculate if we need to roundup. + // We need to roundup if we are above halfway, or if we are odd + // and at half-way (need to tie-to-even). + if is_above || (is_odd && is_halfway) { + fp.mant += 1; + } +} + +// Shift right N-bytes and round nearest, tie-to-even. +// +// Floating-point arithmetic uses round to nearest, ties to even, +// which rounds to the nearest value, if the value is halfway in between, +// round to an even value. +#[inline] +pub(crate) fn round_nearest_tie_even(fp: &mut ExtendedFloat, shift: i32) { + let (is_above, is_halfway) = round_nearest(fp, shift); + tie_even(fp, is_above, is_halfway); +} + +// DIRECTED ROUNDING + +// Shift right N-bytes and round towards a direction. +// +// Return if we have any truncated bytes. +#[inline] +fn round_toward(fp: &mut ExtendedFloat, shift: i32) -> bool { + let mask: u64 = lower_n_mask(shift as u64); + let truncated_bits = fp.mant & mask; + + // Bit shift so the leading bit is in the hidden bit. + overflowing_shr(fp, shift); + + truncated_bits != 0 +} + +// Round down. +#[inline] +fn downard(_: &mut ExtendedFloat, _: bool) {} + +// Shift right N-bytes and round toward zero. +// +// Floating-point arithmetic defines round toward zero, which rounds +// towards positive zero. +#[inline] +pub(crate) fn round_downward(fp: &mut ExtendedFloat, shift: i32) { + // Bit shift so the leading bit is in the hidden bit. + // No rounding schemes, so we just ignore everything else. + let is_truncated = round_toward(fp, shift); + downard(fp, is_truncated); +} + +// ROUND TO FLOAT + +// Shift the ExtendedFloat fraction to the fraction bits in a native float. +// +// Floating-point arithmetic uses round to nearest, ties to even, +// which rounds to the nearest value, if the value is halfway in between, +// round to an even value. +#[inline] +pub(crate) fn round_to_float(fp: &mut ExtendedFloat, algorithm: Algorithm) +where + F: Float, + Algorithm: FnOnce(&mut ExtendedFloat, i32), +{ + // Calculate the difference to allow a single calculation + // rather than a loop, to minimize the number of ops required. + // This does underflow detection. + let final_exp = fp.exp + F::DEFAULT_SHIFT; + if final_exp < F::DENORMAL_EXPONENT { + // We would end up with a denormal exponent, try to round to more + // digits. Only shift right if we can avoid zeroing out the value, + // which requires the exponent diff to be < M::BITS. The value + // is already normalized, so we shouldn't have any issue zeroing + // out the value. + let diff = F::DENORMAL_EXPONENT - fp.exp; + if diff <= u64::FULL { + // We can avoid underflow, can get a valid representation. + algorithm(fp, diff); + } else { + // Certain underflow, assign literal 0s. + fp.mant = 0; + fp.exp = 0; + } + } else { + algorithm(fp, F::DEFAULT_SHIFT); + } + + if fp.mant & F::CARRY_MASK == F::CARRY_MASK { + // Roundup carried over to 1 past the hidden bit. + shr(fp, 1); + } +} + +// AVOID OVERFLOW/UNDERFLOW + +// Avoid overflow for large values, shift left as needed. +// +// Shift until a 1-bit is in the hidden bit, if the mantissa is not 0. +#[inline] +pub(crate) fn avoid_overflow(fp: &mut ExtendedFloat) +where + F: Float, +{ + // Calculate the difference to allow a single calculation + // rather than a loop, minimizing the number of ops required. + if fp.exp >= F::MAX_EXPONENT { + let diff = fp.exp - F::MAX_EXPONENT; + if diff <= F::MANTISSA_SIZE { + // Our overflow mask needs to start at the hidden bit, or at + // `F::MANTISSA_SIZE+1`, and needs to have `diff+1` bits set, + // to see if our value overflows. + let bit = (F::MANTISSA_SIZE + 1) as u64; + let n = (diff + 1) as u64; + let mask = internal_n_mask(bit, n); + if (fp.mant & mask) == 0 { + // If we have no 1-bit in the hidden-bit position, + // which is index 0, we need to shift 1. + let shift = diff + 1; + shl(fp, shift); + } + } + } +} + +// ROUND TO NATIVE + +// Round an extended-precision float to a native float representation. +#[inline] +pub(crate) fn round_to_native(fp: &mut ExtendedFloat, algorithm: Algorithm) +where + F: Float, + Algorithm: FnOnce(&mut ExtendedFloat, i32), +{ + // Shift all the way left, to ensure a consistent representation. + // The following right-shifts do not work for a non-normalized number. + fp.normalize(); + + // Round so the fraction is in a native mantissa representation, + // and avoid overflow/underflow. + round_to_float::(fp, algorithm); + avoid_overflow::(fp); +} diff --git a/third_party/crates/serde_json-1.0.151/src/lexical/shift.rs b/third_party/crates/serde_json-1.0.151/src/lexical/shift.rs new file mode 100644 index 0000000..a0bae01 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/lexical/shift.rs @@ -0,0 +1,46 @@ +// Adapted from https://github.com/Alexhuszagh/rust-lexical. + +//! Bit-shift helpers. + +use super::float::ExtendedFloat; +use core::mem; + +// Shift extended-precision float right `shift` bytes. +#[inline] +pub(crate) fn shr(fp: &mut ExtendedFloat, shift: i32) { + let bits: u64 = mem::size_of::() as u64 * 8; + debug_assert!((shift as u64) < bits, "shr() overflow in shift right."); + + fp.mant >>= shift; + fp.exp += shift; +} + +// Shift extended-precision float right `shift` bytes. +// +// Accepts when the shift is the same as the type size, and +// sets the value to 0. +#[inline] +pub(crate) fn overflowing_shr(fp: &mut ExtendedFloat, shift: i32) { + let bits: u64 = mem::size_of::() as u64 * 8; + debug_assert!( + (shift as u64) <= bits, + "overflowing_shr() overflow in shift right." + ); + + fp.mant = if shift as u64 == bits { + 0 + } else { + fp.mant >> shift + }; + fp.exp += shift; +} + +// Shift extended-precision float left `shift` bytes. +#[inline] +pub(crate) fn shl(fp: &mut ExtendedFloat, shift: i32) { + let bits: u64 = mem::size_of::() as u64 * 8; + debug_assert!((shift as u64) < bits, "shl() overflow in shift left."); + + fp.mant <<= shift; + fp.exp -= shift; +} diff --git a/third_party/crates/serde_json-1.0.151/src/lexical/small_powers.rs b/third_party/crates/serde_json-1.0.151/src/lexical/small_powers.rs new file mode 100644 index 0000000..29b83a1 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/lexical/small_powers.rs @@ -0,0 +1,70 @@ +// Adapted from https://github.com/Alexhuszagh/rust-lexical. + +//! Pre-computed small powers. + +// 32 BIT +#[cfg(fast_arithmetic = "32")] +pub(crate) const POW5_32: [u32; 14] = [ + 1, 5, 25, 125, 625, 3125, 15625, 78125, 390625, 1953125, 9765625, 48828125, 244140625, + 1220703125, +]; + +#[cfg(fast_arithmetic = "32")] +pub(crate) const POW10_32: [u32; 10] = [ + 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, +]; + +// 64 BIT +#[cfg(fast_arithmetic = "64")] +pub(crate) const POW5_64: [u64; 28] = [ + 1, + 5, + 25, + 125, + 625, + 3125, + 15625, + 78125, + 390625, + 1953125, + 9765625, + 48828125, + 244140625, + 1220703125, + 6103515625, + 30517578125, + 152587890625, + 762939453125, + 3814697265625, + 19073486328125, + 95367431640625, + 476837158203125, + 2384185791015625, + 11920928955078125, + 59604644775390625, + 298023223876953125, + 1490116119384765625, + 7450580596923828125, +]; +pub(crate) const POW10_64: [u64; 20] = [ + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000, + 100000000000, + 1000000000000, + 10000000000000, + 100000000000000, + 1000000000000000, + 10000000000000000, + 100000000000000000, + 1000000000000000000, + 10000000000000000000, +]; diff --git a/third_party/crates/serde_json-1.0.151/src/lib.rs b/third_party/crates/serde_json-1.0.151/src/lib.rs new file mode 100644 index 0000000..ad2820b --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/lib.rs @@ -0,0 +1,441 @@ +//! # Serde JSON +//! +//! JSON is a ubiquitous open-standard format that uses human-readable text to +//! transmit data objects consisting of key-value pairs. +//! +//! ```json +//! { +//! "name": "John Doe", +//! "age": 43, +//! "address": { +//! "street": "10 Downing Street", +//! "city": "London" +//! }, +//! "phones": [ +//! "+44 1234567", +//! "+44 2345678" +//! ] +//! } +//! ``` +//! +//! There are three common ways that you might find yourself needing to work +//! with JSON data in Rust. +//! +//! - **As text data.** An unprocessed string of JSON data that you receive on +//! an HTTP endpoint, read from a file, or prepare to send to a remote +//! server. +//! - **As an untyped or loosely typed representation.** Maybe you want to +//! check that some JSON data is valid before passing it on, but without +//! knowing the structure of what it contains. Or you want to do very basic +//! manipulations like insert a key in a particular spot. +//! - **As a strongly typed Rust data structure.** When you expect all or most +//! of your data to conform to a particular structure and want to get real +//! work done without JSON's loosey-goosey nature tripping you up. +//! +//! Serde JSON provides efficient, flexible, safe ways of converting data +//! between each of these representations. +//! +//! # Operating on untyped JSON values +//! +//! Any valid JSON data can be manipulated in the following recursive enum +//! representation. This data structure is [`serde_json::Value`][value]. +//! +//! ``` +//! # use serde_json::{Number, Map}; +//! # +//! # #[allow(dead_code)] +//! enum Value { +//! Null, +//! Bool(bool), +//! Number(Number), +//! String(String), +//! Array(Vec), +//! Object(Map), +//! } +//! ``` +//! +//! A string of JSON data can be parsed into a `serde_json::Value` by the +//! [`serde_json::from_str`][from_str] function. There is also [`from_slice`] +//! for parsing from a byte slice `&[u8]` and [`from_reader`] for parsing from +//! any `io::Read` like a File or a TCP stream. +//! +//! ``` +//! use serde_json::{Result, Value}; +//! +//! fn untyped_example() -> Result<()> { +//! // Some JSON input data as a &str. Maybe this comes from the user. +//! let data = r#" +//! { +//! "name": "John Doe", +//! "age": 43, +//! "phones": [ +//! "+44 1234567", +//! "+44 2345678" +//! ] +//! }"#; +//! +//! // Parse the string of data into serde_json::Value. +//! let v: Value = serde_json::from_str(data)?; +//! +//! // Access parts of the data by indexing with square brackets. +//! println!("Please call {} at the number {}", v["name"], v["phones"][0]); +//! +//! Ok(()) +//! } +//! # +//! # fn main() { +//! # untyped_example().unwrap(); +//! # } +//! ``` +//! +//! The result of square bracket indexing like `v["name"]` is a borrow of the +//! data at that index, so the type is `&Value`. A JSON map can be indexed with +//! string keys, while a JSON array can be indexed with integer keys. If the +//! type of the data is not right for the type with which it is being indexed, +//! or if a map does not contain the key being indexed, or if the index into a +//! vector is out of bounds, the returned element is `Value::Null`. +//! +//! When a `Value` is printed, it is printed as a JSON string. So in the code +//! above, the output looks like `Please call "John Doe" at the number "+44 +//! 1234567"`. The quotation marks appear because `v["name"]` is a `&Value` +//! containing a JSON string and its JSON representation is `"John Doe"`. +//! Printing as a plain string without quotation marks involves converting from +//! a JSON string to a Rust string with [`as_str()`] or avoiding the use of +//! `Value` as described in the following section. +//! +//! [`as_str()`]: crate::Value::as_str +//! +//! The `Value` representation is sufficient for very basic tasks but can be +//! tedious to work with for anything more significant. Error handling is +//! verbose to implement correctly, for example imagine trying to detect the +//! presence of unrecognized fields in the input data. The compiler is powerless +//! to help you when you make a mistake, for example imagine typoing `v["name"]` +//! as `v["nmae"]` in one of the dozens of places it is used in your code. +//! +//! # Parsing JSON as strongly typed data structures +//! +//! Serde provides a powerful way of mapping JSON data into Rust data structures +//! largely automatically. +//! +//! ``` +//! use serde::{Deserialize, Serialize}; +//! use serde_json::Result; +//! +//! #[derive(Serialize, Deserialize)] +//! struct Person { +//! name: String, +//! age: u8, +//! phones: Vec, +//! } +//! +//! fn typed_example() -> Result<()> { +//! // Some JSON input data as a &str. Maybe this comes from the user. +//! let data = r#" +//! { +//! "name": "John Doe", +//! "age": 43, +//! "phones": [ +//! "+44 1234567", +//! "+44 2345678" +//! ] +//! }"#; +//! +//! // Parse the string of data into a Person object. This is exactly the +//! // same function as the one that produced serde_json::Value above, but +//! // now we are asking it for a Person as output. +//! let p: Person = serde_json::from_str(data)?; +//! +//! // Do things just like with any other Rust data structure. +//! println!("Please call {} at the number {}", p.name, p.phones[0]); +//! +//! Ok(()) +//! } +//! # +//! # fn main() { +//! # typed_example().unwrap(); +//! # } +//! ``` +//! +//! This is the same `serde_json::from_str` function as before, but this time we +//! assign the return value to a variable of type `Person` so Serde will +//! automatically interpret the input data as a `Person` and produce informative +//! error messages if the layout does not conform to what a `Person` is expected +//! to look like. +//! +//! Any type that implements Serde's `Deserialize` trait can be deserialized +//! this way. This includes built-in Rust standard library types like `Vec` +//! and `HashMap`, as well as any structs or enums annotated with +//! `#[derive(Deserialize)]`. +//! +//! Once we have `p` of type `Person`, our IDE and the Rust compiler can help us +//! use it correctly like they do for any other Rust code. The IDE can +//! autocomplete field names to prevent typos, which was impossible in the +//! `serde_json::Value` representation. And the Rust compiler can check that +//! when we write `p.phones[0]`, then `p.phones` is guaranteed to be a +//! `Vec` so indexing into it makes sense and produces a `String`. +//! +//! # Constructing JSON values +//! +//! Serde JSON provides a [`json!` macro][macro] to build `serde_json::Value` +//! objects with very natural JSON syntax. +//! +//! ``` +//! use serde_json::json; +//! +//! fn main() { +//! // The type of `john` is `serde_json::Value` +//! let john = json!({ +//! "name": "John Doe", +//! "age": 43, +//! "phones": [ +//! "+44 1234567", +//! "+44 2345678" +//! ] +//! }); +//! +//! println!("first phone number: {}", john["phones"][0]); +//! +//! // Convert to a string of JSON and print it out +//! println!("{}", john.to_string()); +//! } +//! ``` +//! +//! The `Value::to_string()` function converts a `serde_json::Value` into a +//! `String` of JSON text. +//! +//! One neat thing about the `json!` macro is that variables and expressions can +//! be interpolated directly into the JSON value as you are building it. Serde +//! will check at compile time that the value you are interpolating is able to +//! be represented as JSON. +//! +//! ``` +//! # use serde_json::json; +//! # +//! # fn random_phone() -> u16 { 0 } +//! # +//! let full_name = "John Doe"; +//! let age_last_year = 42; +//! +//! // The type of `john` is `serde_json::Value` +//! let john = json!({ +//! "name": full_name, +//! "age": age_last_year + 1, +//! "phones": [ +//! format!("+44 {}", random_phone()) +//! ] +//! }); +//! ``` +//! +//! This is amazingly convenient, but we have the problem we had before with +//! `Value`: the IDE and Rust compiler cannot help us if we get it wrong. Serde +//! JSON provides a better way of serializing strongly-typed data structures +//! into JSON text. +//! +//! # Creating JSON by serializing data structures +//! +//! A data structure can be converted to a JSON string by +//! [`serde_json::to_string`][to_string]. There is also +//! [`serde_json::to_vec`][to_vec] which serializes to a `Vec` and +//! [`serde_json::to_writer`][to_writer] which serializes to any `io::Write` +//! such as a File or a TCP stream. +//! +//! ``` +//! use serde::{Deserialize, Serialize}; +//! use serde_json::Result; +//! +//! #[derive(Serialize, Deserialize)] +//! struct Address { +//! street: String, +//! city: String, +//! } +//! +//! fn print_an_address() -> Result<()> { +//! // Some data structure. +//! let address = Address { +//! street: "10 Downing Street".to_owned(), +//! city: "London".to_owned(), +//! }; +//! +//! // Serialize it to a JSON string. +//! let j = serde_json::to_string(&address)?; +//! +//! // Print, write to a file, or send to an HTTP server. +//! println!("{}", j); +//! +//! Ok(()) +//! } +//! # +//! # fn main() { +//! # print_an_address().unwrap(); +//! # } +//! ``` +//! +//! Any type that implements Serde's `Serialize` trait can be serialized this +//! way. This includes built-in Rust standard library types like `Vec` and +//! `HashMap`, as well as any structs or enums annotated with +//! `#[derive(Serialize)]`. +//! +//! # No-std support +//! +//! As long as there is a memory allocator, it is possible to use serde_json +//! without the rest of the Rust standard library. Disable the default "std" +//! feature and enable the "alloc" feature: +//! +//! ```toml +//! [dependencies] +//! serde_json = { version = "1.0", default-features = false, features = ["alloc"] } +//! ``` +//! +//! For JSON support in Serde without a memory allocator, please see the +//! [`serde-json-core`] crate. +//! +//! [value]: crate::value::Value +//! [from_str]: crate::de::from_str +//! [from_slice]: crate::de::from_slice +//! [from_reader]: crate::de::from_reader +//! [to_string]: crate::ser::to_string +//! [to_vec]: crate::ser::to_vec +//! [to_writer]: crate::ser::to_writer +//! [macro]: crate::json +//! [`serde-json-core`]: https://github.com/rust-embedded-community/serde-json-core + +#![doc(html_root_url = "https://docs.rs/serde_json/1.0.151")] +// Ignored clippy lints +#![allow( + clippy::collapsible_else_if, + clippy::comparison_chain, + clippy::deprecated_cfg_attr, + clippy::doc_markdown, + clippy::elidable_lifetime_names, + clippy::excessive_precision, + clippy::explicit_auto_deref, + clippy::float_cmp, + clippy::manual_range_contains, + clippy::match_like_matches_macro, + clippy::match_single_binding, + clippy::needless_doctest_main, + clippy::needless_late_init, + clippy::needless_lifetimes, + clippy::return_self_not_must_use, + clippy::transmute_ptr_to_ptr, + clippy::unbuffered_bytes, + clippy::unconditional_recursion, // https://github.com/rust-lang/rust-clippy/issues/12133 + clippy::uninlined_format_args, + clippy::unnecessary_wraps +)] +// Ignored clippy_pedantic lints +#![allow( + // Deserializer::from_str, into_iter + clippy::should_implement_trait, + // 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, + // correctly used + clippy::enum_glob_use, + clippy::if_not_else, + clippy::integer_division, + clippy::let_underscore_untyped, + clippy::map_err_ignore, + clippy::match_same_arms, + clippy::similar_names, + clippy::unused_self, + clippy::wildcard_imports, + // things are often more readable this way + clippy::cast_lossless, + clippy::items_after_statements, + clippy::module_name_repetitions, + clippy::redundant_else, + clippy::shadow_unrelated, + clippy::single_match_else, + clippy::too_many_lines, + clippy::unreadable_literal, + clippy::unseparated_literal_suffix, + clippy::use_self, + clippy::zero_prefixed_literal, + // we support older compilers + clippy::checked_conversions, + clippy::mem_replace_with_default, + // noisy + clippy::missing_errors_doc, + clippy::must_use_candidate, +)] +// Restrictions +#![deny(clippy::question_mark_used)] +#![allow(non_upper_case_globals)] +#![deny(missing_docs)] +#![no_std] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![allow(unknown_lints, mismatched_lifetime_syntaxes)] + +#[cfg(not(any(feature = "std", feature = "alloc")))] +compile_error! { + "serde_json requires that either `std` (default) or `alloc` feature is enabled" +} + +extern crate alloc; + +#[cfg(feature = "std")] +extern crate std; + +extern crate serde_core as serde; + +// Not public API. Used from macro-generated code. +#[doc(hidden)] +pub mod __private { + #[doc(hidden)] + pub use alloc::vec; +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +#[doc(inline)] +pub use crate::de::from_reader; +#[doc(inline)] +pub use crate::de::{from_slice, from_str, Deserializer, StreamDeserializer}; +#[doc(inline)] +pub use crate::error::{Error, Result}; +#[doc(inline)] +pub use crate::ser::{to_string, to_string_pretty, to_vec, to_vec_pretty}; +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +#[doc(inline)] +pub use crate::ser::{to_writer, to_writer_pretty, Serializer}; +#[doc(inline)] +pub use crate::value::{from_value, to_value, Map, Number, Value}; + +// We only use our own error type; no need for From conversions provided by the +// standard library's try! macro. This reduces lines of LLVM IR by 4%. +macro_rules! tri { + ($e:expr $(,)?) => { + match $e { + core::result::Result::Ok(val) => val, + core::result::Result::Err(err) => return core::result::Result::Err(err), + } + }; +} + +#[macro_use] +mod macros; + +pub mod de; +pub mod error; +pub mod map; +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +pub mod ser; +#[cfg(not(feature = "std"))] +mod ser; +pub mod value; + +mod io; +#[cfg(feature = "std")] +mod iter; +#[cfg(feature = "float_roundtrip")] +mod lexical; +mod number; +mod read; + +#[cfg(feature = "raw_value")] +mod raw; diff --git a/third_party/crates/serde_json-1.0.151/src/macros.rs b/third_party/crates/serde_json-1.0.151/src/macros.rs new file mode 100644 index 0000000..2955e4a --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/macros.rs @@ -0,0 +1,303 @@ +/// Construct a `serde_json::Value` from a JSON literal. +/// +/// ``` +/// # use serde_json::json; +/// # +/// let value = json!({ +/// "code": 200, +/// "success": true, +/// "payload": { +/// "features": [ +/// "serde", +/// "json" +/// ], +/// "homepage": null +/// } +/// }); +/// ``` +/// +/// Variables or expressions can be interpolated into the JSON literal. Any type +/// interpolated into an array element or object value must implement Serde's +/// `Serialize` trait, while any type interpolated into an object key must +/// implement `Into`. If the `Serialize` implementation of the +/// interpolated type decides to fail, or if the interpolated type contains a +/// map with non-string keys, the `json!` macro will panic. +/// +/// ``` +/// # use serde_json::json; +/// # +/// let code = 200; +/// let features = vec!["serde", "json"]; +/// +/// let value = json!({ +/// "code": code, +/// "success": code == 200, +/// "payload": { +/// features[0]: features[1] +/// } +/// }); +/// ``` +/// +/// Trailing commas are allowed inside both arrays and objects. +/// +/// ``` +/// # use serde_json::json; +/// # +/// let value = json!([ +/// "notice", +/// "the", +/// "trailing", +/// "comma -->", +/// ]); +/// ``` +#[macro_export] +macro_rules! json { + // Hide distracting implementation details from the generated rustdoc. + ($($json:tt)+) => { + $crate::json_internal!($($json)+) + }; +} + +// Rocket relies on this because they export their own `json!` with a different +// doc comment than ours, and various Rust bugs prevent them from calling our +// `json!` from their `json!` so they call `json_internal!` directly. Check with +// @SergioBenitez before making breaking changes to this macro. +// +// Changes are fine as long as `json_internal!` does not call any new helper +// macros and can still be invoked as `json_internal!($($json)+)`. +#[macro_export] +#[doc(hidden)] +macro_rules! json_internal { + ////////////////////////////////////////////////////////////////////////// + // TT muncher for parsing the inside of an array [...]. Produces a vec![...] + // of the elements. + // + // Must be invoked as: json_internal!(@array [] $($tt)*) + ////////////////////////////////////////////////////////////////////////// + + // Done with trailing comma. + (@array [$($elems:expr,)*]) => { + $crate::__private::vec![$($elems,)*] + }; + + // Done without trailing comma. + (@array [$($elems:expr),*]) => { + $crate::__private::vec![$($elems),*] + }; + + // Next element is `null`. + (@array [$($elems:expr,)*] null $($rest:tt)*) => { + $crate::json_internal!(@array [$($elems,)* $crate::json_internal!(null)] $($rest)*) + }; + + // Next element is `true`. + (@array [$($elems:expr,)*] true $($rest:tt)*) => { + $crate::json_internal!(@array [$($elems,)* $crate::json_internal!(true)] $($rest)*) + }; + + // Next element is `false`. + (@array [$($elems:expr,)*] false $($rest:tt)*) => { + $crate::json_internal!(@array [$($elems,)* $crate::json_internal!(false)] $($rest)*) + }; + + // Next element is an array. + (@array [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => { + $crate::json_internal!(@array [$($elems,)* $crate::json_internal!([$($array)*])] $($rest)*) + }; + + // Next element is a map. + (@array [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => { + $crate::json_internal!(@array [$($elems,)* $crate::json_internal!({$($map)*})] $($rest)*) + }; + + // Next element is an expression followed by comma. + (@array [$($elems:expr,)*] $next:expr, $($rest:tt)*) => { + $crate::json_internal!(@array [$($elems,)* $crate::json_internal!($next),] $($rest)*) + }; + + // Last element is an expression with no trailing comma. + (@array [$($elems:expr,)*] $last:expr) => { + $crate::json_internal!(@array [$($elems,)* $crate::json_internal!($last)]) + }; + + // Comma after the most recent element. + (@array [$($elems:expr),*] , $($rest:tt)*) => { + $crate::json_internal!(@array [$($elems,)*] $($rest)*) + }; + + // Unexpected token after most recent element. + (@array [$($elems:expr),*] $unexpected:tt $($rest:tt)*) => { + $crate::json_unexpected!($unexpected) + }; + + ////////////////////////////////////////////////////////////////////////// + // TT muncher for parsing the inside of an object {...}. Each entry is + // inserted into the given map variable. + // + // Must be invoked as: json_internal!(@object $map () ($($tt)*) ($($tt)*)) + // + // We require two copies of the input tokens so that we can match on one + // copy and trigger errors on the other copy. + ////////////////////////////////////////////////////////////////////////// + + // Done. + (@object $object:ident () () ()) => {}; + + // Insert the current entry followed by trailing comma. + (@object $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => { + let _ = $object.insert(($($key)+).into(), $value); + $crate::json_internal!(@object $object () ($($rest)*) ($($rest)*)); + }; + + // Current entry followed by unexpected token. + (@object $object:ident [$($key:tt)+] ($value:expr) $unexpected:tt $($rest:tt)*) => { + $crate::json_unexpected!($unexpected); + }; + + // Insert the last entry without trailing comma. + (@object $object:ident [$($key:tt)+] ($value:expr)) => { + let _ = $object.insert(($($key)+).into(), $value); + }; + + // Next value is `null`. + (@object $object:ident ($($key:tt)+) (: null $($rest:tt)*) $copy:tt) => { + $crate::json_internal!(@object $object [$($key)+] ($crate::json_internal!(null)) $($rest)*); + }; + + // Next value is `true`. + (@object $object:ident ($($key:tt)+) (: true $($rest:tt)*) $copy:tt) => { + $crate::json_internal!(@object $object [$($key)+] ($crate::json_internal!(true)) $($rest)*); + }; + + // Next value is `false`. + (@object $object:ident ($($key:tt)+) (: false $($rest:tt)*) $copy:tt) => { + $crate::json_internal!(@object $object [$($key)+] ($crate::json_internal!(false)) $($rest)*); + }; + + // Next value is an array. + (@object $object:ident ($($key:tt)+) (: [$($array:tt)*] $($rest:tt)*) $copy:tt) => { + $crate::json_internal!(@object $object [$($key)+] ($crate::json_internal!([$($array)*])) $($rest)*); + }; + + // Next value is a map. + (@object $object:ident ($($key:tt)+) (: {$($map:tt)*} $($rest:tt)*) $copy:tt) => { + $crate::json_internal!(@object $object [$($key)+] ($crate::json_internal!({$($map)*})) $($rest)*); + }; + + // Next value is an expression followed by comma. + (@object $object:ident ($($key:tt)+) (: $value:expr , $($rest:tt)*) $copy:tt) => { + $crate::json_internal!(@object $object [$($key)+] ($crate::json_internal!($value)) , $($rest)*); + }; + + // Last value is an expression with no trailing comma. + (@object $object:ident ($($key:tt)+) (: $value:expr) $copy:tt) => { + $crate::json_internal!(@object $object [$($key)+] ($crate::json_internal!($value))); + }; + + // Missing value for last entry. Trigger a reasonable error message. + (@object $object:ident ($($key:tt)+) (:) $copy:tt) => { + // "unexpected end of macro invocation" + $crate::json_internal!(); + }; + + // Missing colon and value for last entry. Trigger a reasonable error + // message. + (@object $object:ident ($($key:tt)+) () $copy:tt) => { + // "unexpected end of macro invocation" + $crate::json_internal!(); + }; + + // Misplaced colon. Trigger a reasonable error message. + (@object $object:ident () (: $($rest:tt)*) ($colon:tt $($copy:tt)*)) => { + // Takes no arguments so "no rules expected the token `:`". + $crate::json_unexpected!($colon); + }; + + // Found a comma inside a key. Trigger a reasonable error message. + (@object $object:ident ($($key:tt)*) (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => { + // Takes no arguments so "no rules expected the token `,`". + $crate::json_unexpected!($comma); + }; + + // Key is fully parenthesized. This avoids clippy double_parens false + // positives because the parenthesization may be necessary here. + (@object $object:ident () (($key:expr) : $($rest:tt)*) $copy:tt) => { + $crate::json_internal!(@object $object ($key) (: $($rest)*) (: $($rest)*)); + }; + + // Refuse to absorb colon token into key expression. + (@object $object:ident ($($key:tt)*) (: $($unexpected:tt)+) $copy:tt) => { + $crate::json_expect_expr_comma!($($unexpected)+); + }; + + // Munch a token into the current key. + (@object $object:ident ($($key:tt)*) ($tt:tt $($rest:tt)*) $copy:tt) => { + $crate::json_internal!(@object $object ($($key)* $tt) ($($rest)*) ($($rest)*)); + }; + + ////////////////////////////////////////////////////////////////////////// + // The main implementation. + // + // Must be invoked as: json_internal!($($json)+) + ////////////////////////////////////////////////////////////////////////// + + (null) => { + $crate::Value::Null + }; + + (true) => { + $crate::Value::Bool(true) + }; + + (false) => { + $crate::Value::Bool(false) + }; + + ([]) => { + $crate::Value::Array($crate::__private::vec![]) + }; + + ([ $($tt:tt)+ ]) => { + $crate::Value::Array($crate::json_internal!(@array [] $($tt)+)) + }; + + ({}) => { + $crate::Value::Object($crate::Map::new()) + }; + + ({ $($tt:tt)+ }) => { + $crate::Value::Object({ + let mut object = $crate::Map::new(); + $crate::json_internal!(@object object () ($($tt)+) ($($tt)+)); + object + }) + }; + + // Any Serialize type: numbers, strings, struct literals, variables etc. + // Must be below every other rule. + ($other:expr) => { + $crate::to_value(&$other).unwrap() + }; +} + +// Used by old versions of Rocket. +// Unused since https://github.com/rwf2/Rocket/commit/c74bcfd40a47b35330db6cafb88e4f3da83e0d17 +#[macro_export] +#[doc(hidden)] +macro_rules! json_internal_vec { + ($($content:tt)*) => { + vec![$($content)*] + }; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! json_unexpected { + () => {}; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! json_expect_expr_comma { + ($e:expr , $($tt:tt)*) => {}; +} diff --git a/third_party/crates/serde_json-1.0.151/src/map.rs b/third_party/crates/serde_json-1.0.151/src/map.rs new file mode 100644 index 0000000..f91e70b --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/map.rs @@ -0,0 +1,1181 @@ +//! A map of String to serde_json::Value. +//! +//! By default the map is backed by a [`BTreeMap`]. Enable the `preserve_order` +//! feature of serde_json to use [`IndexMap`] instead. +//! +//! [`BTreeMap`]: std::collections::BTreeMap +//! [`IndexMap`]: indexmap::IndexMap + +use crate::error::Error; +use crate::value::Value; +use alloc::string::String; +#[cfg(feature = "preserve_order")] +use alloc::vec::Vec; +use core::borrow::Borrow; +use core::fmt::{self, Debug}; +use core::hash::{Hash, Hasher}; +use core::iter::FusedIterator; +#[cfg(feature = "preserve_order")] +use core::mem; +use core::ops; +use serde::de; + +#[cfg(not(feature = "preserve_order"))] +use alloc::collections::{btree_map, BTreeMap}; +#[cfg(feature = "preserve_order")] +use indexmap::IndexMap; + +/// Represents a JSON key/value type. +pub struct Map { + map: MapImpl, +} + +#[cfg(not(feature = "preserve_order"))] +type MapImpl = BTreeMap; +#[cfg(feature = "preserve_order")] +type MapImpl = IndexMap; + +impl Map { + /// Makes a new empty Map. + #[inline] + pub fn new() -> Self { + Map { + map: MapImpl::new(), + } + } + + /// Makes a new empty Map with the given initial capacity. + #[inline] + pub fn with_capacity(capacity: usize) -> Self { + Map { + #[cfg(not(feature = "preserve_order"))] + map: { + // does not support with_capacity + let _ = capacity; + BTreeMap::new() + }, + #[cfg(feature = "preserve_order")] + map: IndexMap::with_capacity(capacity), + } + } + + /// Clears the map, removing all values. + #[inline] + pub fn clear(&mut self) { + self.map.clear(); + } + + /// Returns a reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but the ordering + /// on the borrowed form *must* match the ordering on the key type. + #[inline] + pub fn get(&self, key: &Q) -> Option<&Value> + where + String: Borrow, + Q: ?Sized + Ord + Eq + Hash, + { + self.map.get(key) + } + + /// Returns true if the map contains a value for the specified key. + /// + /// The key may be any borrowed form of the map's key type, but the ordering + /// on the borrowed form *must* match the ordering on the key type. + #[inline] + pub fn contains_key(&self, key: &Q) -> bool + where + String: Borrow, + Q: ?Sized + Ord + Eq + Hash, + { + self.map.contains_key(key) + } + + /// Returns a mutable reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but the ordering + /// on the borrowed form *must* match the ordering on the key type. + #[inline] + pub fn get_mut(&mut self, key: &Q) -> Option<&mut Value> + where + String: Borrow, + Q: ?Sized + Ord + Eq + Hash, + { + self.map.get_mut(key) + } + + /// Returns the key-value pair matching the given key. + /// + /// The key may be any borrowed form of the map's key type, but the ordering + /// on the borrowed form *must* match the ordering on the key type. + #[inline] + pub fn get_key_value(&self, key: &Q) -> Option<(&String, &Value)> + where + String: Borrow, + Q: ?Sized + Ord + Eq + Hash, + { + self.map.get_key_value(key) + } + + /// Inserts a key-value pair into the map. + /// + /// If the map did not have this key present, `None` is returned. + /// + /// If the map did have this key present, the value is updated, and the old + /// value is returned. + #[inline] + pub fn insert(&mut self, k: String, v: Value) -> Option { + self.map.insert(k, v) + } + + /// Insert a key-value pair in the map at the given index. + /// + /// If the map did not have this key present, `None` is returned. + /// + /// If the map did have this key present, the key is moved to the new + /// position, the value is updated, and the old value is returned. + #[cfg(feature = "preserve_order")] + #[cfg_attr(docsrs, doc(cfg(feature = "preserve_order")))] + #[inline] + pub fn shift_insert(&mut self, index: usize, k: String, v: Value) -> Option { + self.map.shift_insert(index, k, v) + } + + /// Removes a key from the map, returning the value at the key if the key + /// was previously in the map. + /// + /// The key may be any borrowed form of the map's key type, but the ordering + /// on the borrowed form *must* match the ordering on the key type. + /// + /// If serde_json's "preserve_order" is enabled, `.remove(key)` is + /// equivalent to [`.swap_remove(key)`][Self::swap_remove], replacing this + /// entry's position with the last element. If you need to preserve the + /// relative order of the keys in the map, use + /// [`.shift_remove(key)`][Self::shift_remove] instead. + #[inline] + pub fn remove(&mut self, key: &Q) -> Option + where + String: Borrow, + Q: ?Sized + Ord + Eq + Hash, + { + #[cfg(feature = "preserve_order")] + return self.swap_remove(key); + #[cfg(not(feature = "preserve_order"))] + return self.map.remove(key); + } + + /// Removes a key from the map, returning the stored key and value if the + /// key was previously in the map. + /// + /// The key may be any borrowed form of the map's key type, but the ordering + /// on the borrowed form *must* match the ordering on the key type. + /// + /// If serde_json's "preserve_order" is enabled, `.remove_entry(key)` is + /// equivalent to [`.swap_remove_entry(key)`][Self::swap_remove_entry], + /// replacing this entry's position with the last element. If you need to + /// preserve the relative order of the keys in the map, use + /// [`.shift_remove_entry(key)`][Self::shift_remove_entry] instead. + #[inline] + pub fn remove_entry(&mut self, key: &Q) -> Option<(String, Value)> + where + String: Borrow, + Q: ?Sized + Ord + Eq + Hash, + { + #[cfg(feature = "preserve_order")] + return self.swap_remove_entry(key); + #[cfg(not(feature = "preserve_order"))] + return self.map.remove_entry(key); + } + + /// Removes and returns the value corresponding to the key from the map. + /// + /// Like [`Vec::swap_remove`], the entry is removed by swapping it with the + /// last element of the map and popping it off. This perturbs the position + /// of what used to be the last element! + /// + /// [`Vec::swap_remove`]: std::vec::Vec::swap_remove + #[cfg(feature = "preserve_order")] + #[cfg_attr(docsrs, doc(cfg(feature = "preserve_order")))] + #[inline] + pub fn swap_remove(&mut self, key: &Q) -> Option + where + String: Borrow, + Q: ?Sized + Ord + Eq + Hash, + { + self.map.swap_remove(key) + } + + /// Remove and return the key-value pair. + /// + /// Like [`Vec::swap_remove`], the entry is removed by swapping it with the + /// last element of the map and popping it off. This perturbs the position + /// of what used to be the last element! + /// + /// [`Vec::swap_remove`]: std::vec::Vec::swap_remove + #[cfg(feature = "preserve_order")] + #[cfg_attr(docsrs, doc(cfg(feature = "preserve_order")))] + #[inline] + pub fn swap_remove_entry(&mut self, key: &Q) -> Option<(String, Value)> + where + String: Borrow, + Q: ?Sized + Ord + Eq + Hash, + { + self.map.swap_remove_entry(key) + } + + /// Removes and returns the value corresponding to the key from the map. + /// + /// Like [`Vec::remove`], the entry is removed by shifting all of the + /// elements that follow it, preserving their relative order. This perturbs + /// the index of all of those elements! + /// + /// [`Vec::remove`]: std::vec::Vec::remove + #[cfg(feature = "preserve_order")] + #[cfg_attr(docsrs, doc(cfg(feature = "preserve_order")))] + #[inline] + pub fn shift_remove(&mut self, key: &Q) -> Option + where + String: Borrow, + Q: ?Sized + Ord + Eq + Hash, + { + self.map.shift_remove(key) + } + + /// Remove and return the key-value pair. + /// + /// Like [`Vec::remove`], the entry is removed by shifting all of the + /// elements that follow it, preserving their relative order. This perturbs + /// the index of all of those elements! + /// + /// [`Vec::remove`]: std::vec::Vec::remove + #[cfg(feature = "preserve_order")] + #[cfg_attr(docsrs, doc(cfg(feature = "preserve_order")))] + #[inline] + pub fn shift_remove_entry(&mut self, key: &Q) -> Option<(String, Value)> + where + String: Borrow, + Q: ?Sized + Ord + Eq + Hash, + { + self.map.shift_remove_entry(key) + } + + /// Moves all elements from other into self, leaving other empty. + #[inline] + pub fn append(&mut self, other: &mut Self) { + #[cfg(feature = "preserve_order")] + self.map + .extend(mem::replace(&mut other.map, MapImpl::default())); + #[cfg(not(feature = "preserve_order"))] + self.map.append(&mut other.map); + } + + /// Gets the given key's corresponding entry in the map for in-place + /// manipulation. + pub fn entry(&mut self, key: S) -> Entry + where + S: Into, + { + #[cfg(not(feature = "preserve_order"))] + use alloc::collections::btree_map::Entry as EntryImpl; + #[cfg(feature = "preserve_order")] + use indexmap::map::Entry as EntryImpl; + + match self.map.entry(key.into()) { + EntryImpl::Vacant(vacant) => Entry::Vacant(VacantEntry { vacant }), + EntryImpl::Occupied(occupied) => Entry::Occupied(OccupiedEntry { occupied }), + } + } + + /// Returns the number of elements in the map. + #[inline] + pub fn len(&self) -> usize { + self.map.len() + } + + /// Returns true if the map contains no elements. + #[inline] + pub fn is_empty(&self) -> bool { + self.map.is_empty() + } + + /// Gets an iterator over the entries of the map. + #[inline] + pub fn iter(&self) -> Iter { + Iter { + iter: self.map.iter(), + } + } + + /// Gets a mutable iterator over the entries of the map. + #[inline] + pub fn iter_mut(&mut self) -> IterMut { + IterMut { + iter: self.map.iter_mut(), + } + } + + /// Gets an iterator over the keys of the map. + #[inline] + pub fn keys(&self) -> Keys { + Keys { + iter: self.map.keys(), + } + } + + /// Gets an iterator over the values of the map. + #[inline] + pub fn values(&self) -> Values { + Values { + iter: self.map.values(), + } + } + + /// Gets an iterator over mutable values of the map. + #[inline] + pub fn values_mut(&mut self) -> ValuesMut { + ValuesMut { + iter: self.map.values_mut(), + } + } + + /// Gets an iterator over the values of the map. + #[inline] + pub fn into_values(self) -> IntoValues { + IntoValues { + iter: self.map.into_values(), + } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` + /// returns `false`. + #[inline] + pub fn retain(&mut self, f: F) + where + F: FnMut(&String, &mut Value) -> bool, + { + self.map.retain(f); + } + + /// Sorts this map's entries in-place using `str`'s usual ordering. + /// + /// If serde_json's "preserve_order" feature is not enabled, this method + /// does no work because all JSON maps are always kept in a sorted state. + /// + /// If serde_json's "preserve_order" feature is enabled, this method + /// destroys the original source order or insertion order of this map in + /// favor of an alphanumerical order that matches how a BTreeMap with the + /// same contents would be ordered. This takes **O(n log n + c)** time where + /// _n_ is the length of the map and _c_ is the capacity. + /// + /// Other maps nested within the values of this map are not sorted. If you + /// need the entire data structure to be sorted at all levels, you must also + /// call + /// map.[values_mut]\().for_each([Value::sort_all_objects]). + /// + /// [values_mut]: Map::values_mut + #[inline] + pub fn sort_keys(&mut self) { + #[cfg(feature = "preserve_order")] + self.map.sort_unstable_keys(); + } +} + +#[allow(clippy::derivable_impls)] // clippy bug: https://github.com/rust-lang/rust-clippy/issues/7655 +impl Default for Map { + #[inline] + fn default() -> Self { + Map { + map: MapImpl::new(), + } + } +} + +impl Clone for Map { + #[inline] + fn clone(&self) -> Self { + Map { + map: self.map.clone(), + } + } + + #[inline] + fn clone_from(&mut self, source: &Self) { + self.map.clone_from(&source.map); + } +} + +impl PartialEq for Map { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.map.eq(&other.map) + } +} + +impl Eq for Map {} + +impl Hash for Map { + fn hash(&self, state: &mut H) { + #[cfg(not(feature = "preserve_order"))] + { + self.map.hash(state); + } + + #[cfg(feature = "preserve_order")] + { + let mut kv = Vec::from_iter(&self.map); + kv.sort_unstable_by(|a, b| a.0.cmp(b.0)); + kv.hash(state); + } + } +} + +/// Access an element of this map. Panics if the given key is not present in the +/// map. +/// +/// ``` +/// # use serde_json::Value; +/// # +/// # let val = &Value::String("".to_owned()); +/// # let _ = +/// match val { +/// Value::String(s) => Some(s.as_str()), +/// Value::Array(arr) => arr[0].as_str(), +/// Value::Object(map) => map["type"].as_str(), +/// _ => None, +/// } +/// # ; +/// ``` +impl ops::Index<&Q> for Map +where + String: Borrow, + Q: ?Sized + Ord + Eq + Hash, +{ + type Output = Value; + + fn index(&self, index: &Q) -> &Value { + self.map.index(index) + } +} + +/// Mutably access an element of this map. Panics if the given key is not +/// present in the map. +/// +/// ``` +/// # use serde_json::json; +/// # +/// # let mut map = serde_json::Map::new(); +/// # map.insert("key".to_owned(), serde_json::Value::Null); +/// # +/// map["key"] = json!("value"); +/// ``` +impl ops::IndexMut<&Q> for Map +where + String: Borrow, + Q: ?Sized + Ord + Eq + Hash, +{ + fn index_mut(&mut self, index: &Q) -> &mut Value { + self.map.get_mut(index).expect("no entry found for key") + } +} + +impl Debug for Map { + #[inline] + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + self.map.fmt(formatter) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl serde::ser::Serialize for Map { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: serde::ser::Serializer, + { + use serde::ser::SerializeMap; + let mut map = tri!(serializer.serialize_map(Some(self.len()))); + for (k, v) in self { + tri!(map.serialize_entry(k, v)); + } + map.end() + } +} + +impl<'de> de::Deserialize<'de> for Map { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + struct Visitor; + + impl<'de> de::Visitor<'de> for Visitor { + type Value = Map; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a map") + } + + #[inline] + fn visit_unit(self) -> Result + where + E: de::Error, + { + Ok(Map::new()) + } + + #[cfg(any(feature = "std", feature = "alloc"))] + #[inline] + fn visit_map(self, mut visitor: V) -> Result + where + V: de::MapAccess<'de>, + { + let mut values = Map::new(); + + while let Some((key, value)) = tri!(visitor.next_entry()) { + values.insert(key, value); + } + + Ok(values) + } + } + + deserializer.deserialize_map(Visitor) + } +} + +impl FromIterator<(String, Value)> for Map { + fn from_iter(iter: T) -> Self + where + T: IntoIterator, + { + Map { + map: FromIterator::from_iter(iter), + } + } +} + +impl Extend<(String, Value)> for Map { + fn extend(&mut self, iter: T) + where + T: IntoIterator, + { + self.map.extend(iter); + } +} + +macro_rules! delegate_iterator { + (($name:ident $($generics:tt)*) => $item:ty) => { + impl $($generics)* Iterator for $name $($generics)* { + type Item = $item; + #[inline] + fn next(&mut self) -> Option { + self.iter.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + } + + impl $($generics)* DoubleEndedIterator for $name $($generics)* { + #[inline] + fn next_back(&mut self) -> Option { + self.iter.next_back() + } + } + + impl $($generics)* ExactSizeIterator for $name $($generics)* { + #[inline] + fn len(&self) -> usize { + self.iter.len() + } + } + + impl $($generics)* FusedIterator for $name $($generics)* {} + } +} + +impl<'de> de::IntoDeserializer<'de, Error> for Map { + type Deserializer = Self; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} + +impl<'de> de::IntoDeserializer<'de, Error> for &'de Map { + type Deserializer = Self; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} + +////////////////////////////////////////////////////////////////////////////// + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// This enum is constructed from the [`entry`] method on [`Map`]. +/// +/// [`entry`]: Map::entry +pub enum Entry<'a> { + /// A vacant Entry. + Vacant(VacantEntry<'a>), + /// An occupied Entry. + Occupied(OccupiedEntry<'a>), +} + +/// A vacant Entry. It is part of the [`Entry`] enum. +pub struct VacantEntry<'a> { + vacant: VacantEntryImpl<'a>, +} + +/// An occupied Entry. It is part of the [`Entry`] enum. +pub struct OccupiedEntry<'a> { + occupied: OccupiedEntryImpl<'a>, +} + +#[cfg(not(feature = "preserve_order"))] +type VacantEntryImpl<'a> = btree_map::VacantEntry<'a, String, Value>; +#[cfg(feature = "preserve_order")] +type VacantEntryImpl<'a> = indexmap::map::VacantEntry<'a, String, Value>; + +#[cfg(not(feature = "preserve_order"))] +type OccupiedEntryImpl<'a> = btree_map::OccupiedEntry<'a, String, Value>; +#[cfg(feature = "preserve_order")] +type OccupiedEntryImpl<'a> = indexmap::map::OccupiedEntry<'a, String, Value>; + +impl<'a> Entry<'a> { + /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ``` + /// let mut map = serde_json::Map::new(); + /// assert_eq!(map.entry("serde").key(), &"serde"); + /// ``` + pub fn key(&self) -> &String { + match self { + Entry::Vacant(e) => e.key(), + Entry::Occupied(e) => e.key(), + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and + /// returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// # use serde_json::json; + /// # + /// let mut map = serde_json::Map::new(); + /// map.entry("serde").or_insert(json!(12)); + /// + /// assert_eq!(map["serde"], 12); + /// ``` + pub fn or_insert(self, default: Value) -> &'a mut Value { + match self { + Entry::Vacant(entry) => entry.insert(default), + Entry::Occupied(entry) => entry.into_mut(), + } + } + + /// Ensures a value is in the entry by inserting the result of the default + /// function if empty, and returns a mutable reference to the value in the + /// entry. + /// + /// # Examples + /// + /// ``` + /// # use serde_json::json; + /// # + /// let mut map = serde_json::Map::new(); + /// map.entry("serde").or_insert_with(|| json!("hoho")); + /// + /// assert_eq!(map["serde"], "hoho".to_owned()); + /// ``` + pub fn or_insert_with(self, default: F) -> &'a mut Value + where + F: FnOnce() -> Value, + { + match self { + Entry::Vacant(entry) => entry.insert(default()), + Entry::Occupied(entry) => entry.into_mut(), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// # use serde_json::json; + /// # + /// let mut map = serde_json::Map::new(); + /// map.entry("serde") + /// .and_modify(|e| *e = json!("rust")) + /// .or_insert(json!("cpp")); + /// + /// assert_eq!(map["serde"], "cpp"); + /// + /// map.entry("serde") + /// .and_modify(|e| *e = json!("rust")) + /// .or_insert(json!("cpp")); + /// + /// assert_eq!(map["serde"], "rust"); + /// ``` + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut Value), + { + match self { + Entry::Occupied(mut entry) => { + f(entry.get_mut()); + Entry::Occupied(entry) + } + Entry::Vacant(entry) => Entry::Vacant(entry), + } + } +} + +impl<'a> VacantEntry<'a> { + /// Gets a reference to the key that would be used when inserting a value + /// through the VacantEntry. + /// + /// # Examples + /// + /// ``` + /// use serde_json::map::Entry; + /// + /// let mut map = serde_json::Map::new(); + /// + /// match map.entry("serde") { + /// Entry::Vacant(vacant) => { + /// assert_eq!(vacant.key(), &"serde"); + /// } + /// Entry::Occupied(_) => unimplemented!(), + /// } + /// ``` + #[inline] + pub fn key(&self) -> &String { + self.vacant.key() + } + + /// Sets the value of the entry with the VacantEntry's key, and returns a + /// mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// # use serde_json::json; + /// # + /// use serde_json::map::Entry; + /// + /// let mut map = serde_json::Map::new(); + /// + /// match map.entry("serde") { + /// Entry::Vacant(vacant) => { + /// vacant.insert(json!("hoho")); + /// } + /// Entry::Occupied(_) => unimplemented!(), + /// } + /// ``` + #[inline] + pub fn insert(self, value: Value) -> &'a mut Value { + self.vacant.insert(value) + } +} + +impl<'a> OccupiedEntry<'a> { + /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// # use serde_json::json; + /// # + /// use serde_json::map::Entry; + /// + /// let mut map = serde_json::Map::new(); + /// map.insert("serde".to_owned(), json!(12)); + /// + /// match map.entry("serde") { + /// Entry::Occupied(occupied) => { + /// assert_eq!(occupied.key(), &"serde"); + /// } + /// Entry::Vacant(_) => unimplemented!(), + /// } + /// ``` + #[inline] + pub fn key(&self) -> &String { + self.occupied.key() + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// # use serde_json::json; + /// # + /// use serde_json::map::Entry; + /// + /// let mut map = serde_json::Map::new(); + /// map.insert("serde".to_owned(), json!(12)); + /// + /// match map.entry("serde") { + /// Entry::Occupied(occupied) => { + /// assert_eq!(occupied.get(), 12); + /// } + /// Entry::Vacant(_) => unimplemented!(), + /// } + /// ``` + #[inline] + pub fn get(&self) -> &Value { + self.occupied.get() + } + + /// Gets a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// # use serde_json::json; + /// # + /// use serde_json::map::Entry; + /// + /// let mut map = serde_json::Map::new(); + /// map.insert("serde".to_owned(), json!([1, 2, 3])); + /// + /// match map.entry("serde") { + /// Entry::Occupied(mut occupied) => { + /// occupied.get_mut().as_array_mut().unwrap().push(json!(4)); + /// } + /// Entry::Vacant(_) => unimplemented!(), + /// } + /// + /// assert_eq!(map["serde"].as_array().unwrap().len(), 4); + /// ``` + #[inline] + pub fn get_mut(&mut self) -> &mut Value { + self.occupied.get_mut() + } + + /// Converts the entry into a mutable reference to its value. + /// + /// # Examples + /// + /// ``` + /// # use serde_json::json; + /// # + /// use serde_json::map::Entry; + /// + /// let mut map = serde_json::Map::new(); + /// map.insert("serde".to_owned(), json!([1, 2, 3])); + /// + /// match map.entry("serde") { + /// Entry::Occupied(mut occupied) => { + /// occupied.into_mut().as_array_mut().unwrap().push(json!(4)); + /// } + /// Entry::Vacant(_) => unimplemented!(), + /// } + /// + /// assert_eq!(map["serde"].as_array().unwrap().len(), 4); + /// ``` + #[inline] + pub fn into_mut(self) -> &'a mut Value { + self.occupied.into_mut() + } + + /// Sets the value of the entry with the `OccupiedEntry`'s key, and returns + /// the entry's old value. + /// + /// # Examples + /// + /// ``` + /// # use serde_json::json; + /// # + /// use serde_json::map::Entry; + /// + /// let mut map = serde_json::Map::new(); + /// map.insert("serde".to_owned(), json!(12)); + /// + /// match map.entry("serde") { + /// Entry::Occupied(mut occupied) => { + /// assert_eq!(occupied.insert(json!(13)), 12); + /// assert_eq!(occupied.get(), 13); + /// } + /// Entry::Vacant(_) => unimplemented!(), + /// } + /// ``` + #[inline] + pub fn insert(&mut self, value: Value) -> Value { + self.occupied.insert(value) + } + + /// Takes the value of the entry out of the map, and returns it. + /// + /// If serde_json's "preserve_order" is enabled, `.remove()` is + /// equivalent to [`.swap_remove()`][Self::swap_remove], replacing this + /// entry's position with the last element. If you need to preserve the + /// relative order of the keys in the map, use + /// [`.shift_remove()`][Self::shift_remove] instead. + /// + /// # Examples + /// + /// ``` + /// # use serde_json::json; + /// # + /// use serde_json::map::Entry; + /// + /// let mut map = serde_json::Map::new(); + /// map.insert("serde".to_owned(), json!(12)); + /// + /// match map.entry("serde") { + /// Entry::Occupied(occupied) => { + /// assert_eq!(occupied.remove(), 12); + /// } + /// Entry::Vacant(_) => unimplemented!(), + /// } + /// ``` + #[inline] + pub fn remove(self) -> Value { + #[cfg(feature = "preserve_order")] + return self.swap_remove(); + #[cfg(not(feature = "preserve_order"))] + return self.occupied.remove(); + } + + /// Takes the value of the entry out of the map, and returns it. + /// + /// Like [`Vec::swap_remove`], the entry is removed by swapping it with the + /// last element of the map and popping it off. This perturbs the position + /// of what used to be the last element! + /// + /// [`Vec::swap_remove`]: std::vec::Vec::swap_remove + #[cfg(feature = "preserve_order")] + #[cfg_attr(docsrs, doc(cfg(feature = "preserve_order")))] + #[inline] + pub fn swap_remove(self) -> Value { + self.occupied.swap_remove() + } + + /// Takes the value of the entry out of the map, and returns it. + /// + /// Like [`Vec::remove`], the entry is removed by shifting all of the + /// elements that follow it, preserving their relative order. This perturbs + /// the index of all of those elements! + /// + /// [`Vec::remove`]: std::vec::Vec::remove + #[cfg(feature = "preserve_order")] + #[cfg_attr(docsrs, doc(cfg(feature = "preserve_order")))] + #[inline] + pub fn shift_remove(self) -> Value { + self.occupied.shift_remove() + } + + /// Removes the entry from the map, returning the stored key and value. + /// + /// If serde_json's "preserve_order" is enabled, `.remove_entry()` is + /// equivalent to [`.swap_remove_entry()`][Self::swap_remove_entry], + /// replacing this entry's position with the last element. If you need to + /// preserve the relative order of the keys in the map, use + /// [`.shift_remove_entry()`][Self::shift_remove_entry] instead. + /// + /// # Examples + /// + /// ``` + /// # use serde_json::json; + /// # + /// use serde_json::map::Entry; + /// + /// let mut map = serde_json::Map::new(); + /// map.insert("serde".to_owned(), json!(12)); + /// + /// match map.entry("serde") { + /// Entry::Occupied(occupied) => { + /// let (key, value) = occupied.remove_entry(); + /// assert_eq!(key, "serde"); + /// assert_eq!(value, 12); + /// } + /// Entry::Vacant(_) => unimplemented!(), + /// } + /// ``` + #[inline] + pub fn remove_entry(self) -> (String, Value) { + #[cfg(feature = "preserve_order")] + return self.swap_remove_entry(); + #[cfg(not(feature = "preserve_order"))] + return self.occupied.remove_entry(); + } + + /// Removes the entry from the map, returning the stored key and value. + /// + /// Like [`Vec::swap_remove`], the entry is removed by swapping it with the + /// last element of the map and popping it off. This perturbs the position + /// of what used to be the last element! + /// + /// [`Vec::swap_remove`]: std::vec::Vec::swap_remove + #[cfg(feature = "preserve_order")] + #[cfg_attr(docsrs, doc(cfg(feature = "preserve_order")))] + #[inline] + pub fn swap_remove_entry(self) -> (String, Value) { + self.occupied.swap_remove_entry() + } + + /// Removes the entry from the map, returning the stored key and value. + /// + /// Like [`Vec::remove`], the entry is removed by shifting all of the + /// elements that follow it, preserving their relative order. This perturbs + /// the index of all of those elements! + /// + /// [`Vec::remove`]: std::vec::Vec::remove + #[cfg(feature = "preserve_order")] + #[cfg_attr(docsrs, doc(cfg(feature = "preserve_order")))] + #[inline] + pub fn shift_remove_entry(self) -> (String, Value) { + self.occupied.shift_remove_entry() + } +} + +////////////////////////////////////////////////////////////////////////////// + +impl<'a> IntoIterator for &'a Map { + type Item = (&'a String, &'a Value); + type IntoIter = Iter<'a>; + #[inline] + fn into_iter(self) -> Self::IntoIter { + Iter { + iter: self.map.iter(), + } + } +} + +/// An iterator over a serde_json::Map's entries. +#[derive(Clone, Debug)] +pub struct Iter<'a> { + iter: IterImpl<'a>, +} + +#[cfg(not(feature = "preserve_order"))] +type IterImpl<'a> = btree_map::Iter<'a, String, Value>; +#[cfg(feature = "preserve_order")] +type IterImpl<'a> = indexmap::map::Iter<'a, String, Value>; + +delegate_iterator!((Iter<'a>) => (&'a String, &'a Value)); + +////////////////////////////////////////////////////////////////////////////// + +impl<'a> IntoIterator for &'a mut Map { + type Item = (&'a String, &'a mut Value); + type IntoIter = IterMut<'a>; + #[inline] + fn into_iter(self) -> Self::IntoIter { + IterMut { + iter: self.map.iter_mut(), + } + } +} + +/// A mutable iterator over a serde_json::Map's entries. +#[derive(Debug)] +pub struct IterMut<'a> { + iter: IterMutImpl<'a>, +} + +#[cfg(not(feature = "preserve_order"))] +type IterMutImpl<'a> = btree_map::IterMut<'a, String, Value>; +#[cfg(feature = "preserve_order")] +type IterMutImpl<'a> = indexmap::map::IterMut<'a, String, Value>; + +delegate_iterator!((IterMut<'a>) => (&'a String, &'a mut Value)); + +////////////////////////////////////////////////////////////////////////////// + +impl IntoIterator for Map { + type Item = (String, Value); + type IntoIter = IntoIter; + #[inline] + fn into_iter(self) -> Self::IntoIter { + IntoIter { + iter: self.map.into_iter(), + } + } +} + +/// An owning iterator over a serde_json::Map's entries. +#[derive(Debug)] +pub struct IntoIter { + iter: IntoIterImpl, +} + +#[cfg(not(feature = "preserve_order"))] +type IntoIterImpl = btree_map::IntoIter; +#[cfg(feature = "preserve_order")] +type IntoIterImpl = indexmap::map::IntoIter; + +delegate_iterator!((IntoIter) => (String, Value)); + +////////////////////////////////////////////////////////////////////////////// + +/// An iterator over a serde_json::Map's keys. +#[derive(Clone, Debug)] +pub struct Keys<'a> { + iter: KeysImpl<'a>, +} + +#[cfg(not(feature = "preserve_order"))] +type KeysImpl<'a> = btree_map::Keys<'a, String, Value>; +#[cfg(feature = "preserve_order")] +type KeysImpl<'a> = indexmap::map::Keys<'a, String, Value>; + +delegate_iterator!((Keys<'a>) => &'a String); + +////////////////////////////////////////////////////////////////////////////// + +/// An iterator over a serde_json::Map's values. +#[derive(Clone, Debug)] +pub struct Values<'a> { + iter: ValuesImpl<'a>, +} + +#[cfg(not(feature = "preserve_order"))] +type ValuesImpl<'a> = btree_map::Values<'a, String, Value>; +#[cfg(feature = "preserve_order")] +type ValuesImpl<'a> = indexmap::map::Values<'a, String, Value>; + +delegate_iterator!((Values<'a>) => &'a Value); + +////////////////////////////////////////////////////////////////////////////// + +/// A mutable iterator over a serde_json::Map's values. +#[derive(Debug)] +pub struct ValuesMut<'a> { + iter: ValuesMutImpl<'a>, +} + +#[cfg(not(feature = "preserve_order"))] +type ValuesMutImpl<'a> = btree_map::ValuesMut<'a, String, Value>; +#[cfg(feature = "preserve_order")] +type ValuesMutImpl<'a> = indexmap::map::ValuesMut<'a, String, Value>; + +delegate_iterator!((ValuesMut<'a>) => &'a mut Value); + +////////////////////////////////////////////////////////////////////////////// + +/// An owning iterator over a serde_json::Map's values. +#[derive(Debug)] +pub struct IntoValues { + iter: IntoValuesImpl, +} + +#[cfg(not(feature = "preserve_order"))] +type IntoValuesImpl = btree_map::IntoValues; +#[cfg(feature = "preserve_order")] +type IntoValuesImpl = indexmap::map::IntoValues; + +delegate_iterator!((IntoValues) => Value); diff --git a/third_party/crates/serde_json-1.0.151/src/number.rs b/third_party/crates/serde_json-1.0.151/src/number.rs new file mode 100644 index 0000000..45eb3a2 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/number.rs @@ -0,0 +1,814 @@ +use crate::de::ParserNumber; +use crate::error::Error; +#[cfg(feature = "arbitrary_precision")] +use crate::error::ErrorCode; +#[cfg(feature = "arbitrary_precision")] +use alloc::borrow::ToOwned; +#[cfg(feature = "arbitrary_precision")] +use alloc::string::{String, ToString}; +use core::fmt::{self, Debug, Display}; +#[cfg(not(feature = "arbitrary_precision"))] +use core::hash::{Hash, Hasher}; +use serde::de::{self, Unexpected, Visitor}; +#[cfg(feature = "arbitrary_precision")] +use serde::de::{IntoDeserializer, MapAccess}; +use serde::{forward_to_deserialize_any, Deserialize, Deserializer, Serialize, Serializer}; + +#[cfg(feature = "arbitrary_precision")] +pub(crate) const TOKEN: &str = "$serde_json::private::Number"; + +/// Represents a JSON number, whether integer or floating point. +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct Number { + n: N, +} + +#[cfg(not(feature = "arbitrary_precision"))] +#[derive(Copy, Clone)] +enum N { + PosInt(u64), + /// Always less than zero. + NegInt(i64), + /// Always finite. + Float(f64), +} + +#[cfg(not(feature = "arbitrary_precision"))] +impl PartialEq for N { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (N::PosInt(a), N::PosInt(b)) => a == b, + (N::NegInt(a), N::NegInt(b)) => a == b, + (N::Float(a), N::Float(b)) => a == b, + _ => false, + } + } +} + +// Implementing Eq is fine since any float values are always finite. +#[cfg(not(feature = "arbitrary_precision"))] +impl Eq for N {} + +#[cfg(not(feature = "arbitrary_precision"))] +impl Hash for N { + fn hash(&self, h: &mut H) { + match *self { + N::PosInt(i) => i.hash(h), + N::NegInt(i) => i.hash(h), + N::Float(f) => { + if f == 0.0f64 { + // There are 2 zero representations, +0 and -0, which + // compare equal but have different bits. We use the +0 hash + // for both so that hash(+0) == hash(-0). + 0.0f64.to_bits().hash(h); + } else { + f.to_bits().hash(h); + } + } + } + } +} + +#[cfg(feature = "arbitrary_precision")] +type N = String; + +impl Number { + /// Returns true if the `Number` is an integer between `i64::MIN` and + /// `i64::MAX`. + /// + /// For any Number on which `is_i64` returns true, `as_i64` is guaranteed to + /// return the integer value. + pub fn is_i64(&self) -> bool { + #[cfg(not(feature = "arbitrary_precision"))] + match self.n { + N::PosInt(v) => v <= i64::MAX as u64, + N::NegInt(_) => true, + N::Float(_) => false, + } + #[cfg(feature = "arbitrary_precision")] + self.as_i64().is_some() + } + + /// Returns true if the `Number` is an integer between zero and `u64::MAX`. + /// + /// For any Number on which `is_u64` returns true, `as_u64` is guaranteed to + /// return the integer value. + pub fn is_u64(&self) -> bool { + #[cfg(not(feature = "arbitrary_precision"))] + match self.n { + N::PosInt(_) => true, + N::NegInt(_) | N::Float(_) => false, + } + #[cfg(feature = "arbitrary_precision")] + self.as_u64().is_some() + } + + /// Returns true if the `Number` can be represented by f64. + /// + /// For any Number on which `is_f64` returns true, `as_f64` is guaranteed to + /// return the floating point value. + /// + /// Currently this function returns true if and only if both `is_i64` and + /// `is_u64` return false but this is not a guarantee in the future. + pub fn is_f64(&self) -> bool { + #[cfg(not(feature = "arbitrary_precision"))] + match self.n { + N::Float(_) => true, + N::PosInt(_) | N::NegInt(_) => false, + } + #[cfg(feature = "arbitrary_precision")] + { + for c in self.n.chars() { + if c == '.' || c == 'e' || c == 'E' { + return self.n.parse::().is_ok_and(f64::is_finite); + } + } + false + } + } + + /// If the `Number` is an integer, represent it as i64 if possible. Returns + /// None otherwise. + pub fn as_i64(&self) -> Option { + #[cfg(not(feature = "arbitrary_precision"))] + match self.n { + N::PosInt(n) => { + if n <= i64::MAX as u64 { + Some(n as i64) + } else { + None + } + } + N::NegInt(n) => Some(n), + N::Float(_) => None, + } + #[cfg(feature = "arbitrary_precision")] + self.n.parse().ok() + } + + /// If the `Number` is an integer, represent it as u64 if possible. Returns + /// None otherwise. + pub fn as_u64(&self) -> Option { + #[cfg(not(feature = "arbitrary_precision"))] + match self.n { + N::PosInt(n) => Some(n), + N::NegInt(_) | N::Float(_) => None, + } + #[cfg(feature = "arbitrary_precision")] + self.n.parse().ok() + } + + /// Represents the number as f64 if possible. Returns None otherwise. + pub fn as_f64(&self) -> Option { + #[cfg(not(feature = "arbitrary_precision"))] + match self.n { + N::PosInt(n) => Some(n as f64), + N::NegInt(n) => Some(n as f64), + N::Float(n) => Some(n), + } + #[cfg(feature = "arbitrary_precision")] + self.n.parse::().ok().filter(|float| float.is_finite()) + } + + /// Converts a finite `f64` to a `Number`. Infinite or NaN values are not JSON + /// numbers. + /// + /// ``` + /// # use serde_json::Number; + /// # + /// assert!(Number::from_f64(256.0).is_some()); + /// + /// assert!(Number::from_f64(f64::NAN).is_none()); + /// ``` + pub fn from_f64(f: f64) -> Option { + if f.is_finite() { + let n = { + #[cfg(not(feature = "arbitrary_precision"))] + { + N::Float(f) + } + #[cfg(feature = "arbitrary_precision")] + { + zmij::Buffer::new().format_finite(f).to_owned() + } + }; + Some(Number { n }) + } else { + None + } + } + + /// If the `Number` is an integer, represent it as i128 if possible. Returns + /// None otherwise. + pub fn as_i128(&self) -> Option { + #[cfg(not(feature = "arbitrary_precision"))] + match self.n { + N::PosInt(n) => Some(n as i128), + N::NegInt(n) => Some(n as i128), + N::Float(_) => None, + } + #[cfg(feature = "arbitrary_precision")] + self.n.parse().ok() + } + + /// If the `Number` is an integer, represent it as u128 if possible. Returns + /// None otherwise. + pub fn as_u128(&self) -> Option { + #[cfg(not(feature = "arbitrary_precision"))] + match self.n { + N::PosInt(n) => Some(n as u128), + N::NegInt(_) | N::Float(_) => None, + } + #[cfg(feature = "arbitrary_precision")] + self.n.parse().ok() + } + + /// Converts an `i128` to a `Number`. Numbers smaller than i64::MIN or + /// larger than u64::MAX can only be represented in `Number` if serde_json's + /// "arbitrary_precision" feature is enabled. + /// + /// ``` + /// # use serde_json::Number; + /// # + /// assert!(Number::from_i128(256).is_some()); + /// ``` + pub fn from_i128(i: i128) -> Option { + let n = { + #[cfg(not(feature = "arbitrary_precision"))] + { + if let Ok(u) = u64::try_from(i) { + N::PosInt(u) + } else if let Ok(i) = i64::try_from(i) { + N::NegInt(i) + } else { + return None; + } + } + #[cfg(feature = "arbitrary_precision")] + { + i.to_string() + } + }; + Some(Number { n }) + } + + /// Converts a `u128` to a `Number`. Numbers greater than u64::MAX can only + /// be represented in `Number` if serde_json's "arbitrary_precision" feature + /// is enabled. + /// + /// ``` + /// # use serde_json::Number; + /// # + /// assert!(Number::from_u128(256).is_some()); + /// ``` + pub fn from_u128(i: u128) -> Option { + let n = { + #[cfg(not(feature = "arbitrary_precision"))] + { + if let Ok(u) = u64::try_from(i) { + N::PosInt(u) + } else { + return None; + } + } + #[cfg(feature = "arbitrary_precision")] + { + i.to_string() + } + }; + Some(Number { n }) + } + + /// Returns the JSON representation that this Number was parsed from. + /// + /// When parsing with serde_json's `arbitrary_precision` feature enabled, + /// positive exponents are normalized to include an explicit `+` sign so + /// that `1e140` becomes `1e+140`. + /// + /// For numbers constructed not via parsing, such as by `From`, returns + /// the JSON representation that serde\_json would serialize for this + /// number. + /// + /// ``` + /// # use serde_json::Number; + /// for value in [ + /// "7", + /// "12.34", + /// "34e-56789", + /// "0.0123456789000000012345678900000001234567890000123456789", + /// "343412345678910111213141516171819202122232425262728293034", + /// "-343412345678910111213141516171819202122232425262728293031", + /// ] { + /// let number: Number = serde_json::from_str(value).unwrap(); + /// assert_eq!(number.as_str(), value); + /// } + /// ``` + #[cfg(feature = "arbitrary_precision")] + #[cfg_attr(docsrs, doc(cfg(feature = "arbitrary_precision")))] + pub fn as_str(&self) -> &str { + &self.n + } + + pub(crate) fn as_f32(&self) -> Option { + #[cfg(not(feature = "arbitrary_precision"))] + match self.n { + N::PosInt(n) => Some(n as f32), + N::NegInt(n) => Some(n as f32), + N::Float(n) => Some(n as f32), + } + #[cfg(feature = "arbitrary_precision")] + self.n.parse::().ok().filter(|float| float.is_finite()) + } + + pub(crate) fn from_f32(f: f32) -> Option { + if f.is_finite() { + let n = { + #[cfg(not(feature = "arbitrary_precision"))] + { + N::Float(f as f64) + } + #[cfg(feature = "arbitrary_precision")] + { + zmij::Buffer::new().format_finite(f).to_owned() + } + }; + Some(Number { n }) + } else { + None + } + } + + #[cfg(feature = "arbitrary_precision")] + /// Not public API. Only tests use this. + #[doc(hidden)] + #[inline] + pub fn from_string_unchecked(n: String) -> Self { + Number { n } + } +} + +impl Display for Number { + #[cfg(not(feature = "arbitrary_precision"))] + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self.n { + N::PosInt(u) => formatter.write_str(itoa::Buffer::new().format(u)), + N::NegInt(i) => formatter.write_str(itoa::Buffer::new().format(i)), + N::Float(f) => formatter.write_str(zmij::Buffer::new().format_finite(f)), + } + } + + #[cfg(feature = "arbitrary_precision")] + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.n, formatter) + } +} + +impl Debug for Number { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "Number({})", self) + } +} + +impl Serialize for Number { + #[cfg(not(feature = "arbitrary_precision"))] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self.n { + N::PosInt(u) => serializer.serialize_u64(u), + N::NegInt(i) => serializer.serialize_i64(i), + N::Float(f) => serializer.serialize_f64(f), + } + } + + #[cfg(feature = "arbitrary_precision")] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use serde::ser::SerializeStruct; + + let mut s = tri!(serializer.serialize_struct(TOKEN, 1)); + tri!(s.serialize_field(TOKEN, &self.n)); + s.end() + } +} + +impl<'de> Deserialize<'de> for Number { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct NumberVisitor; + + impl<'de> Visitor<'de> for NumberVisitor { + type Value = Number; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a JSON number") + } + + fn visit_i64(self, value: i64) -> Result { + Ok(value.into()) + } + + fn visit_i128(self, value: i128) -> Result + where + E: de::Error, + { + Number::from_i128(value) + .ok_or_else(|| de::Error::custom("JSON number out of range")) + } + + fn visit_u64(self, value: u64) -> Result { + Ok(value.into()) + } + + fn visit_u128(self, value: u128) -> Result + where + E: de::Error, + { + Number::from_u128(value) + .ok_or_else(|| de::Error::custom("JSON number out of range")) + } + + fn visit_f64(self, value: f64) -> Result + where + E: de::Error, + { + Number::from_f64(value).ok_or_else(|| de::Error::custom("not a JSON number")) + } + + #[cfg(feature = "arbitrary_precision")] + fn visit_map(self, mut visitor: V) -> Result + where + V: de::MapAccess<'de>, + { + let value = tri!(visitor.next_key::()); + if value.is_none() { + return Err(de::Error::invalid_type(Unexpected::Map, &self)); + } + let v: NumberFromString = tri!(visitor.next_value()); + Ok(v.value) + } + } + + deserializer.deserialize_any(NumberVisitor) + } +} + +#[cfg(feature = "arbitrary_precision")] +struct NumberKey; + +#[cfg(feature = "arbitrary_precision")] +impl<'de> de::Deserialize<'de> for NumberKey { + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + struct FieldVisitor; + + impl<'de> de::Visitor<'de> for FieldVisitor { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a valid number field") + } + + fn visit_str(self, s: &str) -> Result<(), E> + where + E: de::Error, + { + if s == TOKEN { + Ok(()) + } else { + Err(de::Error::custom("expected field with custom name")) + } + } + } + + tri!(deserializer.deserialize_identifier(FieldVisitor)); + Ok(NumberKey) + } +} + +#[cfg(feature = "arbitrary_precision")] +pub struct NumberFromString { + pub value: Number, +} + +#[cfg(feature = "arbitrary_precision")] +impl<'de> de::Deserialize<'de> for NumberFromString { + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + struct Visitor; + + impl<'de> de::Visitor<'de> for Visitor { + type Value = NumberFromString; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("string containing a number") + } + + fn visit_str(self, s: &str) -> Result + where + E: de::Error, + { + let n = tri!(s.parse().map_err(de::Error::custom)); + Ok(NumberFromString { value: n }) + } + } + + deserializer.deserialize_str(Visitor) + } +} + +#[cfg(feature = "arbitrary_precision")] +fn invalid_number() -> Error { + Error::syntax(ErrorCode::InvalidNumber, 0, 0) +} + +macro_rules! deserialize_any { + (@expand [$($num_string:tt)*]) => { + #[cfg(not(feature = "arbitrary_precision"))] + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.n { + N::PosInt(u) => visitor.visit_u64(u), + N::NegInt(i) => visitor.visit_i64(i), + N::Float(f) => visitor.visit_f64(f), + } + } + + #[cfg(feature = "arbitrary_precision")] + fn deserialize_any(self, visitor: V) -> Result + where V: Visitor<'de> + { + if let Some(u) = self.as_u64() { + return visitor.visit_u64(u); + } else if let Some(i) = self.as_i64() { + return visitor.visit_i64(i); + } else if let Some(u) = self.as_u128() { + return visitor.visit_u128(u); + } else if let Some(i) = self.as_i128() { + return visitor.visit_i128(i); + } else if let Some(f) = self.as_f64() { + if zmij::Buffer::new().format_finite(f) == self.n || f.to_string() == self.n { + return visitor.visit_f64(f); + } + } + + visitor.visit_map(NumberDeserializer { + number: Some(self.$($num_string)*), + }) + } + }; + + (owned) => { + deserialize_any!(@expand [n]); + }; + + (ref) => { + deserialize_any!(@expand [n.clone()]); + }; +} + +macro_rules! deserialize_number { + ($deserialize:ident => $visit:ident) => { + #[cfg(not(feature = "arbitrary_precision"))] + fn $deserialize(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_any(visitor) + } + + #[cfg(feature = "arbitrary_precision")] + fn $deserialize(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + visitor.$visit(tri!(self.n.parse().map_err(|_| invalid_number()))) + } + }; +} + +impl<'de> Deserializer<'de> for Number { + type Error = Error; + + deserialize_any!(owned); + + deserialize_number!(deserialize_i8 => visit_i8); + deserialize_number!(deserialize_i16 => visit_i16); + deserialize_number!(deserialize_i32 => visit_i32); + deserialize_number!(deserialize_i64 => visit_i64); + deserialize_number!(deserialize_i128 => visit_i128); + deserialize_number!(deserialize_u8 => visit_u8); + deserialize_number!(deserialize_u16 => visit_u16); + deserialize_number!(deserialize_u32 => visit_u32); + deserialize_number!(deserialize_u64 => visit_u64); + deserialize_number!(deserialize_u128 => visit_u128); + deserialize_number!(deserialize_f32 => visit_f32); + deserialize_number!(deserialize_f64 => visit_f64); + + forward_to_deserialize_any! { + bool char str string bytes byte_buf option unit unit_struct + newtype_struct seq tuple tuple_struct map struct enum identifier + ignored_any + } +} + +impl<'de> Deserializer<'de> for &Number { + type Error = Error; + + deserialize_any!(ref); + + deserialize_number!(deserialize_i8 => visit_i8); + deserialize_number!(deserialize_i16 => visit_i16); + deserialize_number!(deserialize_i32 => visit_i32); + deserialize_number!(deserialize_i64 => visit_i64); + deserialize_number!(deserialize_i128 => visit_i128); + deserialize_number!(deserialize_u8 => visit_u8); + deserialize_number!(deserialize_u16 => visit_u16); + deserialize_number!(deserialize_u32 => visit_u32); + deserialize_number!(deserialize_u64 => visit_u64); + deserialize_number!(deserialize_u128 => visit_u128); + deserialize_number!(deserialize_f32 => visit_f32); + deserialize_number!(deserialize_f64 => visit_f64); + + forward_to_deserialize_any! { + bool char str string bytes byte_buf option unit unit_struct + newtype_struct seq tuple tuple_struct map struct enum identifier + ignored_any + } +} + +#[cfg(feature = "arbitrary_precision")] +pub(crate) struct NumberDeserializer { + pub number: Option, +} + +#[cfg(feature = "arbitrary_precision")] +impl<'de> MapAccess<'de> for NumberDeserializer { + type Error = Error; + + fn next_key_seed(&mut self, seed: K) -> Result, Error> + where + K: de::DeserializeSeed<'de>, + { + if self.number.is_none() { + return Ok(None); + } + seed.deserialize(NumberFieldDeserializer).map(Some) + } + + fn next_value_seed(&mut self, seed: V) -> Result + where + V: de::DeserializeSeed<'de>, + { + seed.deserialize(self.number.take().unwrap().into_deserializer()) + } +} + +#[cfg(feature = "arbitrary_precision")] +struct NumberFieldDeserializer; + +#[cfg(feature = "arbitrary_precision")] +impl<'de> Deserializer<'de> for NumberFieldDeserializer { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_borrowed_str(TOKEN) + } + + forward_to_deserialize_any! { + bool u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 char str string seq + bytes byte_buf map struct option unit newtype_struct ignored_any + unit_struct tuple_struct tuple enum identifier + } +} + +impl From for Number { + fn from(value: ParserNumber) -> Self { + let n = match value { + ParserNumber::F64(f) => { + #[cfg(not(feature = "arbitrary_precision"))] + { + N::Float(f) + } + #[cfg(feature = "arbitrary_precision")] + { + zmij::Buffer::new().format_finite(f).to_owned() + } + } + ParserNumber::U64(u) => { + #[cfg(not(feature = "arbitrary_precision"))] + { + N::PosInt(u) + } + #[cfg(feature = "arbitrary_precision")] + { + itoa::Buffer::new().format(u).to_owned() + } + } + ParserNumber::I64(i) => { + #[cfg(not(feature = "arbitrary_precision"))] + { + N::NegInt(i) + } + #[cfg(feature = "arbitrary_precision")] + { + itoa::Buffer::new().format(i).to_owned() + } + } + #[cfg(feature = "arbitrary_precision")] + ParserNumber::String(s) => s, + }; + Number { n } + } +} + +macro_rules! impl_from_unsigned { + ( + $($ty:ty),* + ) => { + $( + impl From<$ty> for Number { + fn from(u: $ty) -> Self { + let n = { + #[cfg(not(feature = "arbitrary_precision"))] + { N::PosInt(u as u64) } + #[cfg(feature = "arbitrary_precision")] + { + itoa::Buffer::new().format(u).to_owned() + } + }; + Number { n } + } + } + )* + }; +} + +macro_rules! impl_from_signed { + ( + $($ty:ty),* + ) => { + $( + impl From<$ty> for Number { + fn from(i: $ty) -> Self { + let n = { + #[cfg(not(feature = "arbitrary_precision"))] + { + if i < 0 { + N::NegInt(i as i64) + } else { + N::PosInt(i as u64) + } + } + #[cfg(feature = "arbitrary_precision")] + { + itoa::Buffer::new().format(i).to_owned() + } + }; + Number { n } + } + } + )* + }; +} + +impl_from_unsigned!(u8, u16, u32, u64, usize); +impl_from_signed!(i8, i16, i32, i64, isize); + +#[cfg(feature = "arbitrary_precision")] +impl_from_unsigned!(u128); +#[cfg(feature = "arbitrary_precision")] +impl_from_signed!(i128); + +impl Number { + #[cfg(not(feature = "arbitrary_precision"))] + #[cold] + pub(crate) fn unexpected(&self) -> Unexpected { + match self.n { + N::PosInt(u) => Unexpected::Unsigned(u), + N::NegInt(i) => Unexpected::Signed(i), + N::Float(f) => Unexpected::Float(f), + } + } + + #[cfg(feature = "arbitrary_precision")] + #[cold] + pub(crate) fn unexpected(&self) -> Unexpected { + Unexpected::Other("number") + } +} diff --git a/third_party/crates/serde_json-1.0.151/src/raw.rs b/third_party/crates/serde_json-1.0.151/src/raw.rs new file mode 100644 index 0000000..01aa4d3 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/raw.rs @@ -0,0 +1,827 @@ +use crate::error::Error; +use alloc::borrow::ToOwned; +use alloc::boxed::Box; +use alloc::string::String; +use core::fmt::{self, Debug, Display}; +use core::mem; +use serde::de::value::BorrowedStrDeserializer; +use serde::de::{ + self, Deserialize, DeserializeSeed, Deserializer, IntoDeserializer, MapAccess, Unexpected, + Visitor, +}; +use serde::forward_to_deserialize_any; +use serde::ser::{Serialize, SerializeStruct, Serializer}; + +/// Reference to a range of bytes encompassing a single valid JSON value in the +/// input data. +/// +/// A `RawValue` can be used to defer parsing parts of a payload until later, +/// or to avoid parsing it at all in the case that part of the payload just +/// needs to be transferred verbatim into a different output object. +/// +/// When serializing, a value of this type will retain its original formatting +/// and will not be minified or pretty-printed. +/// +/// # Note +/// +/// `RawValue` is only available if serde\_json is built with the `"raw_value"` +/// feature. +/// +/// ```toml +/// [dependencies] +/// serde_json = { version = "1.0", features = ["raw_value"] } +/// ``` +/// +/// # Example +/// +/// ``` +/// use serde::{Deserialize, Serialize}; +/// use serde_json::{Result, value::RawValue}; +/// +/// #[derive(Deserialize)] +/// struct Input<'a> { +/// code: u32, +/// #[serde(borrow)] +/// payload: &'a RawValue, +/// } +/// +/// #[derive(Serialize)] +/// struct Output<'a> { +/// info: (u32, &'a RawValue), +/// } +/// +/// // Efficiently rearrange JSON input containing separate "code" and "payload" +/// // keys into a single "info" key holding an array of code and payload. +/// // +/// // This could be done equivalently using serde_json::Value as the type for +/// // payload, but &RawValue will perform better because it does not require +/// // memory allocation. The correct range of bytes is borrowed from the input +/// // data and pasted verbatim into the output. +/// fn rearrange(input: &str) -> Result { +/// let input: Input = serde_json::from_str(input)?; +/// +/// let output = Output { +/// info: (input.code, input.payload), +/// }; +/// +/// serde_json::to_string(&output) +/// } +/// +/// fn main() -> Result<()> { +/// let out = rearrange(r#" {"code": 200, "payload": {}} "#)?; +/// +/// assert_eq!(out, r#"{"info":[200,{}]}"#); +/// +/// Ok(()) +/// } +/// ``` +/// +/// # Ownership +/// +/// The typical usage of `RawValue` will be in the borrowed form: +/// +/// ``` +/// # use serde::Deserialize; +/// # use serde_json::value::RawValue; +/// # +/// #[derive(Deserialize)] +/// struct SomeStruct<'a> { +/// #[serde(borrow)] +/// raw_value: &'a RawValue, +/// } +/// ``` +/// +/// The borrowed form is suitable when deserializing through +/// [`serde_json::from_str`] and [`serde_json::from_slice`] which support +/// borrowing from the input data without memory allocation. +/// +/// When deserializing through [`serde_json::from_reader`] you will need to use +/// the boxed form of `RawValue` instead. This is almost as efficient but +/// involves buffering the raw value from the I/O stream into memory. +/// +/// [`serde_json::from_str`]: crate::from_str +/// [`serde_json::from_slice`]: crate::from_slice +/// [`serde_json::from_reader`]: crate::from_reader +/// +/// ``` +/// # use serde::Deserialize; +/// # use serde_json::value::RawValue; +/// # +/// #[derive(Deserialize)] +/// struct SomeStruct { +/// raw_value: Box, +/// } +/// ``` +#[cfg_attr(docsrs, doc(cfg(feature = "raw_value")))] +#[repr(transparent)] +pub struct RawValue { + json: str, +} + +impl RawValue { + const fn from_borrowed(json: &str) -> &Self { + unsafe { mem::transmute::<&str, &RawValue>(json) } + } + + fn from_owned(json: Box) -> Box { + unsafe { mem::transmute::, Box>(json) } + } + + fn into_owned(raw_value: Box) -> Box { + unsafe { mem::transmute::, Box>(raw_value) } + } +} + +impl Clone for Box { + fn clone(&self) -> Self { + (**self).to_owned() + } +} + +impl ToOwned for RawValue { + type Owned = Box; + + fn to_owned(&self) -> Self::Owned { + RawValue::from_owned(self.json.to_owned().into_boxed_str()) + } +} + +impl Default for Box { + fn default() -> Self { + RawValue::NULL.to_owned() + } +} + +impl Debug for RawValue { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_tuple("RawValue") + .field(&format_args!("{}", &self.json)) + .finish() + } +} + +impl Display for RawValue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.json) + } +} + +impl RawValue { + /// A constant RawValue with the JSON value `null`. + pub const NULL: &'static RawValue = RawValue::from_borrowed("null"); + /// A constant RawValue with the JSON value `true`. + pub const TRUE: &'static RawValue = RawValue::from_borrowed("true"); + /// A constant RawValue with the JSON value `false`. + pub const FALSE: &'static RawValue = RawValue::from_borrowed("false"); + + /// Convert an owned `String` of JSON data to an owned `RawValue`. + /// + /// This function is equivalent to `serde_json::from_str::>` + /// except that we avoid an allocation and memcpy if both of the following + /// are true: + /// + /// - the input has no leading or trailing whitespace, and + /// - the input has capacity equal to its length. + pub fn from_string(json: String) -> Result, Error> { + let borrowed = tri!(crate::from_str::<&Self>(&json)); + if borrowed.json.len() < json.len() { + return Ok(borrowed.to_owned()); + } + Ok(Self::from_owned(json.into_boxed_str())) + } + + /// Convert an owned `String` of JSON data to an owned `RawValue` without + /// checking that it contains valid JSON. + /// + /// This is the unchecked counterpart of [`RawValue::from_string`], for + /// strings that are already known to be valid JSON, such as the output of + /// another JSON serializer. Unlike `from_string`, it does not re-parse the + /// string; the only cost is `String::into_boxed_str`. + /// + /// # Safety + /// + /// The string passed in must contain a single well-formed JSON value with + /// no leading or trailing whitespace. `RawValue` is written verbatim into + /// JSON output wherever it is embedded, and other code (including unsafe + /// code) is allowed to rely on `RawValue` upholding this invariant, in the + /// same way that unsafe code may rely on `str` containing valid UTF-8. + /// + /// In debug builds this contract is checked with a `debug_assert!` that + /// re-parses the input; the check is compiled out in release builds, so + /// only release performance matches the "no re-parse" guarantee above. + /// + /// # Example + /// + /// ``` + /// use serde_json::value::RawValue; + /// + /// let json = serde_json::to_string(&[1, 2, 3])?; + /// + /// // SAFETY: `json` was produced by serde_json's own serializer, so it is + /// // a single well-formed JSON value without surrounding whitespace. + /// let raw = unsafe { RawValue::from_string_unchecked(json) }; + /// + /// assert_eq!(raw.get(), "[1,2,3]"); + /// # Ok::<(), serde_json::Error>(()) + /// ``` + pub unsafe fn from_string_unchecked(json: String) -> Box { + debug_assert!( + crate::from_str::<&Self>(&json).is_ok_and(|v| v.json.len() == json.len()), + "from_string_unchecked: input is not a single well-formed JSON value \ + with no leading or trailing whitespace", + ); + Self::from_owned(json.into_boxed_str()) + } + + /// Access the JSON text underlying a raw value. + /// + /// # Example + /// + /// ``` + /// use serde::Deserialize; + /// use serde_json::{Result, value::RawValue}; + /// + /// #[derive(Deserialize)] + /// struct Response<'a> { + /// code: u32, + /// #[serde(borrow)] + /// payload: &'a RawValue, + /// } + /// + /// fn process(input: &str) -> Result<()> { + /// let response: Response = serde_json::from_str(input)?; + /// + /// let payload = response.payload.get(); + /// if payload.starts_with('{') { + /// // handle a payload which is a JSON map + /// } else { + /// // handle any other type + /// } + /// + /// Ok(()) + /// } + /// + /// fn main() -> Result<()> { + /// process(r#" {"code": 200, "payload": {}} "#)?; + /// Ok(()) + /// } + /// ``` + pub fn get(&self) -> &str { + &self.json + } +} + +impl From> for Box { + fn from(raw_value: Box) -> Self { + RawValue::into_owned(raw_value) + } +} + +/// Convert a `T` into a boxed `RawValue`. +/// +/// # Example +/// +/// ``` +/// // Upstream crate +/// # #[derive(Serialize)] +/// pub struct Thing { +/// foo: String, +/// bar: Option, +/// extra_data: Box, +/// } +/// +/// // Local crate +/// use serde::Serialize; +/// use serde_json::value::{to_raw_value, RawValue}; +/// +/// #[derive(Serialize)] +/// struct MyExtraData { +/// a: u32, +/// b: u32, +/// } +/// +/// let my_thing = Thing { +/// foo: "FooVal".into(), +/// bar: None, +/// extra_data: to_raw_value(&MyExtraData { a: 1, b: 2 }).unwrap(), +/// }; +/// # assert_eq!( +/// # serde_json::to_value(my_thing).unwrap(), +/// # serde_json::json!({ +/// # "foo": "FooVal", +/// # "bar": null, +/// # "extra_data": { "a": 1, "b": 2 } +/// # }) +/// # ); +/// ``` +/// +/// # Errors +/// +/// This conversion can fail if `T`'s implementation of `Serialize` decides to +/// fail, or if `T` contains a map with non-string keys. +/// +/// ``` +/// use std::collections::BTreeMap; +/// +/// // The keys in this map are vectors, not strings. +/// let mut map = BTreeMap::new(); +/// map.insert(vec![32, 64], "x86"); +/// +/// println!("{}", serde_json::value::to_raw_value(&map).unwrap_err()); +/// ``` +#[cfg_attr(docsrs, doc(cfg(feature = "raw_value")))] +pub fn to_raw_value(value: &T) -> Result, Error> +where + T: ?Sized + Serialize, +{ + let json_string = tri!(crate::to_string(value)); + Ok(RawValue::from_owned(json_string.into_boxed_str())) +} + +pub const TOKEN: &str = "$serde_json::private::RawValue"; + +impl Serialize for RawValue { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut s = tri!(serializer.serialize_struct(TOKEN, 1)); + tri!(s.serialize_field(TOKEN, &self.json)); + s.end() + } +} + +impl<'de: 'a, 'a> Deserialize<'de> for &'a RawValue { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct ReferenceVisitor; + + impl<'de> Visitor<'de> for ReferenceVisitor { + type Value = &'de RawValue; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "any valid JSON value") + } + + fn visit_map(self, mut visitor: V) -> Result + where + V: MapAccess<'de>, + { + let value = tri!(visitor.next_key::()); + if value.is_none() { + return Err(de::Error::invalid_type(Unexpected::Map, &self)); + } + visitor.next_value_seed(ReferenceFromString) + } + } + + deserializer.deserialize_newtype_struct(TOKEN, ReferenceVisitor) + } +} + +impl<'de> Deserialize<'de> for Box { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct BoxedVisitor; + + impl<'de> Visitor<'de> for BoxedVisitor { + type Value = Box; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "any valid JSON value") + } + + fn visit_map(self, mut visitor: V) -> Result + where + V: MapAccess<'de>, + { + let value = tri!(visitor.next_key::()); + if value.is_none() { + return Err(de::Error::invalid_type(Unexpected::Map, &self)); + } + visitor.next_value_seed(BoxedFromString) + } + } + + deserializer.deserialize_newtype_struct(TOKEN, BoxedVisitor) + } +} + +struct RawKey; + +impl<'de> Deserialize<'de> for RawKey { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct FieldVisitor; + + impl<'de> Visitor<'de> for FieldVisitor { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("raw value") + } + + fn visit_str(self, s: &str) -> Result<(), E> + where + E: de::Error, + { + if s == TOKEN { + Ok(()) + } else { + Err(de::Error::custom("unexpected raw value")) + } + } + } + + tri!(deserializer.deserialize_identifier(FieldVisitor)); + Ok(RawKey) + } +} + +pub struct ReferenceFromString; + +impl<'de> DeserializeSeed<'de> for ReferenceFromString { + type Value = &'de RawValue; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(self) + } +} + +impl<'de> Visitor<'de> for ReferenceFromString { + type Value = &'de RawValue; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("raw value") + } + + fn visit_borrowed_str(self, s: &'de str) -> Result + where + E: de::Error, + { + Ok(RawValue::from_borrowed(s)) + } +} + +pub struct BoxedFromString; + +impl<'de> DeserializeSeed<'de> for BoxedFromString { + type Value = Box; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(self) + } +} + +impl<'de> Visitor<'de> for BoxedFromString { + type Value = Box; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("raw value") + } + + fn visit_str(self, s: &str) -> Result + where + E: de::Error, + { + Ok(RawValue::from_owned(s.to_owned().into_boxed_str())) + } + + #[cfg(any(feature = "std", feature = "alloc"))] + fn visit_string(self, s: String) -> Result + where + E: de::Error, + { + Ok(RawValue::from_owned(s.into_boxed_str())) + } +} + +struct RawKeyDeserializer; + +impl<'de> Deserializer<'de> for RawKeyDeserializer { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_borrowed_str(TOKEN) + } + + forward_to_deserialize_any! { + bool u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 char str string seq + bytes byte_buf map struct option unit newtype_struct ignored_any + unit_struct tuple_struct tuple enum identifier + } +} + +pub struct OwnedRawDeserializer { + pub raw_value: Option, +} + +impl<'de> MapAccess<'de> for OwnedRawDeserializer { + type Error = Error; + + fn next_key_seed(&mut self, seed: K) -> Result, Error> + where + K: de::DeserializeSeed<'de>, + { + if self.raw_value.is_none() { + return Ok(None); + } + seed.deserialize(RawKeyDeserializer).map(Some) + } + + fn next_value_seed(&mut self, seed: V) -> Result + where + V: de::DeserializeSeed<'de>, + { + seed.deserialize(self.raw_value.take().unwrap().into_deserializer()) + } +} + +pub struct BorrowedRawDeserializer<'de> { + pub raw_value: Option<&'de str>, +} + +impl<'de> MapAccess<'de> for BorrowedRawDeserializer<'de> { + type Error = Error; + + fn next_key_seed(&mut self, seed: K) -> Result, Error> + where + K: de::DeserializeSeed<'de>, + { + if self.raw_value.is_none() { + return Ok(None); + } + seed.deserialize(RawKeyDeserializer).map(Some) + } + + fn next_value_seed(&mut self, seed: V) -> Result + where + V: de::DeserializeSeed<'de>, + { + seed.deserialize(BorrowedStrDeserializer::new(self.raw_value.take().unwrap())) + } +} + +impl<'de> IntoDeserializer<'de, Error> for &'de RawValue { + type Deserializer = &'de RawValue; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} + +impl<'de> Deserializer<'de> for &'de RawValue { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_any(visitor) + } + + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_bool(visitor) + } + + fn deserialize_i8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_i8(visitor) + } + + fn deserialize_i16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_i16(visitor) + } + + fn deserialize_i32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_i32(visitor) + } + + fn deserialize_i64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_i64(visitor) + } + + fn deserialize_i128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_i128(visitor) + } + + fn deserialize_u8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_u8(visitor) + } + + fn deserialize_u16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_u16(visitor) + } + + fn deserialize_u32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_u32(visitor) + } + + fn deserialize_u64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_u64(visitor) + } + + fn deserialize_u128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_u128(visitor) + } + + fn deserialize_f32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_f32(visitor) + } + + fn deserialize_f64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_f64(visitor) + } + + fn deserialize_char(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_char(visitor) + } + + fn deserialize_str(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_str(visitor) + } + + fn deserialize_string(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_string(visitor) + } + + fn deserialize_bytes(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_bytes(visitor) + } + + fn deserialize_byte_buf(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_byte_buf(visitor) + } + + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_option(visitor) + } + + fn deserialize_unit(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_unit(visitor) + } + + fn deserialize_unit_struct(self, name: &'static str, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_unit_struct(name, visitor) + } + + fn deserialize_newtype_struct( + self, + name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_newtype_struct(name, visitor) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_seq(visitor) + } + + fn deserialize_tuple(self, len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_tuple(len, visitor) + } + + fn deserialize_tuple_struct( + self, + name: &'static str, + len: usize, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_tuple_struct(name, len, visitor) + } + + fn deserialize_map(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_map(visitor) + } + + fn deserialize_struct( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_struct(name, fields, visitor) + } + + fn deserialize_enum( + self, + name: &'static str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_enum(name, variants, visitor) + } + + fn deserialize_identifier(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_identifier(visitor) + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + crate::Deserializer::from_str(&self.json).deserialize_ignored_any(visitor) + } +} diff --git a/third_party/crates/serde_json-1.0.151/src/read.rs b/third_party/crates/serde_json-1.0.151/src/read.rs new file mode 100644 index 0000000..f90d9f7 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/read.rs @@ -0,0 +1,1089 @@ +use crate::error::{Error, ErrorCode, Result}; +use alloc::vec::Vec; +use core::cmp; +use core::mem; +use core::ops::Deref; +use core::str; + +#[cfg(feature = "std")] +use crate::io; +#[cfg(feature = "std")] +use crate::iter::LineColIterator; + +#[cfg(feature = "raw_value")] +use crate::raw::BorrowedRawDeserializer; +#[cfg(all(feature = "raw_value", feature = "std"))] +use crate::raw::OwnedRawDeserializer; +#[cfg(all(feature = "raw_value", feature = "std"))] +use alloc::string::String; +#[cfg(feature = "raw_value")] +use serde::de::Visitor; + +/// Trait used by the deserializer for iterating over input. This is manually +/// "specialized" for iterating over `&[u8]`. Once feature(specialization) is +/// stable we can use actual specialization. +/// +/// This trait is sealed and cannot be implemented for types outside of +/// `serde_json`. +pub trait Read<'de>: private::Sealed { + #[doc(hidden)] + fn next(&mut self) -> Result>; + #[doc(hidden)] + fn peek(&mut self) -> Result>; + + /// Only valid after a call to peek(). Discards the peeked byte. + #[doc(hidden)] + fn discard(&mut self); + + /// Position of the most recent call to next(). + /// + /// The most recent call was probably next() and not peek(), but this method + /// should try to return a sensible result if the most recent call was + /// actually peek() because we don't always know. + /// + /// Only called in case of an error, so performance is not important. + #[doc(hidden)] + fn position(&self) -> Position; + + /// Position of the most recent call to peek(). + /// + /// The most recent call was probably peek() and not next(), but this method + /// should try to return a sensible result if the most recent call was + /// actually next() because we don't always know. + /// + /// Only called in case of an error, so performance is not important. + #[doc(hidden)] + fn peek_position(&self) -> Position; + + /// Offset from the beginning of the input to the next byte that would be + /// returned by next() or peek(). + #[doc(hidden)] + fn byte_offset(&self) -> usize; + + /// Assumes the previous byte was a quotation mark. Parses a JSON-escaped + /// string until the next quotation mark using the given scratch space if + /// necessary. The scratch space is initially empty. + #[doc(hidden)] + fn parse_str<'s>(&'s mut self, scratch: &'s mut Vec) -> Result>; + + /// Assumes the previous byte was a quotation mark. Parses a JSON-escaped + /// string until the next quotation mark using the given scratch space if + /// necessary. The scratch space is initially empty. + /// + /// This function returns the raw bytes in the string with escape sequences + /// expanded but without performing unicode validation. + #[doc(hidden)] + fn parse_str_raw<'s>( + &'s mut self, + scratch: &'s mut Vec, + ) -> Result>; + + /// Assumes the previous byte was a quotation mark. Parses a JSON-escaped + /// string until the next quotation mark but discards the data. + #[doc(hidden)] + fn ignore_str(&mut self) -> Result<()>; + + /// Assumes the previous byte was a hex escape sequence ('\u') in a string. + /// Parses next hexadecimal sequence. + #[doc(hidden)] + fn decode_hex_escape(&mut self) -> Result; + + /// Switch raw buffering mode on. + /// + /// This is used when deserializing `RawValue`. + #[cfg(feature = "raw_value")] + #[doc(hidden)] + fn begin_raw_buffering(&mut self); + + /// Switch raw buffering mode off and provides the raw buffered data to the + /// given visitor. + #[cfg(feature = "raw_value")] + #[doc(hidden)] + fn end_raw_buffering(&mut self, visitor: V) -> Result + where + V: Visitor<'de>; + + /// Whether StreamDeserializer::next needs to check the failed flag. True + /// for IoRead, false for StrRead and SliceRead which can track failure by + /// truncating their input slice to avoid the extra check on every next + /// call. + #[doc(hidden)] + const should_early_return_if_failed: bool; + + /// Mark a persistent failure of StreamDeserializer, either by setting the + /// flag or by truncating the input data. + #[doc(hidden)] + fn set_failed(&mut self, failed: &mut bool); +} + +pub struct Position { + pub line: usize, + pub column: usize, +} + +pub enum Reference<'b, 'c, T> +where + T: ?Sized + 'static, +{ + Borrowed(&'b T), + Copied(&'c T), +} + +impl<'b, 'c, T> Deref for Reference<'b, 'c, T> +where + T: ?Sized + 'static, +{ + type Target = T; + + fn deref(&self) -> &Self::Target { + match *self { + Reference::Borrowed(b) => b, + Reference::Copied(c) => c, + } + } +} + +/// JSON input source that reads from a std::io input stream. +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +pub struct IoRead +where + R: io::Read, +{ + iter: LineColIterator>, + /// Temporary storage of peeked byte. + ch: Option, + #[cfg(feature = "raw_value")] + raw_buffer: Option>, +} + +/// JSON input source that reads from a slice of bytes. +// +// This is more efficient than other iterators because peek() can be read-only +// and we can compute line/col position only if an error happens. +pub struct SliceRead<'a> { + slice: &'a [u8], + /// Index of the *next* byte that will be returned by next() or peek(). + index: usize, + #[cfg(feature = "raw_value")] + raw_buffering_start_index: usize, +} + +/// JSON input source that reads from a UTF-8 string. +// +// Able to elide UTF-8 checks by assuming that the input is valid UTF-8. +pub struct StrRead<'a> { + delegate: SliceRead<'a>, + #[cfg(feature = "raw_value")] + data: &'a str, +} + +// Prevent users from implementing the Read trait. +mod private { + pub trait Sealed {} +} + +////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "std")] +impl IoRead +where + R: io::Read, +{ + /// Create a JSON input source to read from a std::io input stream. + /// + /// When reading from a source against which short reads are not efficient, such + /// as a [`File`], you will want to apply your own buffering because serde_json + /// will not buffer the input. See [`std::io::BufReader`]. + /// + /// [`File`]: std::fs::File + pub fn new(reader: R) -> Self { + IoRead { + iter: LineColIterator::new(reader.bytes()), + ch: None, + #[cfg(feature = "raw_value")] + raw_buffer: None, + } + } +} + +#[cfg(feature = "std")] +impl private::Sealed for IoRead where R: io::Read {} + +#[cfg(feature = "std")] +impl IoRead +where + R: io::Read, +{ + fn parse_str_bytes<'s, T, F>( + &'s mut self, + scratch: &'s mut Vec, + validate: bool, + result: F, + ) -> Result + where + T: 's, + F: FnOnce(&'s Self, &'s [u8]) -> Result, + { + loop { + let ch = tri!(next_or_eof(self)); + if !is_escape(ch, true) { + scratch.push(ch); + continue; + } + match ch { + b'"' => { + return result(self, scratch); + } + b'\\' => { + tri!(parse_escape(self, validate, scratch)); + } + _ => { + if validate { + return error(self, ErrorCode::ControlCharacterWhileParsingString); + } + scratch.push(ch); + } + } + } + } +} + +#[cfg(feature = "std")] +impl<'de, R> Read<'de> for IoRead +where + R: io::Read, +{ + #[inline] + fn next(&mut self) -> Result> { + match self.ch.take() { + Some(ch) => { + #[cfg(feature = "raw_value")] + { + if let Some(buf) = &mut self.raw_buffer { + buf.push(ch); + } + } + Ok(Some(ch)) + } + None => match self.iter.next() { + Some(Err(err)) => Err(Error::io(err)), + Some(Ok(ch)) => { + #[cfg(feature = "raw_value")] + { + if let Some(buf) = &mut self.raw_buffer { + buf.push(ch); + } + } + Ok(Some(ch)) + } + None => Ok(None), + }, + } + } + + #[inline] + fn peek(&mut self) -> Result> { + match self.ch { + Some(ch) => Ok(Some(ch)), + None => match self.iter.next() { + Some(Err(err)) => Err(Error::io(err)), + Some(Ok(ch)) => { + self.ch = Some(ch); + Ok(self.ch) + } + None => Ok(None), + }, + } + } + + #[cfg(not(feature = "raw_value"))] + #[inline] + fn discard(&mut self) { + self.ch = None; + } + + #[cfg(feature = "raw_value")] + fn discard(&mut self) { + if let Some(ch) = self.ch.take() { + if let Some(buf) = &mut self.raw_buffer { + buf.push(ch); + } + } + } + + fn position(&self) -> Position { + Position { + line: self.iter.line(), + column: self.iter.col(), + } + } + + fn peek_position(&self) -> Position { + // The LineColIterator updates its position during peek() so it has the + // right one here. + self.position() + } + + fn byte_offset(&self) -> usize { + match self.ch { + Some(_) => self.iter.byte_offset() - 1, + None => self.iter.byte_offset(), + } + } + + fn parse_str<'s>(&'s mut self, scratch: &'s mut Vec) -> Result> { + self.parse_str_bytes(scratch, true, as_str) + .map(Reference::Copied) + } + + fn parse_str_raw<'s>( + &'s mut self, + scratch: &'s mut Vec, + ) -> Result> { + self.parse_str_bytes(scratch, false, |_, bytes| Ok(bytes)) + .map(Reference::Copied) + } + + fn ignore_str(&mut self) -> Result<()> { + loop { + let ch = tri!(next_or_eof(self)); + if !is_escape(ch, true) { + continue; + } + match ch { + b'"' => { + return Ok(()); + } + b'\\' => { + tri!(ignore_escape(self)); + } + _ => { + return error(self, ErrorCode::ControlCharacterWhileParsingString); + } + } + } + } + + fn decode_hex_escape(&mut self) -> Result { + let a = tri!(next_or_eof(self)); + let b = tri!(next_or_eof(self)); + let c = tri!(next_or_eof(self)); + let d = tri!(next_or_eof(self)); + match decode_four_hex_digits(a, b, c, d) { + Some(val) => Ok(val), + None => error(self, ErrorCode::InvalidEscape), + } + } + + #[cfg(feature = "raw_value")] + fn begin_raw_buffering(&mut self) { + self.raw_buffer = Some(Vec::new()); + } + + #[cfg(feature = "raw_value")] + fn end_raw_buffering(&mut self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let raw = self.raw_buffer.take().unwrap(); + let raw = match String::from_utf8(raw) { + Ok(raw) => raw, + Err(_) => return error(self, ErrorCode::InvalidUnicodeCodePoint), + }; + visitor.visit_map(OwnedRawDeserializer { + raw_value: Some(raw), + }) + } + + const should_early_return_if_failed: bool = true; + + #[inline] + #[cold] + fn set_failed(&mut self, failed: &mut bool) { + *failed = true; + } +} + +////////////////////////////////////////////////////////////////////////////// + +impl<'a> SliceRead<'a> { + /// Create a JSON input source to read from a slice of bytes. + pub fn new(slice: &'a [u8]) -> Self { + SliceRead { + slice, + index: 0, + #[cfg(feature = "raw_value")] + raw_buffering_start_index: 0, + } + } + + fn position_of_index(&self, i: usize) -> Position { + let start_of_line = match memchr::memrchr(b'\n', &self.slice[..i]) { + Some(position) => position + 1, + None => 0, + }; + Position { + line: 1 + memchr::memchr_iter(b'\n', &self.slice[..start_of_line]).count(), + column: i - start_of_line, + } + } + + fn skip_to_escape(&mut self, forbid_control_characters: bool) { + // Immediately bail-out on empty strings and consecutive escapes (e.g. \u041b\u0435) + if self.index == self.slice.len() + || is_escape(self.slice[self.index], forbid_control_characters) + { + return; + } + self.index += 1; + + let rest = &self.slice[self.index..]; + + if !forbid_control_characters { + self.index += memchr::memchr2(b'"', b'\\', rest).unwrap_or(rest.len()); + return; + } + + // We wish to find the first byte in range 0x00..=0x1F or " or \. Ideally, we'd use + // something akin to memchr3, but the memchr crate does not support this at the moment. + // Therefore, we use a variation on Mycroft's algorithm [1] to provide performance better + // than a naive loop. It runs faster than equivalent two-pass memchr2+SWAR code on + // benchmarks and it's cross-platform, so probably the right fit. + // [1]: https://groups.google.com/forum/#!original/comp.lang.c/2HtQXvg7iKc/xOJeipH6KLMJ + + #[cfg(fast_arithmetic = "64")] + type Chunk = u64; + #[cfg(fast_arithmetic = "32")] + type Chunk = u32; + + const STEP: usize = mem::size_of::(); + const ONE_BYTES: Chunk = Chunk::MAX / 255; // 0x0101...01 + + for chunk in rest.chunks_exact(STEP) { + let chars = Chunk::from_le_bytes(chunk.try_into().unwrap()); + let contains_ctrl = chars.wrapping_sub(ONE_BYTES * 0x20) & !chars; + let chars_quote = chars ^ (ONE_BYTES * Chunk::from(b'"')); + let contains_quote = chars_quote.wrapping_sub(ONE_BYTES) & !chars_quote; + let chars_backslash = chars ^ (ONE_BYTES * Chunk::from(b'\\')); + let contains_backslash = chars_backslash.wrapping_sub(ONE_BYTES) & !chars_backslash; + let masked = (contains_ctrl | contains_quote | contains_backslash) & (ONE_BYTES << 7); + if masked != 0 { + // SAFETY: chunk is in-bounds for slice + self.index = unsafe { chunk.as_ptr().offset_from(self.slice.as_ptr()) } as usize + + masked.trailing_zeros() as usize / 8; + return; + } + } + + self.index += rest.len() / STEP * STEP; + self.skip_to_escape_slow(); + } + + #[cold] + #[inline(never)] + fn skip_to_escape_slow(&mut self) { + while self.index < self.slice.len() && !is_escape(self.slice[self.index], true) { + self.index += 1; + } + } + + /// The big optimization here over IoRead is that if the string contains no + /// backslash escape sequences, the returned &str is a slice of the raw JSON + /// data so we avoid copying into the scratch space. + fn parse_str_bytes<'s, T, F>( + &'s mut self, + scratch: &'s mut Vec, + validate: bool, + result: F, + ) -> Result> + where + T: ?Sized + 's, + F: for<'f> FnOnce(&'s Self, &'f [u8]) -> Result<&'f T>, + { + // Index of the first byte not yet copied into the scratch space. + let mut start = self.index; + + loop { + self.skip_to_escape(validate); + if self.index == self.slice.len() { + return error(self, ErrorCode::EofWhileParsingString); + } + match self.slice[self.index] { + b'"' => { + if scratch.is_empty() { + // Fast path: return a slice of the raw JSON without any + // copying. + let borrowed = &self.slice[start..self.index]; + self.index += 1; + return result(self, borrowed).map(Reference::Borrowed); + } else { + scratch.extend_from_slice(&self.slice[start..self.index]); + self.index += 1; + return result(self, scratch).map(Reference::Copied); + } + } + b'\\' => { + scratch.extend_from_slice(&self.slice[start..self.index]); + self.index += 1; + tri!(parse_escape(self, validate, scratch)); + start = self.index; + } + _ => { + self.index += 1; + return error(self, ErrorCode::ControlCharacterWhileParsingString); + } + } + } + } +} + +impl<'a> private::Sealed for SliceRead<'a> {} + +impl<'a> Read<'a> for SliceRead<'a> { + #[inline] + fn next(&mut self) -> Result> { + // `Ok(self.slice.get(self.index).map(|ch| { self.index += 1; *ch }))` + // is about 10% slower. + Ok(if self.index < self.slice.len() { + let ch = self.slice[self.index]; + self.index += 1; + Some(ch) + } else { + None + }) + } + + #[inline] + fn peek(&mut self) -> Result> { + // `Ok(self.slice.get(self.index).map(|ch| *ch))` is about 10% slower + // for some reason. + Ok(if self.index < self.slice.len() { + Some(self.slice[self.index]) + } else { + None + }) + } + + #[inline] + fn discard(&mut self) { + self.index += 1; + } + + fn position(&self) -> Position { + self.position_of_index(self.index) + } + + fn peek_position(&self) -> Position { + // Cap it at slice.len() just in case the most recent call was next() + // and it returned the last byte. + self.position_of_index(cmp::min(self.slice.len(), self.index + 1)) + } + + fn byte_offset(&self) -> usize { + self.index + } + + fn parse_str<'s>(&'s mut self, scratch: &'s mut Vec) -> Result> { + self.parse_str_bytes(scratch, true, as_str) + } + + fn parse_str_raw<'s>( + &'s mut self, + scratch: &'s mut Vec, + ) -> Result> { + self.parse_str_bytes(scratch, false, |_, bytes| Ok(bytes)) + } + + fn ignore_str(&mut self) -> Result<()> { + loop { + self.skip_to_escape(true); + if self.index == self.slice.len() { + return error(self, ErrorCode::EofWhileParsingString); + } + match self.slice[self.index] { + b'"' => { + self.index += 1; + return Ok(()); + } + b'\\' => { + self.index += 1; + tri!(ignore_escape(self)); + } + _ => { + return error(self, ErrorCode::ControlCharacterWhileParsingString); + } + } + } + } + + #[inline] + fn decode_hex_escape(&mut self) -> Result { + match self.slice[self.index..] { + [a, b, c, d, ..] => { + self.index += 4; + match decode_four_hex_digits(a, b, c, d) { + Some(val) => Ok(val), + None => error(self, ErrorCode::InvalidEscape), + } + } + _ => { + self.index = self.slice.len(); + error(self, ErrorCode::EofWhileParsingString) + } + } + } + + #[cfg(feature = "raw_value")] + fn begin_raw_buffering(&mut self) { + self.raw_buffering_start_index = self.index; + } + + #[cfg(feature = "raw_value")] + fn end_raw_buffering(&mut self, visitor: V) -> Result + where + V: Visitor<'a>, + { + let raw = &self.slice[self.raw_buffering_start_index..self.index]; + let raw = match str::from_utf8(raw) { + Ok(raw) => raw, + Err(_) => return error(self, ErrorCode::InvalidUnicodeCodePoint), + }; + visitor.visit_map(BorrowedRawDeserializer { + raw_value: Some(raw), + }) + } + + const should_early_return_if_failed: bool = false; + + #[inline] + #[cold] + fn set_failed(&mut self, _failed: &mut bool) { + self.slice = &self.slice[..self.index]; + } +} + +////////////////////////////////////////////////////////////////////////////// + +impl<'a> StrRead<'a> { + /// Create a JSON input source to read from a UTF-8 string. + pub fn new(s: &'a str) -> Self { + StrRead { + delegate: SliceRead::new(s.as_bytes()), + #[cfg(feature = "raw_value")] + data: s, + } + } +} + +impl<'a> private::Sealed for StrRead<'a> {} + +impl<'a> Read<'a> for StrRead<'a> { + #[inline] + fn next(&mut self) -> Result> { + self.delegate.next() + } + + #[inline] + fn peek(&mut self) -> Result> { + self.delegate.peek() + } + + #[inline] + fn discard(&mut self) { + self.delegate.discard(); + } + + fn position(&self) -> Position { + self.delegate.position() + } + + fn peek_position(&self) -> Position { + self.delegate.peek_position() + } + + fn byte_offset(&self) -> usize { + self.delegate.byte_offset() + } + + fn parse_str<'s>(&'s mut self, scratch: &'s mut Vec) -> Result> { + self.delegate.parse_str_bytes(scratch, true, |_, bytes| { + // The deserialization input came in as &str with a UTF-8 guarantee, + // and the \u-escapes are checked along the way, so don't need to + // check here. + Ok(unsafe { str::from_utf8_unchecked(bytes) }) + }) + } + + fn parse_str_raw<'s>( + &'s mut self, + scratch: &'s mut Vec, + ) -> Result> { + self.delegate.parse_str_raw(scratch) + } + + fn ignore_str(&mut self) -> Result<()> { + self.delegate.ignore_str() + } + + fn decode_hex_escape(&mut self) -> Result { + self.delegate.decode_hex_escape() + } + + #[cfg(feature = "raw_value")] + fn begin_raw_buffering(&mut self) { + self.delegate.begin_raw_buffering(); + } + + #[cfg(feature = "raw_value")] + fn end_raw_buffering(&mut self, visitor: V) -> Result + where + V: Visitor<'a>, + { + let raw = &self.data[self.delegate.raw_buffering_start_index..self.delegate.index]; + visitor.visit_map(BorrowedRawDeserializer { + raw_value: Some(raw), + }) + } + + const should_early_return_if_failed: bool = false; + + #[inline] + #[cold] + fn set_failed(&mut self, failed: &mut bool) { + self.delegate.set_failed(failed); + } +} + +////////////////////////////////////////////////////////////////////////////// + +impl<'de, R> private::Sealed for &mut R where R: Read<'de> {} + +impl<'de, R> Read<'de> for &mut R +where + R: Read<'de>, +{ + fn next(&mut self) -> Result> { + R::next(self) + } + + fn peek(&mut self) -> Result> { + R::peek(self) + } + + fn discard(&mut self) { + R::discard(self); + } + + fn position(&self) -> Position { + R::position(self) + } + + fn peek_position(&self) -> Position { + R::peek_position(self) + } + + fn byte_offset(&self) -> usize { + R::byte_offset(self) + } + + fn parse_str<'s>(&'s mut self, scratch: &'s mut Vec) -> Result> { + R::parse_str(self, scratch) + } + + fn parse_str_raw<'s>( + &'s mut self, + scratch: &'s mut Vec, + ) -> Result> { + R::parse_str_raw(self, scratch) + } + + fn ignore_str(&mut self) -> Result<()> { + R::ignore_str(self) + } + + fn decode_hex_escape(&mut self) -> Result { + R::decode_hex_escape(self) + } + + #[cfg(feature = "raw_value")] + fn begin_raw_buffering(&mut self) { + R::begin_raw_buffering(self); + } + + #[cfg(feature = "raw_value")] + fn end_raw_buffering(&mut self, visitor: V) -> Result + where + V: Visitor<'de>, + { + R::end_raw_buffering(self, visitor) + } + + const should_early_return_if_failed: bool = R::should_early_return_if_failed; + + fn set_failed(&mut self, failed: &mut bool) { + R::set_failed(self, failed); + } +} + +////////////////////////////////////////////////////////////////////////////// + +/// Marker for whether StreamDeserializer can implement FusedIterator. +pub trait Fused: private::Sealed {} +impl<'a> Fused for SliceRead<'a> {} +impl<'a> Fused for StrRead<'a> {} + +fn is_escape(ch: u8, including_control_characters: bool) -> bool { + ch == b'"' || ch == b'\\' || (including_control_characters && ch < 0x20) +} + +fn next_or_eof<'de, R>(read: &mut R) -> Result +where + R: ?Sized + Read<'de>, +{ + match tri!(read.next()) { + Some(b) => Ok(b), + None => error(read, ErrorCode::EofWhileParsingString), + } +} + +fn peek_or_eof<'de, R>(read: &mut R) -> Result +where + R: ?Sized + Read<'de>, +{ + match tri!(read.peek()) { + Some(b) => Ok(b), + None => error(read, ErrorCode::EofWhileParsingString), + } +} + +fn error<'de, R, T>(read: &R, reason: ErrorCode) -> Result +where + R: ?Sized + Read<'de>, +{ + let position = read.position(); + Err(Error::syntax(reason, position.line, position.column)) +} + +fn as_str<'de, 's, R: Read<'de>>(read: &R, slice: &'s [u8]) -> Result<&'s str> { + str::from_utf8(slice).or_else(|_| error(read, ErrorCode::InvalidUnicodeCodePoint)) +} + +/// Parses a JSON escape sequence and appends it into the scratch space. Assumes +/// the previous byte read was a backslash. +fn parse_escape<'de, R: Read<'de>>( + read: &mut R, + validate: bool, + scratch: &mut Vec, +) -> Result<()> { + let ch = tri!(next_or_eof(read)); + + match ch { + b'"' => scratch.push(b'"'), + b'\\' => scratch.push(b'\\'), + b'/' => scratch.push(b'/'), + b'b' => scratch.push(b'\x08'), + b'f' => scratch.push(b'\x0c'), + b'n' => scratch.push(b'\n'), + b'r' => scratch.push(b'\r'), + b't' => scratch.push(b'\t'), + b'u' => return parse_unicode_escape(read, validate, scratch), + _ => return error(read, ErrorCode::InvalidEscape), + } + + Ok(()) +} + +/// Parses a JSON \u escape and appends it into the scratch space. Assumes `\u` +/// has just been read. +#[cold] +fn parse_unicode_escape<'de, R: Read<'de>>( + read: &mut R, + validate: bool, + scratch: &mut Vec, +) -> Result<()> { + let mut n = tri!(read.decode_hex_escape()); + + // Non-BMP characters are encoded as a sequence of two hex escapes, + // representing UTF-16 surrogates. If deserializing a utf-8 string the + // surrogates are required to be paired, whereas deserializing a byte string + // accepts lone surrogates. + if validate && n >= 0xDC00 && n <= 0xDFFF { + // XXX: This is actually a trailing surrogate. + return error(read, ErrorCode::LoneLeadingSurrogateInHexEscape); + } + + loop { + if n < 0xD800 || n > 0xDBFF { + // Every u16 outside of the surrogate ranges is guaranteed to be a + // legal char. + push_wtf8_codepoint(n as u32, scratch); + return Ok(()); + } + + // n is a leading surrogate, we now expect a trailing surrogate. + let n1 = n; + + if tri!(peek_or_eof(read)) == b'\\' { + read.discard(); + } else { + return if validate { + read.discard(); + error(read, ErrorCode::UnexpectedEndOfHexEscape) + } else { + push_wtf8_codepoint(n1 as u32, scratch); + Ok(()) + }; + } + + if tri!(peek_or_eof(read)) == b'u' { + read.discard(); + } else { + return if validate { + read.discard(); + error(read, ErrorCode::UnexpectedEndOfHexEscape) + } else { + push_wtf8_codepoint(n1 as u32, scratch); + // The \ prior to this byte started an escape sequence, so we + // need to parse that now. This recursive call does not blow the + // stack on malicious input because the escape is not \u, so it + // will be handled by one of the easy nonrecursive cases. + parse_escape(read, validate, scratch) + }; + } + + let n2 = tri!(read.decode_hex_escape()); + + if n2 < 0xDC00 || n2 > 0xDFFF { + if validate { + return error(read, ErrorCode::LoneLeadingSurrogateInHexEscape); + } + push_wtf8_codepoint(n1 as u32, scratch); + // If n2 is a leading surrogate, we need to restart. + n = n2; + continue; + } + + // This value is in range U+10000..=U+10FFFF, which is always a valid + // codepoint. + let n = ((((n1 - 0xD800) as u32) << 10) | (n2 - 0xDC00) as u32) + 0x1_0000; + push_wtf8_codepoint(n, scratch); + return Ok(()); + } +} + +/// Adds a WTF-8 codepoint to the end of the buffer. This is a more efficient +/// implementation of String::push. The codepoint may be a surrogate. +#[inline] +fn push_wtf8_codepoint(n: u32, scratch: &mut Vec) { + if n < 0x80 { + scratch.push(n as u8); + return; + } + + scratch.reserve(4); + + // SAFETY: After the `reserve` call, `scratch` has at least 4 bytes of + // allocated but uninitialized memory after its last initialized byte, which + // is where `ptr` points. All reachable match arms write `encoded_len` bytes + // to that region and update the length accordingly, and `encoded_len` is + // always <= 4. + unsafe { + let ptr = scratch.as_mut_ptr().add(scratch.len()); + + let encoded_len = match n { + 0..=0x7F => unreachable!(), + 0x80..=0x7FF => { + ptr.write(((n >> 6) & 0b0001_1111) as u8 | 0b1100_0000); + 2 + } + 0x800..=0xFFFF => { + ptr.write(((n >> 12) & 0b0000_1111) as u8 | 0b1110_0000); + ptr.add(1) + .write(((n >> 6) & 0b0011_1111) as u8 | 0b1000_0000); + 3 + } + 0x1_0000..=0x10_FFFF => { + ptr.write(((n >> 18) & 0b0000_0111) as u8 | 0b1111_0000); + ptr.add(1) + .write(((n >> 12) & 0b0011_1111) as u8 | 0b1000_0000); + ptr.add(2) + .write(((n >> 6) & 0b0011_1111) as u8 | 0b1000_0000); + 4 + } + 0x11_0000.. => unreachable!(), + }; + ptr.add(encoded_len - 1) + .write((n & 0b0011_1111) as u8 | 0b1000_0000); + + scratch.set_len(scratch.len() + encoded_len); + } +} + +/// Parses a JSON escape sequence and discards the value. Assumes the previous +/// byte read was a backslash. +fn ignore_escape<'de, R>(read: &mut R) -> Result<()> +where + R: ?Sized + Read<'de>, +{ + let ch = tri!(next_or_eof(read)); + + match ch { + b'"' | b'\\' | b'/' | b'b' | b'f' | b'n' | b'r' | b't' => {} + b'u' => { + // At this point we don't care if the codepoint is valid. We just + // want to consume it. We don't actually know what is valid or not + // at this point, because that depends on if this string will + // ultimately be parsed into a string or a byte buffer in the "real" + // parse. + + tri!(read.decode_hex_escape()); + } + _ => { + return error(read, ErrorCode::InvalidEscape); + } + } + + Ok(()) +} + +const fn decode_hex_val_slow(val: u8) -> Option { + match val { + b'0'..=b'9' => Some(val - b'0'), + b'A'..=b'F' => Some(val - b'A' + 10), + b'a'..=b'f' => Some(val - b'a' + 10), + _ => None, + } +} + +const fn build_hex_table(shift: usize) -> [i16; 256] { + let mut table = [0; 256]; + let mut ch = 0; + while ch < 256 { + table[ch] = match decode_hex_val_slow(ch as u8) { + Some(val) => (val as i16) << shift, + None => -1, + }; + ch += 1; + } + table +} + +static HEX0: [i16; 256] = build_hex_table(0); +static HEX1: [i16; 256] = build_hex_table(4); + +fn decode_four_hex_digits(a: u8, b: u8, c: u8, d: u8) -> Option { + let a = HEX1[a as usize] as i32; + let b = HEX0[b as usize] as i32; + let c = HEX1[c as usize] as i32; + let d = HEX0[d as usize] as i32; + + let codepoint = ((a | b) << 8) | c | d; + + // A single sign bit check. + if codepoint >= 0 { + Some(codepoint as u16) + } else { + None + } +} diff --git a/third_party/crates/serde_json-1.0.151/src/ser.rs b/third_party/crates/serde_json-1.0.151/src/ser.rs new file mode 100644 index 0000000..053f95a --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/ser.rs @@ -0,0 +1,2285 @@ +//! Serialize a Rust data structure into JSON data. + +use crate::error::{Error, ErrorCode, Result}; +use crate::io; +use alloc::string::String; +#[cfg(feature = "raw_value")] +use alloc::string::ToString; +use alloc::vec::Vec; +use core::fmt::{self, Display}; +use core::hint; +use core::num::FpCategory; +use core::str; +use serde::ser::{self, Impossible, Serialize}; + +/// A structure for serializing Rust values into JSON. +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +pub struct Serializer { + writer: W, + formatter: F, +} + +impl Serializer +where + W: io::Write, +{ + /// Creates a new JSON serializer. + #[inline] + pub fn new(writer: W) -> Self { + Serializer::with_formatter(writer, CompactFormatter) + } +} + +impl<'a, W> Serializer> +where + W: io::Write, +{ + /// Creates a new JSON pretty print serializer. + #[inline] + pub fn pretty(writer: W) -> Self { + Serializer::with_formatter(writer, PrettyFormatter::new()) + } +} + +impl Serializer +where + W: io::Write, + F: Formatter, +{ + /// Creates a new JSON visitor whose output will be written to the writer + /// specified. + #[inline] + pub fn with_formatter(writer: W, formatter: F) -> Self { + Serializer { writer, formatter } + } + + /// Unwrap the `Writer` from the `Serializer`. + #[inline] + pub fn into_inner(self) -> W { + self.writer + } +} + +impl<'a, W, F> ser::Serializer for &'a mut Serializer +where + W: io::Write, + F: Formatter, +{ + type Ok = (); + type Error = Error; + + type SerializeSeq = Compound<'a, W, F>; + type SerializeTuple = Compound<'a, W, F>; + type SerializeTupleStruct = Compound<'a, W, F>; + type SerializeTupleVariant = Compound<'a, W, F>; + type SerializeMap = Compound<'a, W, F>; + type SerializeStruct = Compound<'a, W, F>; + type SerializeStructVariant = Compound<'a, W, F>; + + #[inline] + fn serialize_bool(self, value: bool) -> Result<()> { + self.formatter + .write_bool(&mut self.writer, value) + .map_err(Error::io) + } + + #[inline] + fn serialize_i8(self, value: i8) -> Result<()> { + self.formatter + .write_i8(&mut self.writer, value) + .map_err(Error::io) + } + + #[inline] + fn serialize_i16(self, value: i16) -> Result<()> { + self.formatter + .write_i16(&mut self.writer, value) + .map_err(Error::io) + } + + #[inline] + fn serialize_i32(self, value: i32) -> Result<()> { + self.formatter + .write_i32(&mut self.writer, value) + .map_err(Error::io) + } + + #[inline] + fn serialize_i64(self, value: i64) -> Result<()> { + self.formatter + .write_i64(&mut self.writer, value) + .map_err(Error::io) + } + + fn serialize_i128(self, value: i128) -> Result<()> { + self.formatter + .write_i128(&mut self.writer, value) + .map_err(Error::io) + } + + #[inline] + fn serialize_u8(self, value: u8) -> Result<()> { + self.formatter + .write_u8(&mut self.writer, value) + .map_err(Error::io) + } + + #[inline] + fn serialize_u16(self, value: u16) -> Result<()> { + self.formatter + .write_u16(&mut self.writer, value) + .map_err(Error::io) + } + + #[inline] + fn serialize_u32(self, value: u32) -> Result<()> { + self.formatter + .write_u32(&mut self.writer, value) + .map_err(Error::io) + } + + #[inline] + fn serialize_u64(self, value: u64) -> Result<()> { + self.formatter + .write_u64(&mut self.writer, value) + .map_err(Error::io) + } + + fn serialize_u128(self, value: u128) -> Result<()> { + self.formatter + .write_u128(&mut self.writer, value) + .map_err(Error::io) + } + + #[inline] + fn serialize_f32(self, value: f32) -> Result<()> { + match value.classify() { + FpCategory::Nan | FpCategory::Infinite => self + .formatter + .write_null(&mut self.writer) + .map_err(Error::io), + _ => self + .formatter + .write_f32(&mut self.writer, value) + .map_err(Error::io), + } + } + + #[inline] + fn serialize_f64(self, value: f64) -> Result<()> { + match value.classify() { + FpCategory::Nan | FpCategory::Infinite => self + .formatter + .write_null(&mut self.writer) + .map_err(Error::io), + _ => self + .formatter + .write_f64(&mut self.writer, value) + .map_err(Error::io), + } + } + + #[inline] + fn serialize_char(self, value: char) -> Result<()> { + // A char encoded as UTF-8 takes 4 bytes at most. + let mut buf = [0; 4]; + self.serialize_str(value.encode_utf8(&mut buf)) + } + + #[inline] + fn serialize_str(self, value: &str) -> Result<()> { + format_escaped_str(&mut self.writer, &mut self.formatter, value).map_err(Error::io) + } + + #[inline] + fn serialize_bytes(self, value: &[u8]) -> Result<()> { + self.formatter + .write_byte_array(&mut self.writer, value) + .map_err(Error::io) + } + + #[inline] + fn serialize_unit(self) -> Result<()> { + self.formatter + .write_null(&mut self.writer) + .map_err(Error::io) + } + + #[inline] + fn serialize_unit_struct(self, _name: &'static str) -> Result<()> { + self.serialize_unit() + } + + #[inline] + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result<()> { + self.serialize_str(variant) + } + + /// Serialize newtypes without an object wrapper. + #[inline] + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + #[inline] + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result<()> + where + T: ?Sized + Serialize, + { + tri!(self + .formatter + .begin_object(&mut self.writer) + .map_err(Error::io)); + tri!(self + .formatter + .begin_object_key(&mut self.writer, true) + .map_err(Error::io)); + tri!(self.serialize_str(variant)); + tri!(self + .formatter + .end_object_key(&mut self.writer) + .map_err(Error::io)); + tri!(self + .formatter + .begin_object_value(&mut self.writer) + .map_err(Error::io)); + tri!(value.serialize(&mut *self)); + tri!(self + .formatter + .end_object_value(&mut self.writer) + .map_err(Error::io)); + self.formatter + .end_object(&mut self.writer) + .map_err(Error::io) + } + + #[inline] + fn serialize_none(self) -> Result<()> { + self.serialize_unit() + } + + #[inline] + fn serialize_some(self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + #[inline] + fn serialize_seq(self, len: Option) -> Result { + tri!(self + .formatter + .begin_array(&mut self.writer) + .map_err(Error::io)); + if len == Some(0) { + tri!(self + .formatter + .end_array(&mut self.writer) + .map_err(Error::io)); + Ok(Compound::Map { + ser: self, + state: State::Empty, + }) + } else { + Ok(Compound::Map { + ser: self, + state: State::First, + }) + } + } + + #[inline] + fn serialize_tuple(self, len: usize) -> Result { + self.serialize_seq(Some(len)) + } + + #[inline] + fn serialize_tuple_struct( + self, + _name: &'static str, + len: usize, + ) -> Result { + self.serialize_seq(Some(len)) + } + + #[inline] + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + tri!(self + .formatter + .begin_object(&mut self.writer) + .map_err(Error::io)); + tri!(self + .formatter + .begin_object_key(&mut self.writer, true) + .map_err(Error::io)); + tri!(self.serialize_str(variant)); + tri!(self + .formatter + .end_object_key(&mut self.writer) + .map_err(Error::io)); + tri!(self + .formatter + .begin_object_value(&mut self.writer) + .map_err(Error::io)); + self.serialize_seq(Some(len)) + } + + #[inline] + fn serialize_map(self, len: Option) -> Result { + tri!(self + .formatter + .begin_object(&mut self.writer) + .map_err(Error::io)); + if len == Some(0) { + tri!(self + .formatter + .end_object(&mut self.writer) + .map_err(Error::io)); + Ok(Compound::Map { + ser: self, + state: State::Empty, + }) + } else { + Ok(Compound::Map { + ser: self, + state: State::First, + }) + } + } + + #[inline] + fn serialize_struct(self, name: &'static str, len: usize) -> Result { + match name { + #[cfg(feature = "arbitrary_precision")] + crate::number::TOKEN => Ok(Compound::Number { ser: self }), + #[cfg(feature = "raw_value")] + crate::raw::TOKEN => Ok(Compound::RawValue { ser: self }), + _ => self.serialize_map(Some(len)), + } + } + + #[inline] + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + tri!(self + .formatter + .begin_object(&mut self.writer) + .map_err(Error::io)); + tri!(self + .formatter + .begin_object_key(&mut self.writer, true) + .map_err(Error::io)); + tri!(self.serialize_str(variant)); + tri!(self + .formatter + .end_object_key(&mut self.writer) + .map_err(Error::io)); + tri!(self + .formatter + .begin_object_value(&mut self.writer) + .map_err(Error::io)); + self.serialize_map(Some(len)) + } + + fn collect_str(self, value: &T) -> Result<()> + where + T: ?Sized + Display, + { + use self::fmt::Write; + + struct Adapter<'ser, W: 'ser, F: 'ser> { + writer: &'ser mut W, + formatter: &'ser mut F, + error: Option, + } + + impl<'ser, W, F> Write for Adapter<'ser, W, F> + where + W: io::Write, + F: Formatter, + { + fn write_str(&mut self, s: &str) -> fmt::Result { + debug_assert!(self.error.is_none()); + match format_escaped_str_contents(self.writer, self.formatter, s) { + Ok(()) => Ok(()), + Err(err) => { + self.error = Some(err); + Err(fmt::Error) + } + } + } + } + + tri!(self + .formatter + .begin_string(&mut self.writer) + .map_err(Error::io)); + let mut adapter = Adapter { + writer: &mut self.writer, + formatter: &mut self.formatter, + error: None, + }; + match write!(adapter, "{}", value) { + Ok(()) => debug_assert!(adapter.error.is_none()), + Err(fmt::Error) => { + return Err(Error::io(adapter.error.expect("there should be an error"))); + } + } + self.formatter + .end_string(&mut self.writer) + .map_err(Error::io) + } +} + +// Not public API. Should be pub(crate). +#[doc(hidden)] +#[derive(Eq, PartialEq)] +pub enum State { + Empty, + First, + Rest, +} + +// Not public API. Should be pub(crate). +#[doc(hidden)] +pub enum Compound<'a, W: 'a, F: 'a> { + Map { + ser: &'a mut Serializer, + state: State, + }, + #[cfg(feature = "arbitrary_precision")] + Number { ser: &'a mut Serializer }, + #[cfg(feature = "raw_value")] + RawValue { ser: &'a mut Serializer }, +} + +impl<'a, W, F> ser::SerializeSeq for Compound<'a, W, F> +where + W: io::Write, + F: Formatter, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_element(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + match self { + Compound::Map { ser, state } => { + tri!(ser + .formatter + .begin_array_value(&mut ser.writer, *state == State::First) + .map_err(Error::io)); + *state = State::Rest; + tri!(value.serialize(&mut **ser)); + ser.formatter + .end_array_value(&mut ser.writer) + .map_err(Error::io) + } + #[cfg(feature = "arbitrary_precision")] + Compound::Number { .. } => unreachable!(), + #[cfg(feature = "raw_value")] + Compound::RawValue { .. } => unreachable!(), + } + } + + #[inline] + fn end(self) -> Result<()> { + match self { + Compound::Map { ser, state } => match state { + State::Empty => Ok(()), + _ => ser.formatter.end_array(&mut ser.writer).map_err(Error::io), + }, + #[cfg(feature = "arbitrary_precision")] + Compound::Number { .. } => unreachable!(), + #[cfg(feature = "raw_value")] + Compound::RawValue { .. } => unreachable!(), + } + } +} + +impl<'a, W, F> ser::SerializeTuple for Compound<'a, W, F> +where + W: io::Write, + F: Formatter, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_element(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + ser::SerializeSeq::serialize_element(self, value) + } + + #[inline] + fn end(self) -> Result<()> { + ser::SerializeSeq::end(self) + } +} + +impl<'a, W, F> ser::SerializeTupleStruct for Compound<'a, W, F> +where + W: io::Write, + F: Formatter, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_field(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + ser::SerializeSeq::serialize_element(self, value) + } + + #[inline] + fn end(self) -> Result<()> { + ser::SerializeSeq::end(self) + } +} + +impl<'a, W, F> ser::SerializeTupleVariant for Compound<'a, W, F> +where + W: io::Write, + F: Formatter, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_field(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + ser::SerializeSeq::serialize_element(self, value) + } + + #[inline] + fn end(self) -> Result<()> { + match self { + Compound::Map { ser, state } => { + match state { + State::Empty => {} + _ => tri!(ser.formatter.end_array(&mut ser.writer).map_err(Error::io)), + } + tri!(ser + .formatter + .end_object_value(&mut ser.writer) + .map_err(Error::io)); + ser.formatter.end_object(&mut ser.writer).map_err(Error::io) + } + #[cfg(feature = "arbitrary_precision")] + Compound::Number { .. } => unreachable!(), + #[cfg(feature = "raw_value")] + Compound::RawValue { .. } => unreachable!(), + } + } +} + +impl<'a, W, F> ser::SerializeMap for Compound<'a, W, F> +where + W: io::Write, + F: Formatter, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_key(&mut self, key: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + match self { + Compound::Map { ser, state } => { + tri!(ser + .formatter + .begin_object_key(&mut ser.writer, *state == State::First) + .map_err(Error::io)); + *state = State::Rest; + + tri!(key.serialize(MapKeySerializer { ser: *ser })); + + ser.formatter + .end_object_key(&mut ser.writer) + .map_err(Error::io) + } + #[cfg(feature = "arbitrary_precision")] + Compound::Number { .. } => unreachable!(), + #[cfg(feature = "raw_value")] + Compound::RawValue { .. } => unreachable!(), + } + } + + #[inline] + fn serialize_value(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + match self { + Compound::Map { ser, .. } => { + tri!(ser + .formatter + .begin_object_value(&mut ser.writer) + .map_err(Error::io)); + tri!(value.serialize(&mut **ser)); + ser.formatter + .end_object_value(&mut ser.writer) + .map_err(Error::io) + } + #[cfg(feature = "arbitrary_precision")] + Compound::Number { .. } => unreachable!(), + #[cfg(feature = "raw_value")] + Compound::RawValue { .. } => unreachable!(), + } + } + + #[inline] + fn end(self) -> Result<()> { + match self { + Compound::Map { ser, state } => match state { + State::Empty => Ok(()), + _ => ser.formatter.end_object(&mut ser.writer).map_err(Error::io), + }, + #[cfg(feature = "arbitrary_precision")] + Compound::Number { .. } => unreachable!(), + #[cfg(feature = "raw_value")] + Compound::RawValue { .. } => unreachable!(), + } + } +} + +impl<'a, W, F> ser::SerializeStruct for Compound<'a, W, F> +where + W: io::Write, + F: Formatter, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + match self { + Compound::Map { .. } => ser::SerializeMap::serialize_entry(self, key, value), + #[cfg(feature = "arbitrary_precision")] + Compound::Number { ser, .. } => { + if key == crate::number::TOKEN { + value.serialize(NumberStrEmitter(ser)) + } else { + Err(invalid_number()) + } + } + #[cfg(feature = "raw_value")] + Compound::RawValue { ser, .. } => { + if key == crate::raw::TOKEN { + value.serialize(RawValueStrEmitter(ser)) + } else { + Err(invalid_raw_value()) + } + } + } + } + + #[inline] + fn end(self) -> Result<()> { + match self { + Compound::Map { .. } => ser::SerializeMap::end(self), + #[cfg(feature = "arbitrary_precision")] + Compound::Number { .. } => Ok(()), + #[cfg(feature = "raw_value")] + Compound::RawValue { .. } => Ok(()), + } + } +} + +impl<'a, W, F> ser::SerializeStructVariant for Compound<'a, W, F> +where + W: io::Write, + F: Formatter, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + match *self { + Compound::Map { .. } => ser::SerializeStruct::serialize_field(self, key, value), + #[cfg(feature = "arbitrary_precision")] + Compound::Number { .. } => unreachable!(), + #[cfg(feature = "raw_value")] + Compound::RawValue { .. } => unreachable!(), + } + } + + #[inline] + fn end(self) -> Result<()> { + match self { + Compound::Map { ser, state } => { + match state { + State::Empty => {} + _ => tri!(ser.formatter.end_object(&mut ser.writer).map_err(Error::io)), + } + tri!(ser + .formatter + .end_object_value(&mut ser.writer) + .map_err(Error::io)); + ser.formatter.end_object(&mut ser.writer).map_err(Error::io) + } + #[cfg(feature = "arbitrary_precision")] + Compound::Number { .. } => unreachable!(), + #[cfg(feature = "raw_value")] + Compound::RawValue { .. } => unreachable!(), + } + } +} + +struct MapKeySerializer<'a, W: 'a, F: 'a> { + ser: &'a mut Serializer, +} + +#[cfg(feature = "arbitrary_precision")] +fn invalid_number() -> Error { + Error::syntax(ErrorCode::InvalidNumber, 0, 0) +} + +#[cfg(feature = "raw_value")] +fn invalid_raw_value() -> Error { + Error::syntax(ErrorCode::ExpectedSomeValue, 0, 0) +} + +fn key_must_be_a_string() -> Error { + Error::syntax(ErrorCode::KeyMustBeAString, 0, 0) +} + +fn float_key_must_be_finite() -> Error { + Error::syntax(ErrorCode::FloatKeyMustBeFinite, 0, 0) +} + +impl<'a, W, F> ser::Serializer for MapKeySerializer<'a, W, F> +where + W: io::Write, + F: Formatter, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_str(self, value: &str) -> Result<()> { + self.ser.serialize_str(value) + } + + #[inline] + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result<()> { + self.ser.serialize_str(variant) + } + + #[inline] + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + type SerializeSeq = Impossible<(), Error>; + type SerializeTuple = Impossible<(), Error>; + type SerializeTupleStruct = Impossible<(), Error>; + type SerializeTupleVariant = Impossible<(), Error>; + type SerializeMap = Impossible<(), Error>; + type SerializeStruct = Impossible<(), Error>; + type SerializeStructVariant = Impossible<(), Error>; + + fn serialize_bool(self, value: bool) -> Result<()> { + tri!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + tri!(self + .ser + .formatter + .write_bool(&mut self.ser.writer, value) + .map_err(Error::io)); + self.ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io) + } + + fn serialize_i8(self, value: i8) -> Result<()> { + tri!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + tri!(self + .ser + .formatter + .write_i8(&mut self.ser.writer, value) + .map_err(Error::io)); + self.ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io) + } + + fn serialize_i16(self, value: i16) -> Result<()> { + tri!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + tri!(self + .ser + .formatter + .write_i16(&mut self.ser.writer, value) + .map_err(Error::io)); + self.ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io) + } + + fn serialize_i32(self, value: i32) -> Result<()> { + tri!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + tri!(self + .ser + .formatter + .write_i32(&mut self.ser.writer, value) + .map_err(Error::io)); + self.ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io) + } + + fn serialize_i64(self, value: i64) -> Result<()> { + tri!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + tri!(self + .ser + .formatter + .write_i64(&mut self.ser.writer, value) + .map_err(Error::io)); + self.ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io) + } + + fn serialize_i128(self, value: i128) -> Result<()> { + tri!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + tri!(self + .ser + .formatter + .write_i128(&mut self.ser.writer, value) + .map_err(Error::io)); + self.ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io) + } + + fn serialize_u8(self, value: u8) -> Result<()> { + tri!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + tri!(self + .ser + .formatter + .write_u8(&mut self.ser.writer, value) + .map_err(Error::io)); + self.ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io) + } + + fn serialize_u16(self, value: u16) -> Result<()> { + tri!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + tri!(self + .ser + .formatter + .write_u16(&mut self.ser.writer, value) + .map_err(Error::io)); + self.ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io) + } + + fn serialize_u32(self, value: u32) -> Result<()> { + tri!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + tri!(self + .ser + .formatter + .write_u32(&mut self.ser.writer, value) + .map_err(Error::io)); + self.ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io) + } + + fn serialize_u64(self, value: u64) -> Result<()> { + tri!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + tri!(self + .ser + .formatter + .write_u64(&mut self.ser.writer, value) + .map_err(Error::io)); + self.ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io) + } + + fn serialize_u128(self, value: u128) -> Result<()> { + tri!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + tri!(self + .ser + .formatter + .write_u128(&mut self.ser.writer, value) + .map_err(Error::io)); + self.ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io) + } + + fn serialize_f32(self, value: f32) -> Result<()> { + if !value.is_finite() { + return Err(float_key_must_be_finite()); + } + + tri!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + tri!(self + .ser + .formatter + .write_f32(&mut self.ser.writer, value) + .map_err(Error::io)); + self.ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io) + } + + fn serialize_f64(self, value: f64) -> Result<()> { + if !value.is_finite() { + return Err(float_key_must_be_finite()); + } + + tri!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + tri!(self + .ser + .formatter + .write_f64(&mut self.ser.writer, value) + .map_err(Error::io)); + self.ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io) + } + + fn serialize_char(self, value: char) -> Result<()> { + self.ser.serialize_str(value.encode_utf8(&mut [0u8; 4])) + } + + fn serialize_bytes(self, _value: &[u8]) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_unit(self) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result<()> + where + T: ?Sized + Serialize, + { + Err(key_must_be_a_string()) + } + + fn serialize_none(self) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_some(self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + fn serialize_seq(self, _len: Option) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_tuple(self, _len: usize) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_map(self, _len: Option) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(key_must_be_a_string()) + } + + fn collect_str(self, value: &T) -> Result<()> + where + T: ?Sized + Display, + { + self.ser.collect_str(value) + } +} + +#[cfg(feature = "arbitrary_precision")] +struct NumberStrEmitter<'a, W: 'a + io::Write, F: 'a + Formatter>(&'a mut Serializer); + +#[cfg(feature = "arbitrary_precision")] +impl<'a, W: io::Write, F: Formatter> ser::Serializer for NumberStrEmitter<'a, W, F> { + type Ok = (); + type Error = Error; + + type SerializeSeq = Impossible<(), Error>; + type SerializeTuple = Impossible<(), Error>; + type SerializeTupleStruct = Impossible<(), Error>; + type SerializeTupleVariant = Impossible<(), Error>; + type SerializeMap = Impossible<(), Error>; + type SerializeStruct = Impossible<(), Error>; + type SerializeStructVariant = Impossible<(), Error>; + + fn serialize_bool(self, _v: bool) -> Result<()> { + Err(invalid_number()) + } + + fn serialize_i8(self, _v: i8) -> Result<()> { + Err(invalid_number()) + } + + fn serialize_i16(self, _v: i16) -> Result<()> { + Err(invalid_number()) + } + + fn serialize_i32(self, _v: i32) -> Result<()> { + Err(invalid_number()) + } + + fn serialize_i64(self, _v: i64) -> Result<()> { + Err(invalid_number()) + } + + fn serialize_i128(self, _v: i128) -> Result<()> { + Err(invalid_number()) + } + + fn serialize_u8(self, _v: u8) -> Result<()> { + Err(invalid_number()) + } + + fn serialize_u16(self, _v: u16) -> Result<()> { + Err(invalid_number()) + } + + fn serialize_u32(self, _v: u32) -> Result<()> { + Err(invalid_number()) + } + + fn serialize_u64(self, _v: u64) -> Result<()> { + Err(invalid_number()) + } + + fn serialize_u128(self, _v: u128) -> Result<()> { + Err(invalid_number()) + } + + fn serialize_f32(self, _v: f32) -> Result<()> { + Err(invalid_number()) + } + + fn serialize_f64(self, _v: f64) -> Result<()> { + Err(invalid_number()) + } + + fn serialize_char(self, _v: char) -> Result<()> { + Err(invalid_number()) + } + + fn serialize_str(self, value: &str) -> Result<()> { + let NumberStrEmitter(serializer) = self; + serializer + .formatter + .write_number_str(&mut serializer.writer, value) + .map_err(Error::io) + } + + fn serialize_bytes(self, _value: &[u8]) -> Result<()> { + Err(invalid_number()) + } + + fn serialize_none(self) -> Result<()> { + Err(invalid_number()) + } + + fn serialize_some(self, _value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + Err(invalid_number()) + } + + fn serialize_unit(self) -> Result<()> { + Err(invalid_number()) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result<()> { + Err(invalid_number()) + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + ) -> Result<()> { + Err(invalid_number()) + } + + fn serialize_newtype_struct(self, _name: &'static str, _value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + Err(invalid_number()) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result<()> + where + T: ?Sized + Serialize, + { + Err(invalid_number()) + } + + fn serialize_seq(self, _len: Option) -> Result { + Err(invalid_number()) + } + + fn serialize_tuple(self, _len: usize) -> Result { + Err(invalid_number()) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + Err(invalid_number()) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(invalid_number()) + } + + fn serialize_map(self, _len: Option) -> Result { + Err(invalid_number()) + } + + fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { + Err(invalid_number()) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(invalid_number()) + } +} + +#[cfg(feature = "raw_value")] +struct RawValueStrEmitter<'a, W: 'a + io::Write, F: 'a + Formatter>(&'a mut Serializer); + +#[cfg(feature = "raw_value")] +impl<'a, W: io::Write, F: Formatter> ser::Serializer for RawValueStrEmitter<'a, W, F> { + type Ok = (); + type Error = Error; + + type SerializeSeq = Impossible<(), Error>; + type SerializeTuple = Impossible<(), Error>; + type SerializeTupleStruct = Impossible<(), Error>; + type SerializeTupleVariant = Impossible<(), Error>; + type SerializeMap = Impossible<(), Error>; + type SerializeStruct = Impossible<(), Error>; + type SerializeStructVariant = Impossible<(), Error>; + + fn serialize_bool(self, _v: bool) -> Result<()> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_i8(self, _v: i8) -> Result<()> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_i16(self, _v: i16) -> Result<()> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_i32(self, _v: i32) -> Result<()> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_i64(self, _v: i64) -> Result<()> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_i128(self, _v: i128) -> Result<()> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_u8(self, _v: u8) -> Result<()> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_u16(self, _v: u16) -> Result<()> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_u32(self, _v: u32) -> Result<()> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_u64(self, _v: u64) -> Result<()> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_u128(self, _v: u128) -> Result<()> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_f32(self, _v: f32) -> Result<()> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_f64(self, _v: f64) -> Result<()> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_char(self, _v: char) -> Result<()> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_str(self, value: &str) -> Result<()> { + let RawValueStrEmitter(serializer) = self; + serializer + .formatter + .write_raw_fragment(&mut serializer.writer, value) + .map_err(Error::io) + } + + fn serialize_bytes(self, _value: &[u8]) -> Result<()> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_none(self) -> Result<()> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_some(self, _value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_unit(self) -> Result<()> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result<()> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + ) -> Result<()> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_newtype_struct(self, _name: &'static str, _value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result<()> + where + T: ?Sized + Serialize, + { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_seq(self, _len: Option) -> Result { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_tuple(self, _len: usize) -> Result { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_map(self, _len: Option) -> Result { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(ser::Error::custom("expected RawValue")) + } + + fn collect_str(self, value: &T) -> Result + where + T: ?Sized + Display, + { + self.serialize_str(&value.to_string()) + } +} + +/// Represents a character escape code in a type-safe manner. +pub enum CharEscape { + /// An escaped quote `"` + Quote, + /// An escaped reverse solidus `\` + ReverseSolidus, + /// An escaped solidus `/` + Solidus, + /// An escaped backspace character (usually escaped as `\b`) + Backspace, + /// An escaped form feed character (usually escaped as `\f`) + FormFeed, + /// An escaped line feed character (usually escaped as `\n`) + LineFeed, + /// An escaped carriage return character (usually escaped as `\r`) + CarriageReturn, + /// An escaped tab character (usually escaped as `\t`) + Tab, + /// An escaped ASCII plane control character (usually escaped as + /// `\u00XX` where `XX` are two hex characters) + AsciiControl(u8), +} + +/// This trait abstracts away serializing the JSON control characters, which allows the user to +/// optionally pretty print the JSON output. +pub trait Formatter { + /// Writes a `null` value to the specified writer. + #[inline] + fn write_null(&mut self, writer: &mut W) -> io::Result<()> + where + W: ?Sized + io::Write, + { + writer.write_all(b"null") + } + + /// Writes a `true` or `false` value to the specified writer. + #[inline] + fn write_bool(&mut self, writer: &mut W, value: bool) -> io::Result<()> + where + W: ?Sized + io::Write, + { + let s = if value { + b"true" as &[u8] + } else { + b"false" as &[u8] + }; + writer.write_all(s) + } + + /// Writes an integer value like `-123` to the specified writer. + #[inline] + fn write_i8(&mut self, writer: &mut W, value: i8) -> io::Result<()> + where + W: ?Sized + io::Write, + { + let mut buffer = itoa::Buffer::new(); + let s = buffer.format(value); + writer.write_all(s.as_bytes()) + } + + /// Writes an integer value like `-123` to the specified writer. + #[inline] + fn write_i16(&mut self, writer: &mut W, value: i16) -> io::Result<()> + where + W: ?Sized + io::Write, + { + let mut buffer = itoa::Buffer::new(); + let s = buffer.format(value); + writer.write_all(s.as_bytes()) + } + + /// Writes an integer value like `-123` to the specified writer. + #[inline] + fn write_i32(&mut self, writer: &mut W, value: i32) -> io::Result<()> + where + W: ?Sized + io::Write, + { + let mut buffer = itoa::Buffer::new(); + let s = buffer.format(value); + writer.write_all(s.as_bytes()) + } + + /// Writes an integer value like `-123` to the specified writer. + #[inline] + fn write_i64(&mut self, writer: &mut W, value: i64) -> io::Result<()> + where + W: ?Sized + io::Write, + { + let mut buffer = itoa::Buffer::new(); + let s = buffer.format(value); + writer.write_all(s.as_bytes()) + } + + /// Writes an integer value like `-123` to the specified writer. + #[inline] + fn write_i128(&mut self, writer: &mut W, value: i128) -> io::Result<()> + where + W: ?Sized + io::Write, + { + let mut buffer = itoa::Buffer::new(); + let s = buffer.format(value); + writer.write_all(s.as_bytes()) + } + + /// Writes an integer value like `123` to the specified writer. + #[inline] + fn write_u8(&mut self, writer: &mut W, value: u8) -> io::Result<()> + where + W: ?Sized + io::Write, + { + let mut buffer = itoa::Buffer::new(); + let s = buffer.format(value); + writer.write_all(s.as_bytes()) + } + + /// Writes an integer value like `123` to the specified writer. + #[inline] + fn write_u16(&mut self, writer: &mut W, value: u16) -> io::Result<()> + where + W: ?Sized + io::Write, + { + let mut buffer = itoa::Buffer::new(); + let s = buffer.format(value); + writer.write_all(s.as_bytes()) + } + + /// Writes an integer value like `123` to the specified writer. + #[inline] + fn write_u32(&mut self, writer: &mut W, value: u32) -> io::Result<()> + where + W: ?Sized + io::Write, + { + let mut buffer = itoa::Buffer::new(); + let s = buffer.format(value); + writer.write_all(s.as_bytes()) + } + + /// Writes an integer value like `123` to the specified writer. + #[inline] + fn write_u64(&mut self, writer: &mut W, value: u64) -> io::Result<()> + where + W: ?Sized + io::Write, + { + let mut buffer = itoa::Buffer::new(); + let s = buffer.format(value); + writer.write_all(s.as_bytes()) + } + + /// Writes an integer value like `123` to the specified writer. + #[inline] + fn write_u128(&mut self, writer: &mut W, value: u128) -> io::Result<()> + where + W: ?Sized + io::Write, + { + let mut buffer = itoa::Buffer::new(); + let s = buffer.format(value); + writer.write_all(s.as_bytes()) + } + + /// Writes a floating point value like `-31.26e+12` to the specified writer. + /// + /// # Special cases + /// + /// This function **does not** check for NaN or infinity. If the input + /// number is not a finite float, the printed representation will be some + /// correctly formatted but unspecified numerical value. + /// + /// Please check [`is_finite`] yourself before calling this function, or + /// check [`is_nan`] and [`is_infinite`] and handle those cases yourself + /// with a different `Formatter` method. + /// + /// [`is_finite`]: f32::is_finite + /// [`is_nan`]: f32::is_nan + /// [`is_infinite`]: f32::is_infinite + #[inline] + fn write_f32(&mut self, writer: &mut W, value: f32) -> io::Result<()> + where + W: ?Sized + io::Write, + { + let mut buffer = zmij::Buffer::new(); + let s = buffer.format_finite(value); + writer.write_all(s.as_bytes()) + } + + /// Writes a floating point value like `-31.26e+12` to the specified writer. + /// + /// # Special cases + /// + /// This function **does not** check for NaN or infinity. If the input + /// number is not a finite float, the printed representation will be some + /// correctly formatted but unspecified numerical value. + /// + /// Please check [`is_finite`] yourself before calling this function, or + /// check [`is_nan`] and [`is_infinite`] and handle those cases yourself + /// with a different `Formatter` method. + /// + /// [`is_finite`]: f64::is_finite + /// [`is_nan`]: f64::is_nan + /// [`is_infinite`]: f64::is_infinite + #[inline] + fn write_f64(&mut self, writer: &mut W, value: f64) -> io::Result<()> + where + W: ?Sized + io::Write, + { + let mut buffer = zmij::Buffer::new(); + let s = buffer.format_finite(value); + writer.write_all(s.as_bytes()) + } + + /// Writes a number that has already been rendered to a string. + #[inline] + fn write_number_str(&mut self, writer: &mut W, value: &str) -> io::Result<()> + where + W: ?Sized + io::Write, + { + writer.write_all(value.as_bytes()) + } + + /// Called before each series of `write_string_fragment` and + /// `write_char_escape`. Writes a `"` to the specified writer. + #[inline] + fn begin_string(&mut self, writer: &mut W) -> io::Result<()> + where + W: ?Sized + io::Write, + { + writer.write_all(b"\"") + } + + /// Called after each series of `write_string_fragment` and + /// `write_char_escape`. Writes a `"` to the specified writer. + #[inline] + fn end_string(&mut self, writer: &mut W) -> io::Result<()> + where + W: ?Sized + io::Write, + { + writer.write_all(b"\"") + } + + /// Writes a string fragment that doesn't need any escaping to the + /// specified writer. + #[inline] + fn write_string_fragment(&mut self, writer: &mut W, fragment: &str) -> io::Result<()> + where + W: ?Sized + io::Write, + { + writer.write_all(fragment.as_bytes()) + } + + /// Writes a character escape code to the specified writer. + #[inline] + fn write_char_escape(&mut self, writer: &mut W, char_escape: CharEscape) -> io::Result<()> + where + W: ?Sized + io::Write, + { + use self::CharEscape::*; + + let escape_char = match char_escape { + Quote => b'"', + ReverseSolidus => b'\\', + Solidus => b'/', + Backspace => b'b', + FormFeed => b'f', + LineFeed => b'n', + CarriageReturn => b'r', + Tab => b't', + AsciiControl(_) => b'u', + }; + + match char_escape { + AsciiControl(byte) => { + static HEX_DIGITS: [u8; 16] = *b"0123456789abcdef"; + let bytes = &[ + b'\\', + escape_char, + b'0', + b'0', + HEX_DIGITS[(byte >> 4) as usize], + HEX_DIGITS[(byte & 0xF) as usize], + ]; + writer.write_all(bytes) + } + _ => writer.write_all(&[b'\\', escape_char]), + } + } + + /// Writes the representation of a byte array. Formatters can choose whether + /// to represent bytes as a JSON array of integers (the default), or some + /// JSON string encoding like hex or base64. + fn write_byte_array(&mut self, writer: &mut W, value: &[u8]) -> io::Result<()> + where + W: ?Sized + io::Write, + { + tri!(self.begin_array(writer)); + let mut first = true; + for byte in value { + tri!(self.begin_array_value(writer, first)); + tri!(self.write_u8(writer, *byte)); + tri!(self.end_array_value(writer)); + first = false; + } + self.end_array(writer) + } + + /// Called before every array. Writes a `[` to the specified + /// writer. + #[inline] + fn begin_array(&mut self, writer: &mut W) -> io::Result<()> + where + W: ?Sized + io::Write, + { + writer.write_all(b"[") + } + + /// Called after every array. Writes a `]` to the specified + /// writer. + #[inline] + fn end_array(&mut self, writer: &mut W) -> io::Result<()> + where + W: ?Sized + io::Write, + { + writer.write_all(b"]") + } + + /// Called before every array value. Writes a `,` if needed to + /// the specified writer. + #[inline] + fn begin_array_value(&mut self, writer: &mut W, first: bool) -> io::Result<()> + where + W: ?Sized + io::Write, + { + if first { + Ok(()) + } else { + writer.write_all(b",") + } + } + + /// Called after every array value. + #[inline] + fn end_array_value(&mut self, _writer: &mut W) -> io::Result<()> + where + W: ?Sized + io::Write, + { + Ok(()) + } + + /// Called before every object. Writes a `{` to the specified + /// writer. + #[inline] + fn begin_object(&mut self, writer: &mut W) -> io::Result<()> + where + W: ?Sized + io::Write, + { + writer.write_all(b"{") + } + + /// Called after every object. Writes a `}` to the specified + /// writer. + #[inline] + fn end_object(&mut self, writer: &mut W) -> io::Result<()> + where + W: ?Sized + io::Write, + { + writer.write_all(b"}") + } + + /// Called before every object key. + #[inline] + fn begin_object_key(&mut self, writer: &mut W, first: bool) -> io::Result<()> + where + W: ?Sized + io::Write, + { + if first { + Ok(()) + } else { + writer.write_all(b",") + } + } + + /// Called after every object key. A `:` should be written to the + /// specified writer by either this method or + /// `begin_object_value`. + #[inline] + fn end_object_key(&mut self, _writer: &mut W) -> io::Result<()> + where + W: ?Sized + io::Write, + { + Ok(()) + } + + /// Called before every object value. A `:` should be written to + /// the specified writer by either this method or + /// `end_object_key`. + #[inline] + fn begin_object_value(&mut self, writer: &mut W) -> io::Result<()> + where + W: ?Sized + io::Write, + { + writer.write_all(b":") + } + + /// Called after every object value. + #[inline] + fn end_object_value(&mut self, _writer: &mut W) -> io::Result<()> + where + W: ?Sized + io::Write, + { + Ok(()) + } + + /// Writes a raw JSON fragment that doesn't need any escaping to the + /// specified writer. + #[inline] + fn write_raw_fragment(&mut self, writer: &mut W, fragment: &str) -> io::Result<()> + where + W: ?Sized + io::Write, + { + writer.write_all(fragment.as_bytes()) + } +} + +/// This structure compacts a JSON value with no extra whitespace. +#[derive(Clone, Debug, Default)] +pub struct CompactFormatter; + +impl Formatter for CompactFormatter {} + +/// This structure pretty prints a JSON value to make it human readable. +#[derive(Clone, Debug)] +pub struct PrettyFormatter<'a> { + current_indent: usize, + has_value: bool, + indent: &'a [u8], +} + +impl<'a> PrettyFormatter<'a> { + /// Construct a pretty printer formatter that defaults to using two spaces for indentation. + pub fn new() -> Self { + PrettyFormatter::with_indent(b" ") + } + + /// Construct a pretty printer formatter that uses the `indent` string for indentation. + pub fn with_indent(indent: &'a [u8]) -> Self { + PrettyFormatter { + current_indent: 0, + has_value: false, + indent, + } + } +} + +impl<'a> Default for PrettyFormatter<'a> { + fn default() -> Self { + PrettyFormatter::new() + } +} + +impl<'a> Formatter for PrettyFormatter<'a> { + #[inline] + fn begin_array(&mut self, writer: &mut W) -> io::Result<()> + where + W: ?Sized + io::Write, + { + self.current_indent += 1; + self.has_value = false; + writer.write_all(b"[") + } + + #[inline] + fn end_array(&mut self, writer: &mut W) -> io::Result<()> + where + W: ?Sized + io::Write, + { + self.current_indent -= 1; + + if self.has_value { + tri!(writer.write_all(b"\n")); + tri!(indent(writer, self.current_indent, self.indent)); + } + + writer.write_all(b"]") + } + + #[inline] + fn begin_array_value(&mut self, writer: &mut W, first: bool) -> io::Result<()> + where + W: ?Sized + io::Write, + { + tri!(writer.write_all(if first { b"\n" } else { b",\n" })); + indent(writer, self.current_indent, self.indent) + } + + #[inline] + fn end_array_value(&mut self, _writer: &mut W) -> io::Result<()> + where + W: ?Sized + io::Write, + { + self.has_value = true; + Ok(()) + } + + #[inline] + fn begin_object(&mut self, writer: &mut W) -> io::Result<()> + where + W: ?Sized + io::Write, + { + self.current_indent += 1; + self.has_value = false; + writer.write_all(b"{") + } + + #[inline] + fn end_object(&mut self, writer: &mut W) -> io::Result<()> + where + W: ?Sized + io::Write, + { + self.current_indent -= 1; + + if self.has_value { + tri!(writer.write_all(b"\n")); + tri!(indent(writer, self.current_indent, self.indent)); + } + + writer.write_all(b"}") + } + + #[inline] + fn begin_object_key(&mut self, writer: &mut W, first: bool) -> io::Result<()> + where + W: ?Sized + io::Write, + { + tri!(writer.write_all(if first { b"\n" } else { b",\n" })); + indent(writer, self.current_indent, self.indent) + } + + #[inline] + fn begin_object_value(&mut self, writer: &mut W) -> io::Result<()> + where + W: ?Sized + io::Write, + { + writer.write_all(b": ") + } + + #[inline] + fn end_object_value(&mut self, _writer: &mut W) -> io::Result<()> + where + W: ?Sized + io::Write, + { + self.has_value = true; + Ok(()) + } +} + +fn format_escaped_str(writer: &mut W, formatter: &mut F, value: &str) -> io::Result<()> +where + W: ?Sized + io::Write, + F: ?Sized + Formatter, +{ + tri!(formatter.begin_string(writer)); + tri!(format_escaped_str_contents(writer, formatter, value)); + formatter.end_string(writer) +} + +fn format_escaped_str_contents( + writer: &mut W, + formatter: &mut F, + value: &str, +) -> io::Result<()> +where + W: ?Sized + io::Write, + F: ?Sized + Formatter, +{ + let mut bytes = value.as_bytes(); + + let mut i = 0; + while i < bytes.len() { + let (string_run, rest) = bytes.split_at(i); + let (&byte, rest) = rest.split_first().unwrap(); + + let escape = ESCAPE[byte as usize]; + + i += 1; + if escape == 0 { + continue; + } + + bytes = rest; + i = 0; + + // Safety: string_run is a valid utf8 string, since we only split on ascii sequences + let string_run = unsafe { str::from_utf8_unchecked(string_run) }; + if !string_run.is_empty() { + tri!(formatter.write_string_fragment(writer, string_run)); + } + + let char_escape = match escape { + self::BB => CharEscape::Backspace, + self::TT => CharEscape::Tab, + self::NN => CharEscape::LineFeed, + self::FF => CharEscape::FormFeed, + self::RR => CharEscape::CarriageReturn, + self::QU => CharEscape::Quote, + self::BS => CharEscape::ReverseSolidus, + self::UU => CharEscape::AsciiControl(byte), + // Safety: the escape table does not contain any other type of character. + _ => unsafe { hint::unreachable_unchecked() }, + }; + tri!(formatter.write_char_escape(writer, char_escape)); + } + + // Safety: bytes is a valid utf8 string, since we only split on ascii sequences + let string_run = unsafe { str::from_utf8_unchecked(bytes) }; + if string_run.is_empty() { + return Ok(()); + } + + formatter.write_string_fragment(writer, string_run) +} + +const BB: u8 = b'b'; // \x08 +const TT: u8 = b't'; // \x09 +const NN: u8 = b'n'; // \x0A +const FF: u8 = b'f'; // \x0C +const RR: u8 = b'r'; // \x0D +const QU: u8 = b'"'; // \x22 +const BS: u8 = b'\\'; // \x5C +const UU: u8 = b'u'; // \x00...\x1F except the ones above +const __: u8 = 0; + +// Lookup table of escape sequences. A value of b'x' at index i means that byte +// i is escaped as "\x" in JSON. A value of 0 means that byte i is not escaped. +static ESCAPE: [u8; 256] = [ + // 1 2 3 4 5 6 7 8 9 A B C D E F + UU, UU, UU, UU, UU, UU, UU, UU, BB, TT, NN, UU, FF, RR, UU, UU, // 0 + UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, // 1 + __, __, QU, __, __, __, __, __, __, __, __, __, __, __, __, __, // 2 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 3 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 4 + __, __, __, __, __, __, __, __, __, __, __, __, BS, __, __, __, // 5 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 6 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 7 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 8 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 9 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // A + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // B + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // C + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // D + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // E + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // F +]; + +/// Serialize the given data structure as JSON into the I/O stream. +/// +/// Serialization guarantees it only feeds valid UTF-8 sequences to the writer. +/// +/// # Errors +/// +/// Serialization can fail if `T`'s implementation of `Serialize` decides to +/// fail, or if `T` contains a map with non-string keys. +#[inline] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +pub fn to_writer(writer: W, value: &T) -> Result<()> +where + W: io::Write, + T: ?Sized + Serialize, +{ + let mut ser = Serializer::new(writer); + value.serialize(&mut ser) +} + +/// Serialize the given data structure as pretty-printed JSON into the I/O +/// stream. +/// +/// Serialization guarantees it only feeds valid UTF-8 sequences to the writer. +/// +/// # Errors +/// +/// Serialization can fail if `T`'s implementation of `Serialize` decides to +/// fail, or if `T` contains a map with non-string keys. +#[inline] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +pub fn to_writer_pretty(writer: W, value: &T) -> Result<()> +where + W: io::Write, + T: ?Sized + Serialize, +{ + let mut ser = Serializer::pretty(writer); + value.serialize(&mut ser) +} + +/// Serialize the given data structure as a JSON byte vector. +/// +/// # Errors +/// +/// Serialization can fail if `T`'s implementation of `Serialize` decides to +/// fail, or if `T` contains a map with non-string keys. +#[inline] +pub fn to_vec(value: &T) -> Result> +where + T: ?Sized + Serialize, +{ + let mut writer = Vec::with_capacity(128); + tri!(to_writer(&mut writer, value)); + Ok(writer) +} + +/// Serialize the given data structure as a pretty-printed JSON byte vector. +/// +/// # Errors +/// +/// Serialization can fail if `T`'s implementation of `Serialize` decides to +/// fail, or if `T` contains a map with non-string keys. +#[inline] +pub fn to_vec_pretty(value: &T) -> Result> +where + T: ?Sized + Serialize, +{ + let mut writer = Vec::with_capacity(128); + tri!(to_writer_pretty(&mut writer, value)); + Ok(writer) +} + +/// Serialize the given data structure as a String of JSON. +/// +/// # Errors +/// +/// Serialization can fail if `T`'s implementation of `Serialize` decides to +/// fail, or if `T` contains a map with non-string keys. +#[inline] +pub fn to_string(value: &T) -> Result +where + T: ?Sized + Serialize, +{ + let vec = tri!(to_vec(value)); + let string = unsafe { + // We do not emit invalid UTF-8. + String::from_utf8_unchecked(vec) + }; + Ok(string) +} + +/// Serialize the given data structure as a pretty-printed String of JSON. +/// +/// # Errors +/// +/// Serialization can fail if `T`'s implementation of `Serialize` decides to +/// fail, or if `T` contains a map with non-string keys. +#[inline] +pub fn to_string_pretty(value: &T) -> Result +where + T: ?Sized + Serialize, +{ + let vec = tri!(to_vec_pretty(value)); + let string = unsafe { + // We do not emit invalid UTF-8. + String::from_utf8_unchecked(vec) + }; + Ok(string) +} + +fn indent(wr: &mut W, n: usize, s: &[u8]) -> io::Result<()> +where + W: ?Sized + io::Write, +{ + for _ in 0..n { + tri!(wr.write_all(s)); + } + + Ok(()) +} diff --git a/third_party/crates/serde_json-1.0.151/src/value/de.rs b/third_party/crates/serde_json-1.0.151/src/value/de.rs new file mode 100644 index 0000000..9c3b35b --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/value/de.rs @@ -0,0 +1,1507 @@ +use crate::error::{Error, ErrorCode}; +use crate::map::Map; +use crate::number::Number; +use crate::value::Value; +use alloc::borrow::{Cow, ToOwned}; +use alloc::string::String; +#[cfg(feature = "raw_value")] +use alloc::string::ToString; +use alloc::vec::{self, Vec}; +use core::fmt; +use core::slice; +use core::str::FromStr; +use serde::de::{ + self, Deserialize, DeserializeSeed, Deserializer as _, EnumAccess, Expected, IntoDeserializer, + MapAccess, SeqAccess, Unexpected, VariantAccess, Visitor, +}; +use serde::forward_to_deserialize_any; + +#[cfg(feature = "arbitrary_precision")] +use crate::number::NumberFromString; + +impl<'de> Deserialize<'de> for Value { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + struct ValueVisitor; + + impl<'de> Visitor<'de> for ValueVisitor { + type Value = Value; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("any valid JSON value") + } + + #[inline] + fn visit_bool(self, value: bool) -> Result { + Ok(Value::Bool(value)) + } + + #[inline] + fn visit_i64(self, value: i64) -> Result { + Ok(Value::Number(value.into())) + } + + fn visit_i128(self, value: i128) -> Result + where + E: serde::de::Error, + { + let de = serde::de::value::I128Deserializer::new(value); + Number::deserialize(de).map(Value::Number) + } + + #[inline] + fn visit_u64(self, value: u64) -> Result { + Ok(Value::Number(value.into())) + } + + fn visit_u128(self, value: u128) -> Result + where + E: serde::de::Error, + { + let de = serde::de::value::U128Deserializer::new(value); + Number::deserialize(de).map(Value::Number) + } + + #[inline] + fn visit_f64(self, value: f64) -> Result { + Ok(Number::from_f64(value).map_or(Value::Null, Value::Number)) + } + + #[cfg(any(feature = "std", feature = "alloc"))] + #[inline] + fn visit_str(self, value: &str) -> Result + where + E: serde::de::Error, + { + self.visit_string(String::from(value)) + } + + #[cfg(any(feature = "std", feature = "alloc"))] + #[inline] + fn visit_string(self, value: String) -> Result { + Ok(Value::String(value)) + } + + #[inline] + fn visit_none(self) -> Result { + Ok(Value::Null) + } + + #[inline] + fn visit_some(self, deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + Deserialize::deserialize(deserializer) + } + + #[inline] + fn visit_unit(self) -> Result { + Ok(Value::Null) + } + + #[inline] + fn visit_seq(self, mut visitor: V) -> Result + where + V: SeqAccess<'de>, + { + let mut vec = Vec::new(); + + while let Some(elem) = tri!(visitor.next_element()) { + vec.push(elem); + } + + Ok(Value::Array(vec)) + } + + #[cfg(any(feature = "std", feature = "alloc"))] + fn visit_map(self, mut visitor: V) -> Result + where + V: MapAccess<'de>, + { + match tri!(visitor.next_key_seed(KeyClassifier)) { + #[cfg(feature = "arbitrary_precision")] + Some(KeyClass::Number) => { + let number: NumberFromString = tri!(visitor.next_value()); + Ok(Value::Number(number.value)) + } + #[cfg(feature = "raw_value")] + Some(KeyClass::RawValue) => { + let value = tri!(visitor.next_value_seed(crate::raw::BoxedFromString)); + crate::from_str(value.get()).map_err(de::Error::custom) + } + Some(KeyClass::Map(first_key)) => { + let mut values = Map::new(); + + values.insert(first_key, tri!(visitor.next_value())); + while let Some((key, value)) = tri!(visitor.next_entry()) { + values.insert(key, value); + } + + Ok(Value::Object(values)) + } + None => Ok(Value::Object(Map::new())), + } + } + } + + deserializer.deserialize_any(ValueVisitor) + } +} + +impl FromStr for Value { + type Err = Error; + fn from_str(s: &str) -> Result { + crate::from_str(s) + } +} + +impl FromStr for Map { + type Err = Error; + fn from_str(s: &str) -> Result { + crate::from_str(s) + } +} + +macro_rules! deserialize_number { + ($method:ident) => { + #[cfg(not(feature = "arbitrary_precision"))] + fn $method(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Number(n) => n.deserialize_any(visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + #[cfg(feature = "arbitrary_precision")] + fn $method(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Number(n) => n.$method(visitor), + _ => self.deserialize_any(visitor), + } + } + }; +} + +fn visit_array<'de, V>(array: Vec, visitor: V) -> Result +where + V: Visitor<'de>, +{ + let len = array.len(); + let mut deserializer = SeqDeserializer::new(array); + let seq = tri!(visitor.visit_seq(&mut deserializer)); + let remaining = deserializer.iter.len(); + if remaining == 0 { + Ok(seq) + } else { + Err(serde::de::Error::invalid_length( + len, + &"fewer elements in array", + )) + } +} + +impl<'de> serde::Deserializer<'de> for Map { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let len = self.len(); + let mut deserializer = MapDeserializer::new(self); + let map = tri!(visitor.visit_map(&mut deserializer)); + let remaining = deserializer.iter.len(); + if remaining == 0 { + Ok(map) + } else { + Err(serde::de::Error::invalid_length( + len, + &"fewer elements in map", + )) + } + } + + fn deserialize_enum( + self, + _name: &'static str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + let mut iter = self.into_iter(); + let (variant, value) = match iter.next() { + Some(v) => v, + None => { + return Err(serde::de::Error::invalid_value( + Unexpected::Map, + &"map with a single key", + )); + } + }; + // enums are encoded in json as maps with a single key:value pair + if iter.next().is_some() { + return Err(serde::de::Error::invalid_value( + Unexpected::Map, + &"map with a single key", + )); + } + + visitor.visit_enum(EnumDeserializer { + variant, + value: Some(value), + }) + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + drop(self); + visitor.visit_unit() + } + + 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 + } +} + +impl<'de> serde::Deserializer<'de> for Value { + type Error = Error; + + #[inline] + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Null => visitor.visit_unit(), + Value::Bool(v) => visitor.visit_bool(v), + Value::Number(n) => n.deserialize_any(visitor), + #[cfg(any(feature = "std", feature = "alloc"))] + Value::String(v) => visitor.visit_string(v), + #[cfg(not(any(feature = "std", feature = "alloc")))] + Value::String(_) => unreachable!(), + Value::Array(v) => visit_array(v, visitor), + Value::Object(v) => v.deserialize_any(visitor), + } + } + + deserialize_number!(deserialize_i8); + deserialize_number!(deserialize_i16); + deserialize_number!(deserialize_i32); + deserialize_number!(deserialize_i64); + deserialize_number!(deserialize_i128); + deserialize_number!(deserialize_u8); + deserialize_number!(deserialize_u16); + deserialize_number!(deserialize_u32); + deserialize_number!(deserialize_u64); + deserialize_number!(deserialize_u128); + deserialize_number!(deserialize_f32); + deserialize_number!(deserialize_f64); + + #[inline] + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Null => visitor.visit_none(), + _ => visitor.visit_some(self), + } + } + + #[inline] + fn deserialize_enum( + self, + name: &'static str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Object(value) => value.deserialize_enum(name, variants, visitor), + Value::String(variant) => visitor.visit_enum(EnumDeserializer { + variant, + value: None, + }), + other => Err(serde::de::Error::invalid_type( + other.unexpected(), + &"string or map", + )), + } + } + + #[inline] + fn deserialize_newtype_struct( + self, + name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + #[cfg(feature = "raw_value")] + { + if name == crate::raw::TOKEN { + return visitor.visit_map(crate::raw::OwnedRawDeserializer { + raw_value: Some(self.to_string()), + }); + } + } + + let _ = name; + visitor.visit_newtype_struct(self) + } + + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Bool(v) => visitor.visit_bool(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_char(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_string(visitor) + } + + fn deserialize_str(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_string(visitor) + } + + fn deserialize_string(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + #[cfg(any(feature = "std", feature = "alloc"))] + Value::String(v) => visitor.visit_string(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_bytes(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_byte_buf(visitor) + } + + fn deserialize_byte_buf(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + #[cfg(any(feature = "std", feature = "alloc"))] + Value::String(v) => visitor.visit_string(v), + Value::Array(v) => visit_array(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_unit(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Null => visitor.visit_unit(), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_unit_struct(self, _name: &'static str, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_unit(visitor) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Array(v) => visit_array(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_tuple(self, _len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_map(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Object(v) => v.deserialize_any(visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_struct( + self, + _name: &'static str, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Array(v) => visit_array(v, visitor), + Value::Object(v) => v.deserialize_any(visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_identifier(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_string(visitor) + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + drop(self); + visitor.visit_unit() + } +} + +struct EnumDeserializer { + variant: String, + value: Option, +} + +impl<'de> EnumAccess<'de> for EnumDeserializer { + type Error = Error; + type Variant = VariantDeserializer; + + fn variant_seed(self, seed: V) -> Result<(V::Value, VariantDeserializer), Error> + where + V: DeserializeSeed<'de>, + { + let variant = self.variant.into_deserializer(); + let visitor = VariantDeserializer { value: self.value }; + seed.deserialize(variant).map(|v| (v, visitor)) + } +} + +impl<'de> IntoDeserializer<'de, Error> for Value { + type Deserializer = Self; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} + +impl<'de> IntoDeserializer<'de, Error> for &'de Value { + type Deserializer = Self; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} + +struct VariantDeserializer { + value: Option, +} + +impl<'de> VariantAccess<'de> for VariantDeserializer { + type Error = Error; + + fn unit_variant(self) -> Result<(), Error> { + match self.value { + Some(value) => Deserialize::deserialize(value), + None => Ok(()), + } + } + + fn newtype_variant_seed(self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + match self.value { + Some(value) => seed.deserialize(value), + None => Err(serde::de::Error::invalid_type( + Unexpected::UnitVariant, + &"newtype variant", + )), + } + } + + fn tuple_variant(self, _len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.value { + Some(Value::Array(v)) => { + if v.is_empty() { + visitor.visit_unit() + } else { + visit_array(v, visitor) + } + } + Some(other) => Err(serde::de::Error::invalid_type( + other.unexpected(), + &"tuple variant", + )), + None => Err(serde::de::Error::invalid_type( + Unexpected::UnitVariant, + &"tuple variant", + )), + } + } + + fn struct_variant( + self, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match self.value { + Some(Value::Object(v)) => v.deserialize_any(visitor), + Some(other) => Err(serde::de::Error::invalid_type( + other.unexpected(), + &"struct variant", + )), + None => Err(serde::de::Error::invalid_type( + Unexpected::UnitVariant, + &"struct variant", + )), + } + } +} + +struct SeqDeserializer { + iter: vec::IntoIter, +} + +impl SeqDeserializer { + fn new(vec: Vec) -> Self { + SeqDeserializer { + iter: vec.into_iter(), + } + } +} + +impl<'de> SeqAccess<'de> for SeqDeserializer { + type Error = Error; + + fn next_element_seed(&mut self, seed: T) -> Result, Error> + where + T: DeserializeSeed<'de>, + { + match self.iter.next() { + Some(value) => seed.deserialize(value).map(Some), + None => Ok(None), + } + } + + fn size_hint(&self) -> Option { + match self.iter.size_hint() { + (lower, Some(upper)) if lower == upper => Some(upper), + _ => None, + } + } +} + +struct MapDeserializer { + iter: as IntoIterator>::IntoIter, + value: Option, +} + +impl MapDeserializer { + fn new(map: Map) -> Self { + MapDeserializer { + iter: map.into_iter(), + value: None, + } + } +} + +impl<'de> MapAccess<'de> for MapDeserializer { + type Error = Error; + + fn next_key_seed(&mut self, seed: T) -> Result, Error> + where + T: DeserializeSeed<'de>, + { + match self.iter.next() { + Some((key, value)) => { + self.value = Some(value); + let key_de = MapKeyDeserializer { + key: Cow::Owned(key), + }; + seed.deserialize(key_de).map(Some) + } + None => Ok(None), + } + } + + fn next_value_seed(&mut self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + match self.value.take() { + Some(value) => seed.deserialize(value), + None => Err(serde::de::Error::custom("value is missing")), + } + } + + fn size_hint(&self) -> Option { + match self.iter.size_hint() { + (lower, Some(upper)) if lower == upper => Some(upper), + _ => None, + } + } +} + +macro_rules! deserialize_value_ref_number { + ($method:ident) => { + #[cfg(not(feature = "arbitrary_precision"))] + fn $method(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Number(n) => n.deserialize_any(visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + #[cfg(feature = "arbitrary_precision")] + fn $method(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Number(n) => n.$method(visitor), + _ => self.deserialize_any(visitor), + } + } + }; +} + +fn visit_array_ref<'de, V>(array: &'de [Value], visitor: V) -> Result +where + V: Visitor<'de>, +{ + let len = array.len(); + let mut deserializer = SeqRefDeserializer::new(array); + let seq = tri!(visitor.visit_seq(&mut deserializer)); + let remaining = deserializer.iter.len(); + if remaining == 0 { + Ok(seq) + } else { + Err(serde::de::Error::invalid_length( + len, + &"fewer elements in array", + )) + } +} + +impl<'de> serde::Deserializer<'de> for &'de Map { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let len = self.len(); + let mut deserializer = MapRefDeserializer::new(self); + let map = tri!(visitor.visit_map(&mut deserializer)); + let remaining = deserializer.iter.len(); + if remaining == 0 { + Ok(map) + } else { + Err(serde::de::Error::invalid_length( + len, + &"fewer elements in map", + )) + } + } + + fn deserialize_enum( + self, + _name: &'static str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + let mut iter = self.into_iter(); + let (variant, value) = match iter.next() { + Some(v) => v, + None => { + return Err(serde::de::Error::invalid_value( + Unexpected::Map, + &"map with a single key", + )); + } + }; + // enums are encoded in json as maps with a single key:value pair + if iter.next().is_some() { + return Err(serde::de::Error::invalid_value( + Unexpected::Map, + &"map with a single key", + )); + } + + visitor.visit_enum(EnumRefDeserializer { + variant, + value: Some(value), + }) + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_unit() + } + + 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 + } +} + +impl<'de> serde::Deserializer<'de> for &'de Value { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Null => visitor.visit_unit(), + Value::Bool(v) => visitor.visit_bool(*v), + Value::Number(n) => n.deserialize_any(visitor), + Value::String(v) => visitor.visit_borrowed_str(v), + Value::Array(v) => visit_array_ref(v, visitor), + Value::Object(v) => v.deserialize_any(visitor), + } + } + + deserialize_value_ref_number!(deserialize_i8); + deserialize_value_ref_number!(deserialize_i16); + deserialize_value_ref_number!(deserialize_i32); + deserialize_value_ref_number!(deserialize_i64); + deserialize_number!(deserialize_i128); + deserialize_value_ref_number!(deserialize_u8); + deserialize_value_ref_number!(deserialize_u16); + deserialize_value_ref_number!(deserialize_u32); + deserialize_value_ref_number!(deserialize_u64); + deserialize_number!(deserialize_u128); + deserialize_value_ref_number!(deserialize_f32); + deserialize_value_ref_number!(deserialize_f64); + + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match *self { + Value::Null => visitor.visit_none(), + _ => visitor.visit_some(self), + } + } + + fn deserialize_enum( + self, + name: &'static str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Object(value) => value.deserialize_enum(name, variants, visitor), + Value::String(variant) => visitor.visit_enum(EnumRefDeserializer { + variant, + value: None, + }), + other => Err(serde::de::Error::invalid_type( + other.unexpected(), + &"string or map", + )), + } + } + + #[inline] + fn deserialize_newtype_struct( + self, + name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + #[cfg(feature = "raw_value")] + { + if name == crate::raw::TOKEN { + return visitor.visit_map(crate::raw::OwnedRawDeserializer { + raw_value: Some(self.to_string()), + }); + } + } + + let _ = name; + visitor.visit_newtype_struct(self) + } + + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match *self { + Value::Bool(v) => visitor.visit_bool(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_char(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_str(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::String(v) => visitor.visit_borrowed_str(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_string(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_bytes(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::String(v) => visitor.visit_borrowed_str(v), + Value::Array(v) => visit_array_ref(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_byte_buf(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_bytes(visitor) + } + + fn deserialize_unit(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match *self { + Value::Null => visitor.visit_unit(), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_unit_struct(self, _name: &'static str, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_unit(visitor) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Array(v) => visit_array_ref(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_tuple(self, _len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_map(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Object(v) => v.deserialize_any(visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_struct( + self, + _name: &'static str, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match self { + Value::Array(v) => visit_array_ref(v, visitor), + Value::Object(v) => v.deserialize_any(visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_identifier(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_unit() + } +} + +struct EnumRefDeserializer<'de> { + variant: &'de str, + value: Option<&'de Value>, +} + +impl<'de> EnumAccess<'de> for EnumRefDeserializer<'de> { + type Error = Error; + type Variant = VariantRefDeserializer<'de>; + + fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), Error> + where + V: DeserializeSeed<'de>, + { + let variant = self.variant.into_deserializer(); + let visitor = VariantRefDeserializer { value: self.value }; + seed.deserialize(variant).map(|v| (v, visitor)) + } +} + +struct VariantRefDeserializer<'de> { + value: Option<&'de Value>, +} + +impl<'de> VariantAccess<'de> for VariantRefDeserializer<'de> { + type Error = Error; + + fn unit_variant(self) -> Result<(), Error> { + match self.value { + Some(value) => Deserialize::deserialize(value), + None => Ok(()), + } + } + + fn newtype_variant_seed(self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + match self.value { + Some(value) => seed.deserialize(value), + None => Err(serde::de::Error::invalid_type( + Unexpected::UnitVariant, + &"newtype variant", + )), + } + } + + fn tuple_variant(self, _len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.value { + Some(Value::Array(v)) => { + if v.is_empty() { + visitor.visit_unit() + } else { + visit_array_ref(v, visitor) + } + } + Some(other) => Err(serde::de::Error::invalid_type( + other.unexpected(), + &"tuple variant", + )), + None => Err(serde::de::Error::invalid_type( + Unexpected::UnitVariant, + &"tuple variant", + )), + } + } + + fn struct_variant( + self, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + match self.value { + Some(Value::Object(v)) => v.deserialize_any(visitor), + Some(other) => Err(serde::de::Error::invalid_type( + other.unexpected(), + &"struct variant", + )), + None => Err(serde::de::Error::invalid_type( + Unexpected::UnitVariant, + &"struct variant", + )), + } + } +} + +struct SeqRefDeserializer<'de> { + iter: slice::Iter<'de, Value>, +} + +impl<'de> SeqRefDeserializer<'de> { + fn new(slice: &'de [Value]) -> Self { + SeqRefDeserializer { iter: slice.iter() } + } +} + +impl<'de> SeqAccess<'de> for SeqRefDeserializer<'de> { + type Error = Error; + + fn next_element_seed(&mut self, seed: T) -> Result, Error> + where + T: DeserializeSeed<'de>, + { + match self.iter.next() { + Some(value) => seed.deserialize(value).map(Some), + None => Ok(None), + } + } + + fn size_hint(&self) -> Option { + match self.iter.size_hint() { + (lower, Some(upper)) if lower == upper => Some(upper), + _ => None, + } + } +} + +struct MapRefDeserializer<'de> { + iter: <&'de Map as IntoIterator>::IntoIter, + value: Option<&'de Value>, +} + +impl<'de> MapRefDeserializer<'de> { + fn new(map: &'de Map) -> Self { + MapRefDeserializer { + iter: map.into_iter(), + value: None, + } + } +} + +impl<'de> MapAccess<'de> for MapRefDeserializer<'de> { + type Error = Error; + + fn next_key_seed(&mut self, seed: T) -> Result, Error> + where + T: DeserializeSeed<'de>, + { + match self.iter.next() { + Some((key, value)) => { + self.value = Some(value); + let key_de = MapKeyDeserializer { + key: Cow::Borrowed(&**key), + }; + seed.deserialize(key_de).map(Some) + } + None => Ok(None), + } + } + + fn next_value_seed(&mut self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + match self.value.take() { + Some(value) => seed.deserialize(value), + None => Err(serde::de::Error::custom("value is missing")), + } + } + + fn size_hint(&self) -> Option { + match self.iter.size_hint() { + (lower, Some(upper)) if lower == upper => Some(upper), + _ => None, + } + } +} + +struct MapKeyDeserializer<'de> { + key: Cow<'de, str>, +} + +macro_rules! deserialize_numeric_key { + ($method:ident) => { + deserialize_numeric_key!($method, deserialize_number); + }; + + ($method:ident, $using:ident) => { + fn $method(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let mut de = crate::Deserializer::from_str(&self.key); + + match tri!(de.peek()) { + Some(b'0'..=b'9' | b'-') => {} + _ => return Err(Error::syntax(ErrorCode::ExpectedNumericKey, 0, 0)), + } + + let number = tri!(de.$using(visitor)); + + if tri!(de.peek()).is_some() { + return Err(Error::syntax(ErrorCode::ExpectedNumericKey, 0, 0)); + } + + Ok(number) + } + }; +} + +impl<'de> serde::Deserializer<'de> for MapKeyDeserializer<'de> { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + BorrowedCowStrDeserializer::new(self.key).deserialize_any(visitor) + } + + deserialize_numeric_key!(deserialize_i8); + deserialize_numeric_key!(deserialize_i16); + deserialize_numeric_key!(deserialize_i32); + deserialize_numeric_key!(deserialize_i64); + deserialize_numeric_key!(deserialize_u8); + deserialize_numeric_key!(deserialize_u16); + deserialize_numeric_key!(deserialize_u32); + deserialize_numeric_key!(deserialize_u64); + #[cfg(not(feature = "float_roundtrip"))] + deserialize_numeric_key!(deserialize_f32); + deserialize_numeric_key!(deserialize_f64); + + #[cfg(feature = "float_roundtrip")] + deserialize_numeric_key!(deserialize_f32, do_deserialize_f32); + deserialize_numeric_key!(deserialize_i128, do_deserialize_i128); + deserialize_numeric_key!(deserialize_u128, do_deserialize_u128); + + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + if self.key == "true" { + visitor.visit_bool(true) + } else if self.key == "false" { + visitor.visit_bool(false) + } else { + Err(serde::de::Error::invalid_type( + Unexpected::Str(&self.key), + &visitor, + )) + } + } + + #[inline] + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + // Map keys cannot be null. + visitor.visit_some(self) + } + + #[inline] + fn deserialize_newtype_struct( + self, + _name: &'static str, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + + fn deserialize_enum( + self, + name: &'static str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.key + .into_deserializer() + .deserialize_enum(name, variants, visitor) + } + + forward_to_deserialize_any! { + char str string bytes byte_buf unit unit_struct seq tuple tuple_struct + map struct identifier ignored_any + } +} + +struct KeyClassifier; + +enum KeyClass { + Map(String), + #[cfg(feature = "arbitrary_precision")] + Number, + #[cfg(feature = "raw_value")] + RawValue, +} + +impl<'de> DeserializeSeed<'de> for KeyClassifier { + type Value = KeyClass; + + fn deserialize(self, deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_str(self) + } +} + +impl<'de> Visitor<'de> for KeyClassifier { + type Value = KeyClass; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a string key") + } + + fn visit_str(self, s: &str) -> Result + where + E: de::Error, + { + match s { + #[cfg(feature = "arbitrary_precision")] + crate::number::TOKEN => Ok(KeyClass::Number), + #[cfg(feature = "raw_value")] + crate::raw::TOKEN => Ok(KeyClass::RawValue), + _ => Ok(KeyClass::Map(s.to_owned())), + } + } + + #[cfg(any(feature = "std", feature = "alloc"))] + fn visit_string(self, s: String) -> Result + where + E: de::Error, + { + match s.as_str() { + #[cfg(feature = "arbitrary_precision")] + crate::number::TOKEN => Ok(KeyClass::Number), + #[cfg(feature = "raw_value")] + crate::raw::TOKEN => Ok(KeyClass::RawValue), + _ => Ok(KeyClass::Map(s)), + } + } +} + +impl Value { + #[cold] + fn invalid_type(&self, exp: &dyn Expected) -> E + where + E: serde::de::Error, + { + serde::de::Error::invalid_type(self.unexpected(), exp) + } + + #[cold] + fn unexpected(&self) -> Unexpected { + match self { + Value::Null => Unexpected::Unit, + Value::Bool(b) => Unexpected::Bool(*b), + Value::Number(n) => n.unexpected(), + Value::String(s) => Unexpected::Str(s), + Value::Array(_) => Unexpected::Seq, + Value::Object(_) => Unexpected::Map, + } + } +} + +struct BorrowedCowStrDeserializer<'de> { + value: Cow<'de, str>, +} + +impl<'de> BorrowedCowStrDeserializer<'de> { + fn new(value: Cow<'de, str>) -> Self { + BorrowedCowStrDeserializer { value } + } +} + +impl<'de> de::Deserializer<'de> for BorrowedCowStrDeserializer<'de> { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + match self.value { + Cow::Borrowed(string) => visitor.visit_borrowed_str(string), + #[cfg(any(feature = "std", feature = "alloc"))] + Cow::Owned(string) => visitor.visit_string(string), + #[cfg(not(any(feature = "std", feature = "alloc")))] + Cow::Owned(_) => unreachable!(), + } + } + + fn deserialize_enum( + self, + _name: &str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_enum(self) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct identifier ignored_any + } +} + +impl<'de> de::EnumAccess<'de> for BorrowedCowStrDeserializer<'de> { + type Error = Error; + type Variant = UnitOnly; + + fn variant_seed(self, seed: T) -> Result<(T::Value, Self::Variant), Error> + where + T: de::DeserializeSeed<'de>, + { + let value = tri!(seed.deserialize(self)); + Ok((value, UnitOnly)) + } +} + +struct UnitOnly; + +impl<'de> de::VariantAccess<'de> for UnitOnly { + type Error = Error; + + fn unit_variant(self) -> Result<(), Error> { + Ok(()) + } + + fn newtype_variant_seed(self, _seed: T) -> Result + where + T: de::DeserializeSeed<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"newtype variant", + )) + } + + fn tuple_variant(self, _len: usize, _visitor: V) -> Result + where + V: de::Visitor<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"tuple variant", + )) + } + + fn struct_variant( + self, + _fields: &'static [&'static str], + _visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"struct variant", + )) + } +} diff --git a/third_party/crates/serde_json-1.0.151/src/value/from.rs b/third_party/crates/serde_json-1.0.151/src/value/from.rs new file mode 100644 index 0000000..df4b203 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/value/from.rs @@ -0,0 +1,284 @@ +use super::Value; +use crate::map::Map; +use crate::number::Number; +use alloc::borrow::{Cow, ToOwned}; +use alloc::string::String; +use alloc::vec::Vec; + +macro_rules! from_integer { + ($($ty:ident)*) => { + $( + impl From<$ty> for Value { + fn from(n: $ty) -> Self { + Value::Number(n.into()) + } + } + )* + }; +} + +from_integer! { + i8 i16 i32 i64 isize + u8 u16 u32 u64 usize +} + +#[cfg(feature = "arbitrary_precision")] +from_integer! { + i128 u128 +} + +impl From for Value { + /// Convert 32-bit floating point number to `Value::Number`, or + /// `Value::Null` if infinite or NaN. + /// + /// # Examples + /// + /// ``` + /// use serde_json::Value; + /// + /// let f: f32 = 13.37; + /// let x: Value = f.into(); + /// ``` + fn from(f: f32) -> Self { + Number::from_f32(f).map_or(Value::Null, Value::Number) + } +} + +impl From for Value { + /// Convert 64-bit floating point number to `Value::Number`, or + /// `Value::Null` if infinite or NaN. + /// + /// # Examples + /// + /// ``` + /// use serde_json::Value; + /// + /// let f: f64 = 13.37; + /// let x: Value = f.into(); + /// ``` + fn from(f: f64) -> Self { + Number::from_f64(f).map_or(Value::Null, Value::Number) + } +} + +impl From for Value { + /// Convert boolean to `Value::Bool`. + /// + /// # Examples + /// + /// ``` + /// use serde_json::Value; + /// + /// let b = false; + /// let x: Value = b.into(); + /// ``` + fn from(f: bool) -> Self { + Value::Bool(f) + } +} + +impl From for Value { + /// Convert `String` to `Value::String`. + /// + /// # Examples + /// + /// ``` + /// use serde_json::Value; + /// + /// let s: String = "lorem".to_owned(); + /// let x: Value = s.into(); + /// ``` + fn from(f: String) -> Self { + Value::String(f) + } +} + +impl From<&str> for Value { + /// Convert string slice to `Value::String`. + /// + /// # Examples + /// + /// ``` + /// use serde_json::Value; + /// + /// let s: &str = "lorem"; + /// let x: Value = s.into(); + /// ``` + fn from(f: &str) -> Self { + Value::String(f.to_owned()) + } +} + +impl<'a> From> for Value { + /// Convert copy-on-write string to `Value::String`. + /// + /// # Examples + /// + /// ``` + /// use serde_json::Value; + /// use std::borrow::Cow; + /// + /// let s: Cow = Cow::Borrowed("lorem"); + /// let x: Value = s.into(); + /// ``` + /// + /// ``` + /// use serde_json::Value; + /// use std::borrow::Cow; + /// + /// let s: Cow = Cow::Owned("lorem".to_owned()); + /// let x: Value = s.into(); + /// ``` + fn from(f: Cow<'a, str>) -> Self { + Value::String(f.into_owned()) + } +} + +impl From for Value { + /// Convert `Number` to `Value::Number`. + /// + /// # Examples + /// + /// ``` + /// use serde_json::{Number, Value}; + /// + /// let n = Number::from(7); + /// let x: Value = n.into(); + /// ``` + fn from(f: Number) -> Self { + Value::Number(f) + } +} + +impl From> for Value { + /// Convert map (with string keys) to `Value::Object`. + /// + /// # Examples + /// + /// ``` + /// use serde_json::{Map, Value}; + /// + /// let mut m = Map::new(); + /// m.insert("Lorem".to_owned(), "ipsum".into()); + /// let x: Value = m.into(); + /// ``` + fn from(f: Map) -> Self { + Value::Object(f) + } +} + +impl> From> for Value { + /// Convert a `Vec` to `Value::Array`. + /// + /// # Examples + /// + /// ``` + /// use serde_json::Value; + /// + /// let v = vec!["lorem", "ipsum", "dolor"]; + /// let x: Value = v.into(); + /// ``` + fn from(f: Vec) -> Self { + Value::Array(f.into_iter().map(Into::into).collect()) + } +} + +impl, const N: usize> From<[T; N]> for Value { + fn from(array: [T; N]) -> Self { + Value::Array(array.into_iter().map(Into::into).collect()) + } +} + +impl> From<&[T]> for Value { + /// Convert a slice to `Value::Array`. + /// + /// # Examples + /// + /// ``` + /// use serde_json::Value; + /// + /// let v: &[&str] = &["lorem", "ipsum", "dolor"]; + /// let x: Value = v.into(); + /// ``` + fn from(f: &[T]) -> Self { + Value::Array(f.iter().cloned().map(Into::into).collect()) + } +} + +impl> FromIterator for Value { + /// Create a `Value::Array` by collecting an iterator of array elements. + /// + /// # Examples + /// + /// ``` + /// use serde_json::Value; + /// + /// let v = std::iter::repeat(42).take(5); + /// let x: Value = v.collect(); + /// ``` + /// + /// ``` + /// use serde_json::Value; + /// + /// let v: Vec<_> = vec!["lorem", "ipsum", "dolor"]; + /// let x: Value = v.into_iter().collect(); + /// ``` + /// + /// ``` + /// use std::iter::FromIterator; + /// use serde_json::Value; + /// + /// let x: Value = Value::from_iter(vec!["lorem", "ipsum", "dolor"]); + /// ``` + fn from_iter>(iter: I) -> Self { + Value::Array(iter.into_iter().map(Into::into).collect()) + } +} + +impl, V: Into> FromIterator<(K, V)> for Value { + /// Create a `Value::Object` by collecting an iterator of key-value pairs. + /// + /// # Examples + /// + /// ``` + /// use serde_json::Value; + /// + /// let v: Vec<_> = vec![("lorem", 40), ("ipsum", 2)]; + /// let x: Value = v.into_iter().collect(); + /// ``` + fn from_iter>(iter: I) -> Self { + Value::Object( + iter.into_iter() + .map(|(k, v)| (k.into(), v.into())) + .collect(), + ) + } +} + +impl From<()> for Value { + /// Convert `()` to `Value::Null`. + /// + /// # Examples + /// + /// ``` + /// use serde_json::Value; + /// + /// let u = (); + /// let x: Value = u.into(); + /// ``` + fn from((): ()) -> Self { + Value::Null + } +} + +impl From> for Value +where + T: Into, +{ + fn from(opt: Option) -> Self { + match opt { + None => Value::Null, + Some(value) => Into::into(value), + } + } +} diff --git a/third_party/crates/serde_json-1.0.151/src/value/index.rs b/third_party/crates/serde_json-1.0.151/src/value/index.rs new file mode 100644 index 0000000..7b00110 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/value/index.rs @@ -0,0 +1,258 @@ +use super::Value; +use crate::map::Map; +use alloc::borrow::ToOwned; +use alloc::string::String; +use core::fmt::{self, Display}; +use core::ops; + +/// A type that can be used to index into a `serde_json::Value`. +/// +/// The [`get`] and [`get_mut`] methods of `Value` accept any type that +/// implements `Index`, as does the [square-bracket indexing operator]. This +/// trait is implemented for strings which are used as the index into a JSON +/// map, and for `usize` which is used as the index into a JSON array. +/// +/// [`get`]: Value::get +/// [`get_mut`]: Value::get_mut +/// [square-bracket indexing operator]: Value#impl-Index%3CI%3E-for-Value +/// +/// This trait is sealed and cannot be implemented for types outside of +/// `serde_json`. +/// +/// # Examples +/// +/// ``` +/// # use serde_json::json; +/// # +/// let data = json!({ "inner": [1, 2, 3] }); +/// +/// // Data is a JSON map so it can be indexed with a string. +/// let inner = &data["inner"]; +/// +/// // Inner is a JSON array so it can be indexed with an integer. +/// let first = &inner[0]; +/// +/// assert_eq!(first, 1); +/// ``` +pub trait Index: private::Sealed { + /// Return None if the key is not already in the array or object. + #[doc(hidden)] + fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value>; + + /// Return None if the key is not already in the array or object. + #[doc(hidden)] + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value>; + + /// Panic if array index out of bounds. If key is not already in the object, + /// insert it with a value of null. Panic if Value is a type that cannot be + /// indexed into, except if Value is null then it can be treated as an empty + /// object. + #[doc(hidden)] + fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value; +} + +impl Index for usize { + fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { + match v { + Value::Array(vec) => vec.get(*self), + _ => None, + } + } + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { + match v { + Value::Array(vec) => vec.get_mut(*self), + _ => None, + } + } + fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value { + match v { + Value::Array(vec) => { + let len = vec.len(); + vec.get_mut(*self).unwrap_or_else(|| { + panic!( + "cannot access index {} of JSON array of length {}", + self, len + ) + }) + } + _ => panic!("cannot access index {} of JSON {}", self, Type(v)), + } + } +} + +impl Index for str { + fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { + match v { + Value::Object(map) => map.get(self), + _ => None, + } + } + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { + match v { + Value::Object(map) => map.get_mut(self), + _ => None, + } + } + fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value { + if let Value::Null = v { + *v = Value::Object(Map::new()); + } + match v { + Value::Object(map) => map.entry(self.to_owned()).or_insert(Value::Null), + _ => panic!("cannot access key {:?} in JSON {}", self, Type(v)), + } + } +} + +impl Index for String { + fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { + self[..].index_into(v) + } + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { + self[..].index_into_mut(v) + } + fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value { + self[..].index_or_insert(v) + } +} + +impl Index for &T +where + T: ?Sized + Index, +{ + fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { + (**self).index_into(v) + } + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { + (**self).index_into_mut(v) + } + fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value { + (**self).index_or_insert(v) + } +} + +// Prevent users from implementing the Index trait. +mod private { + pub trait Sealed {} + impl Sealed for usize {} + impl Sealed for str {} + impl Sealed for alloc::string::String {} + impl Sealed for &T where T: ?Sized + Sealed {} +} + +/// Used in panic messages. +struct Type<'a>(&'a Value); + +impl<'a> Display for Type<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match *self.0 { + Value::Null => formatter.write_str("null"), + Value::Bool(_) => formatter.write_str("boolean"), + Value::Number(_) => formatter.write_str("number"), + Value::String(_) => formatter.write_str("string"), + Value::Array(_) => formatter.write_str("array"), + Value::Object(_) => formatter.write_str("object"), + } + } +} + +// The usual semantics of Index is to panic on invalid indexing. +// +// That said, the usual semantics are for things like Vec and BTreeMap which +// have different use cases than Value. If you are working with a Vec, you know +// that you are working with a Vec and you can get the len of the Vec and make +// sure your indices are within bounds. The Value use cases are more +// loosey-goosey. You got some JSON from an endpoint and you want to pull values +// out of it. Outside of this Index impl, you already have the option of using +// value.as_array() and working with the Vec directly, or matching on +// Value::Array and getting the Vec directly. The Index impl means you can skip +// that and index directly into the thing using a concise syntax. You don't have +// to check the type, you don't have to check the len, it is all about what you +// expect the Value to look like. +// +// Basically the use cases that would be well served by panicking here are +// better served by using one of the other approaches: get and get_mut, +// as_array, or match. The value of this impl is that it adds a way of working +// with Value that is not well served by the existing approaches: concise and +// careless and sometimes that is exactly what you want. +impl ops::Index for Value +where + I: Index, +{ + type Output = Value; + + /// Index into a `serde_json::Value` using the syntax `value[0]` or + /// `value["k"]`. + /// + /// Returns `Value::Null` if the type of `self` does not match the type of + /// the index, for example if the index is a string and `self` is an array + /// or a number. Also returns `Value::Null` if the given key does not exist + /// in the map or the given index is not within the bounds of the array. + /// + /// For retrieving deeply nested values, you should have a look at the + /// `Value::pointer` method. + /// + /// # Examples + /// + /// ``` + /// # use serde_json::json; + /// # + /// let data = json!({ + /// "x": { + /// "y": ["z", "zz"] + /// } + /// }); + /// + /// assert_eq!(data["x"]["y"], json!(["z", "zz"])); + /// assert_eq!(data["x"]["y"][0], json!("z")); + /// + /// assert_eq!(data["a"], json!(null)); // returns null for undefined values + /// assert_eq!(data["a"]["b"], json!(null)); // does not panic + /// ``` + fn index(&self, index: I) -> &Value { + static NULL: Value = Value::Null; + index.index_into(self).unwrap_or(&NULL) + } +} + +impl ops::IndexMut for Value +where + I: Index, +{ + /// Write into a `serde_json::Value` using the syntax `value[0] = ...` or + /// `value["k"] = ...`. + /// + /// If the index is a number, the value must be an array of length bigger + /// than the index. Indexing into a value that is not an array or an array + /// that is too small will panic. + /// + /// If the index is a string, the value must be an object or null which is + /// treated like an empty object. If the key is not already present in the + /// object, it will be inserted with a value of null. Indexing into a value + /// that is neither an object nor null will panic. + /// + /// # Examples + /// + /// ``` + /// # use serde_json::json; + /// # + /// let mut data = json!({ "x": 0 }); + /// + /// // replace an existing key + /// data["x"] = json!(1); + /// + /// // insert a new key + /// data["y"] = json!([false, false, false]); + /// + /// // replace an array value + /// data["y"][0] = json!(true); + /// + /// // inserted a deeply nested key + /// data["a"]["b"]["c"]["d"] = json!(true); + /// + /// println!("{}", data); + /// ``` + fn index_mut(&mut self, index: I) -> &mut Value { + index.index_or_insert(self) + } +} diff --git a/third_party/crates/serde_json-1.0.151/src/value/mod.rs b/third_party/crates/serde_json-1.0.151/src/value/mod.rs new file mode 100644 index 0000000..7c562f8 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/value/mod.rs @@ -0,0 +1,1042 @@ +//! The Value enum, a loosely typed way of representing any valid JSON value. +//! +//! # Constructing JSON +//! +//! Serde JSON provides a [`json!` macro][macro] to build `serde_json::Value` +//! objects with very natural JSON syntax. +//! +//! ``` +//! use serde_json::json; +//! +//! fn main() { +//! // The type of `john` is `serde_json::Value` +//! let john = json!({ +//! "name": "John Doe", +//! "age": 43, +//! "phones": [ +//! "+44 1234567", +//! "+44 2345678" +//! ] +//! }); +//! +//! println!("first phone number: {}", john["phones"][0]); +//! +//! // Convert to a string of JSON and print it out +//! println!("{}", john.to_string()); +//! } +//! ``` +//! +//! The `Value::to_string()` function converts a `serde_json::Value` into a +//! `String` of JSON text. +//! +//! One neat thing about the `json!` macro is that variables and expressions can +//! be interpolated directly into the JSON value as you are building it. Serde +//! will check at compile time that the value you are interpolating is able to +//! be represented as JSON. +//! +//! ``` +//! # use serde_json::json; +//! # +//! # fn random_phone() -> u16 { 0 } +//! # +//! let full_name = "John Doe"; +//! let age_last_year = 42; +//! +//! // The type of `john` is `serde_json::Value` +//! let john = json!({ +//! "name": full_name, +//! "age": age_last_year + 1, +//! "phones": [ +//! format!("+44 {}", random_phone()) +//! ] +//! }); +//! ``` +//! +//! A string of JSON data can be parsed into a `serde_json::Value` by the +//! [`serde_json::from_str`][from_str] function. There is also +//! [`from_slice`][from_slice] for parsing from a byte slice `&[u8]` and +//! [`from_reader`][from_reader] for parsing from any `io::Read` like a File or +//! a TCP stream. +//! +//! ``` +//! use serde_json::{json, Value, Error}; +//! +//! fn untyped_example() -> Result<(), Error> { +//! // Some JSON input data as a &str. Maybe this comes from the user. +//! let data = r#" +//! { +//! "name": "John Doe", +//! "age": 43, +//! "phones": [ +//! "+44 1234567", +//! "+44 2345678" +//! ] +//! }"#; +//! +//! // Parse the string of data into serde_json::Value. +//! let v: Value = serde_json::from_str(data)?; +//! +//! // Access parts of the data by indexing with square brackets. +//! println!("Please call {} at the number {}", v["name"], v["phones"][0]); +//! +//! Ok(()) +//! } +//! # +//! # untyped_example().unwrap(); +//! ``` +//! +//! [macro]: crate::json +//! [from_str]: crate::de::from_str +//! [from_slice]: crate::de::from_slice +//! [from_reader]: crate::de::from_reader + +use crate::error::Error; +use crate::io; +use alloc::string::String; +use alloc::vec::Vec; +use core::fmt::{self, Debug, Display}; +use core::mem; +use core::str; +use serde::de::DeserializeOwned; +use serde::ser::Serialize; + +pub use self::index::Index; +pub use self::ser::Serializer; +pub use crate::map::Map; +pub use crate::number::Number; + +#[cfg(feature = "raw_value")] +#[cfg_attr(docsrs, doc(cfg(feature = "raw_value")))] +pub use crate::raw::{to_raw_value, RawValue}; + +/// Represents any valid JSON value. +/// +/// See the [`serde_json::value` module documentation](self) for usage examples. +#[derive(Clone, Eq, PartialEq, Hash)] +pub enum Value { + /// Represents a JSON null value. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let v = json!(null); + /// ``` + Null, + + /// Represents a JSON boolean. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let v = json!(true); + /// ``` + Bool(bool), + + /// Represents a JSON number, whether integer or floating point. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let v = json!(12.5); + /// ``` + Number(Number), + + /// Represents a JSON string. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let v = json!("a string"); + /// ``` + String(String), + + /// Represents a JSON array. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let v = json!(["an", "array"]); + /// ``` + Array(Vec), + + /// Represents a JSON object. + /// + /// By default the map is backed by a BTreeMap. Enable the `preserve_order` + /// feature of serde_json to use IndexMap instead, which preserves + /// entries in the order they are inserted into the map. In particular, this + /// allows JSON data to be deserialized into a Value and serialized to a + /// string while retaining the order of map keys in the input. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let v = json!({ "an": "object" }); + /// ``` + Object(Map), +} + +impl Debug for Value { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + Value::Null => formatter.write_str("Null"), + Value::Bool(boolean) => write!(formatter, "Bool({})", boolean), + Value::Number(number) => Debug::fmt(number, formatter), + Value::String(string) => write!(formatter, "String({:?})", string), + Value::Array(vec) => { + tri!(formatter.write_str("Array ")); + Debug::fmt(vec, formatter) + } + Value::Object(map) => { + tri!(formatter.write_str("Object ")); + Debug::fmt(map, formatter) + } + } + } +} + +impl Display for Value { + /// Display a JSON value as a string. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let json = json!({ "city": "London", "street": "10 Downing Street" }); + /// + /// // Compact format: + /// // + /// // {"city":"London","street":"10 Downing Street"} + /// let compact = format!("{}", json); + /// assert_eq!(compact, + /// "{\"city\":\"London\",\"street\":\"10 Downing Street\"}"); + /// + /// // Pretty format: + /// // + /// // { + /// // "city": "London", + /// // "street": "10 Downing Street" + /// // } + /// let pretty = format!("{:#}", json); + /// assert_eq!(pretty, + /// "{\n \"city\": \"London\",\n \"street\": \"10 Downing Street\"\n}"); + /// ``` + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + struct WriterFormatter<'a, 'b: 'a> { + inner: &'a mut fmt::Formatter<'b>, + } + + impl<'a, 'b> io::Write for WriterFormatter<'a, 'b> { + fn write(&mut self, buf: &[u8]) -> io::Result { + // Safety: the serializer below only emits valid utf8 when using + // the default formatter. + let s = unsafe { str::from_utf8_unchecked(buf) }; + tri!(self.inner.write_str(s).map_err(io_error)); + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + } + + fn io_error(_: fmt::Error) -> io::Error { + // Error value does not matter because Display impl just maps it + // back to fmt::Error. + io::Error::new(io::ErrorKind::Other, "fmt error") + } + + let alternate = f.alternate(); + let mut wr = WriterFormatter { inner: f }; + if alternate { + // {:#} + super::ser::to_writer_pretty(&mut wr, self).map_err(|_| fmt::Error) + } else { + // {} + super::ser::to_writer(&mut wr, self).map_err(|_| fmt::Error) + } + } +} + +fn parse_index(s: &str) -> Option { + if s.starts_with('+') || (s.starts_with('0') && s.len() != 1) { + return None; + } + s.parse().ok() +} + +impl Value { + /// Index into a JSON array or map. A string index can be used to access a + /// value in a map, and a usize index can be used to access an element of an + /// array. + /// + /// Returns `None` if the type of `self` does not match the type of the + /// index, for example if the index is a string and `self` is an array or a + /// number. Also returns `None` if the given key does not exist in the map + /// or the given index is not within the bounds of the array. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let object = json!({ "A": 65, "B": 66, "C": 67 }); + /// assert_eq!(*object.get("A").unwrap(), json!(65)); + /// + /// let array = json!([ "A", "B", "C" ]); + /// assert_eq!(*array.get(2).unwrap(), json!("C")); + /// + /// assert_eq!(array.get("A"), None); + /// ``` + /// + /// Square brackets can also be used to index into a value in a more concise + /// way. This returns `Value::Null` in cases where `get` would have returned + /// `None`. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let object = json!({ + /// "A": ["a", "á", "à"], + /// "B": ["b", "b́"], + /// "C": ["c", "ć", "ć̣", "ḉ"], + /// }); + /// assert_eq!(object["B"][0], json!("b")); + /// + /// assert_eq!(object["D"], json!(null)); + /// assert_eq!(object[0]["x"]["y"]["z"], json!(null)); + /// ``` + pub fn get(&self, index: I) -> Option<&Value> { + index.index_into(self) + } + + /// Mutably index into a JSON array or map. A string index can be used to + /// access a value in a map, and a usize index can be used to access an + /// element of an array. + /// + /// Returns `None` if the type of `self` does not match the type of the + /// index, for example if the index is a string and `self` is an array or a + /// number. Also returns `None` if the given key does not exist in the map + /// or the given index is not within the bounds of the array. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let mut object = json!({ "A": 65, "B": 66, "C": 67 }); + /// *object.get_mut("A").unwrap() = json!(69); + /// + /// let mut array = json!([ "A", "B", "C" ]); + /// *array.get_mut(2).unwrap() = json!("D"); + /// ``` + pub fn get_mut(&mut self, index: I) -> Option<&mut Value> { + index.index_into_mut(self) + } + + /// Returns true if the `Value` is an Object. Returns false otherwise. + /// + /// For any Value on which `is_object` returns true, `as_object` and + /// `as_object_mut` are guaranteed to return the map representation of the + /// object. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let obj = json!({ "a": { "nested": true }, "b": ["an", "array"] }); + /// + /// assert!(obj.is_object()); + /// assert!(obj["a"].is_object()); + /// + /// // array, not an object + /// assert!(!obj["b"].is_object()); + /// ``` + pub fn is_object(&self) -> bool { + self.as_object().is_some() + } + + /// If the `Value` is an Object, returns the associated Map. Returns None + /// otherwise. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let v = json!({ "a": { "nested": true }, "b": ["an", "array"] }); + /// + /// // The length of `{"nested": true}` is 1 entry. + /// assert_eq!(v["a"].as_object().unwrap().len(), 1); + /// + /// // The array `["an", "array"]` is not an object. + /// assert_eq!(v["b"].as_object(), None); + /// ``` + pub fn as_object(&self) -> Option<&Map> { + match self { + Value::Object(map) => Some(map), + _ => None, + } + } + + /// If the `Value` is an Object, returns the associated mutable Map. + /// Returns None otherwise. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let mut v = json!({ "a": { "nested": true } }); + /// + /// v["a"].as_object_mut().unwrap().clear(); + /// assert_eq!(v, json!({ "a": {} })); + /// ``` + pub fn as_object_mut(&mut self) -> Option<&mut Map> { + match self { + Value::Object(map) => Some(map), + _ => None, + } + } + + /// Returns true if the `Value` is an Array. Returns false otherwise. + /// + /// For any Value on which `is_array` returns true, `as_array` and + /// `as_array_mut` are guaranteed to return the vector representing the + /// array. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let obj = json!({ "a": ["an", "array"], "b": { "an": "object" } }); + /// + /// assert!(obj["a"].is_array()); + /// + /// // an object, not an array + /// assert!(!obj["b"].is_array()); + /// ``` + pub fn is_array(&self) -> bool { + self.as_array().is_some() + } + + /// If the `Value` is an Array, returns the associated vector. Returns None + /// otherwise. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let v = json!({ "a": ["an", "array"], "b": { "an": "object" } }); + /// + /// // The length of `["an", "array"]` is 2 elements. + /// assert_eq!(v["a"].as_array().unwrap().len(), 2); + /// + /// // The object `{"an": "object"}` is not an array. + /// assert_eq!(v["b"].as_array(), None); + /// ``` + pub fn as_array(&self) -> Option<&Vec> { + match self { + Value::Array(array) => Some(array), + _ => None, + } + } + + /// If the `Value` is an Array, returns the associated mutable vector. + /// Returns None otherwise. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let mut v = json!({ "a": ["an", "array"] }); + /// + /// v["a"].as_array_mut().unwrap().clear(); + /// assert_eq!(v, json!({ "a": [] })); + /// ``` + pub fn as_array_mut(&mut self) -> Option<&mut Vec> { + match self { + Value::Array(list) => Some(list), + _ => None, + } + } + + /// Returns true if the `Value` is a String. Returns false otherwise. + /// + /// For any Value on which `is_string` returns true, `as_str` is guaranteed + /// to return the string slice. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let v = json!({ "a": "some string", "b": false }); + /// + /// assert!(v["a"].is_string()); + /// + /// // The boolean `false` is not a string. + /// assert!(!v["b"].is_string()); + /// ``` + pub fn is_string(&self) -> bool { + self.as_str().is_some() + } + + /// If the `Value` is a String, returns the associated str. Returns None + /// otherwise. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let v = json!({ "a": "some string", "b": false }); + /// + /// assert_eq!(v["a"].as_str(), Some("some string")); + /// + /// // The boolean `false` is not a string. + /// assert_eq!(v["b"].as_str(), None); + /// + /// // JSON values are printed in JSON representation, so strings are in quotes. + /// // + /// // The value is: "some string" + /// println!("The value is: {}", v["a"]); + /// + /// // Rust strings are printed without quotes. + /// // + /// // The value is: some string + /// println!("The value is: {}", v["a"].as_str().unwrap()); + /// ``` + pub fn as_str(&self) -> Option<&str> { + match self { + Value::String(s) => Some(s), + _ => None, + } + } + + /// Returns true if the `Value` is a Number. Returns false otherwise. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let v = json!({ "a": 1, "b": "2" }); + /// + /// assert!(v["a"].is_number()); + /// + /// // The string `"2"` is a string, not a number. + /// assert!(!v["b"].is_number()); + /// ``` + pub fn is_number(&self) -> bool { + match *self { + Value::Number(_) => true, + _ => false, + } + } + + /// If the `Value` is a Number, returns the associated [`Number`]. Returns + /// None otherwise. + /// + /// ``` + /// # use serde_json::{json, Number}; + /// # + /// let v = json!({ "a": 1, "b": 2.2, "c": -3, "d": "4" }); + /// + /// assert_eq!(v["a"].as_number(), Some(&Number::from(1u64))); + /// assert_eq!(v["b"].as_number(), Some(&Number::from_f64(2.2).unwrap())); + /// assert_eq!(v["c"].as_number(), Some(&Number::from(-3i64))); + /// + /// // The string `"4"` is not a number. + /// assert_eq!(v["d"].as_number(), None); + /// ``` + pub fn as_number(&self) -> Option<&Number> { + match self { + Value::Number(number) => Some(number), + _ => None, + } + } + + /// Returns true if the `Value` is an integer between `i64::MIN` and + /// `i64::MAX`. + /// + /// For any Value on which `is_i64` returns true, `as_i64` is guaranteed to + /// return the integer value. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let big = i64::max_value() as u64 + 10; + /// let v = json!({ "a": 64, "b": big, "c": 256.0 }); + /// + /// assert!(v["a"].is_i64()); + /// + /// // Greater than i64::MAX. + /// assert!(!v["b"].is_i64()); + /// + /// // Numbers with a decimal point are not considered integers. + /// assert!(!v["c"].is_i64()); + /// ``` + pub fn is_i64(&self) -> bool { + match self { + Value::Number(n) => n.is_i64(), + _ => false, + } + } + + /// Returns true if the `Value` is an integer between zero and `u64::MAX`. + /// + /// For any Value on which `is_u64` returns true, `as_u64` is guaranteed to + /// return the integer value. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let v = json!({ "a": 64, "b": -64, "c": 256.0 }); + /// + /// assert!(v["a"].is_u64()); + /// + /// // Negative integer. + /// assert!(!v["b"].is_u64()); + /// + /// // Numbers with a decimal point are not considered integers. + /// assert!(!v["c"].is_u64()); + /// ``` + pub fn is_u64(&self) -> bool { + match self { + Value::Number(n) => n.is_u64(), + _ => false, + } + } + + /// Returns true if the `Value` is a number that can be represented by f64. + /// + /// For any Value on which `is_f64` returns true, `as_f64` is guaranteed to + /// return the floating point value. + /// + /// Currently this function returns true if and only if both `is_i64` and + /// `is_u64` return false but this is not a guarantee in the future. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let v = json!({ "a": 256.0, "b": 64, "c": -64 }); + /// + /// assert!(v["a"].is_f64()); + /// + /// // Integers. + /// assert!(!v["b"].is_f64()); + /// assert!(!v["c"].is_f64()); + /// ``` + pub fn is_f64(&self) -> bool { + match self { + Value::Number(n) => n.is_f64(), + _ => false, + } + } + + /// If the `Value` is an integer, represent it as i64 if possible. Returns + /// None otherwise. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let big = i64::max_value() as u64 + 10; + /// let v = json!({ "a": 64, "b": big, "c": 256.0 }); + /// + /// assert_eq!(v["a"].as_i64(), Some(64)); + /// assert_eq!(v["b"].as_i64(), None); + /// assert_eq!(v["c"].as_i64(), None); + /// ``` + pub fn as_i64(&self) -> Option { + match self { + Value::Number(n) => n.as_i64(), + _ => None, + } + } + + /// If the `Value` is an integer, represent it as u64 if possible. Returns + /// None otherwise. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let v = json!({ "a": 64, "b": -64, "c": 256.0 }); + /// + /// assert_eq!(v["a"].as_u64(), Some(64)); + /// assert_eq!(v["b"].as_u64(), None); + /// assert_eq!(v["c"].as_u64(), None); + /// ``` + pub fn as_u64(&self) -> Option { + match self { + Value::Number(n) => n.as_u64(), + _ => None, + } + } + + /// If the `Value` is a number, represent it as f64 if possible. Returns + /// None otherwise. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let v = json!({ "a": 256.0, "b": 64, "c": -64 }); + /// + /// assert_eq!(v["a"].as_f64(), Some(256.0)); + /// assert_eq!(v["b"].as_f64(), Some(64.0)); + /// assert_eq!(v["c"].as_f64(), Some(-64.0)); + /// ``` + pub fn as_f64(&self) -> Option { + match self { + Value::Number(n) => n.as_f64(), + _ => None, + } + } + + /// Returns true if the `Value` is a Boolean. Returns false otherwise. + /// + /// For any Value on which `is_boolean` returns true, `as_bool` is + /// guaranteed to return the boolean value. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let v = json!({ "a": false, "b": "false" }); + /// + /// assert!(v["a"].is_boolean()); + /// + /// // The string `"false"` is a string, not a boolean. + /// assert!(!v["b"].is_boolean()); + /// ``` + pub fn is_boolean(&self) -> bool { + self.as_bool().is_some() + } + + /// If the `Value` is a Boolean, returns the associated bool. Returns None + /// otherwise. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let v = json!({ "a": false, "b": "false" }); + /// + /// assert_eq!(v["a"].as_bool(), Some(false)); + /// + /// // The string `"false"` is a string, not a boolean. + /// assert_eq!(v["b"].as_bool(), None); + /// ``` + pub fn as_bool(&self) -> Option { + match *self { + Value::Bool(b) => Some(b), + _ => None, + } + } + + /// Returns true if the `Value` is a Null. Returns false otherwise. + /// + /// For any Value on which `is_null` returns true, `as_null` is guaranteed + /// to return `Some(())`. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let v = json!({ "a": null, "b": false }); + /// + /// assert!(v["a"].is_null()); + /// + /// // The boolean `false` is not null. + /// assert!(!v["b"].is_null()); + /// ``` + pub fn is_null(&self) -> bool { + self.as_null().is_some() + } + + /// If the `Value` is a Null, returns (). Returns None otherwise. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let v = json!({ "a": null, "b": false }); + /// + /// assert_eq!(v["a"].as_null(), Some(())); + /// + /// // The boolean `false` is not null. + /// assert_eq!(v["b"].as_null(), None); + /// ``` + pub fn as_null(&self) -> Option<()> { + match *self { + Value::Null => Some(()), + _ => None, + } + } + + /// Looks up a value by a JSON Pointer. + /// + /// JSON Pointer defines a string syntax for identifying a specific value + /// within a JavaScript Object Notation (JSON) document. + /// + /// A Pointer is a Unicode string with the reference tokens separated by `/`. + /// Inside tokens `/` is replaced by `~1` and `~` is replaced by `~0`. The + /// addressed value is returned and if there is no such value `None` is + /// returned. + /// + /// For more information read [RFC6901](https://tools.ietf.org/html/rfc6901). + /// + /// # Examples + /// + /// ``` + /// # use serde_json::json; + /// # + /// let data = json!({ + /// "x": { + /// "y": ["z", "zz"] + /// } + /// }); + /// + /// assert_eq!(data.pointer("/x/y/1").unwrap(), &json!("zz")); + /// assert_eq!(data.pointer("/a/b/c"), None); + /// ``` + pub fn pointer(&self, pointer: &str) -> Option<&Value> { + if pointer.is_empty() { + return Some(self); + } + if !pointer.starts_with('/') { + return None; + } + pointer + .split('/') + .skip(1) + .map(|x| x.replace("~1", "/").replace("~0", "~")) + .try_fold(self, |target, token| match target { + Value::Object(map) => map.get(&token), + Value::Array(list) => parse_index(&token).and_then(|x| list.get(x)), + _ => None, + }) + } + + /// Looks up a value by a JSON Pointer and returns a mutable reference to + /// that value. + /// + /// JSON Pointer defines a string syntax for identifying a specific value + /// within a JavaScript Object Notation (JSON) document. + /// + /// A Pointer is a Unicode string with the reference tokens separated by `/`. + /// Inside tokens `/` is replaced by `~1` and `~` is replaced by `~0`. The + /// addressed value is returned and if there is no such value `None` is + /// returned. + /// + /// For more information read [RFC6901](https://tools.ietf.org/html/rfc6901). + /// + /// # Example of Use + /// + /// ``` + /// use serde_json::Value; + /// + /// fn main() { + /// let s = r#"{"x": 1.0, "y": 2.0}"#; + /// let mut value: Value = serde_json::from_str(s).unwrap(); + /// + /// // Check value using read-only pointer + /// assert_eq!(value.pointer("/x"), Some(&1.0.into())); + /// // Change value with direct assignment + /// *value.pointer_mut("/x").unwrap() = 1.5.into(); + /// // Check that new value was written + /// assert_eq!(value.pointer("/x"), Some(&1.5.into())); + /// // Or change the value only if it exists + /// value.pointer_mut("/x").map(|v| *v = 1.5.into()); + /// + /// // "Steal" ownership of a value. Can replace with any valid Value. + /// let old_x = value.pointer_mut("/x").map(Value::take).unwrap(); + /// assert_eq!(old_x, 1.5); + /// assert_eq!(value.pointer("/x").unwrap(), &Value::Null); + /// } + /// ``` + pub fn pointer_mut(&mut self, pointer: &str) -> Option<&mut Value> { + if pointer.is_empty() { + return Some(self); + } + if !pointer.starts_with('/') { + return None; + } + pointer + .split('/') + .skip(1) + .map(|x| x.replace("~1", "/").replace("~0", "~")) + .try_fold(self, |target, token| match target { + Value::Object(map) => map.get_mut(&token), + Value::Array(list) => parse_index(&token).and_then(move |x| list.get_mut(x)), + _ => None, + }) + } + + /// Takes the value out of the `Value`, leaving a `Null` in its place. + /// + /// ``` + /// # use serde_json::json; + /// # + /// let mut v = json!({ "x": "y" }); + /// assert_eq!(v["x"].take(), json!("y")); + /// assert_eq!(v, json!({ "x": null })); + /// ``` + pub fn take(&mut self) -> Value { + mem::replace(self, Value::Null) + } + + /// Reorders the entries of all `Value::Object` nested within this JSON + /// value according to `str`'s usual ordering. + /// + /// If serde_json's "preserve_order" feature is not enabled, this method + /// does no work because all JSON maps are always kept in a sorted state. + /// + /// If serde_json's "preserve_order" feature is enabled, this method + /// destroys the original source order or insertion order of the JSON + /// objects in favor of an alphanumerical order that matches how a BTreeMap + /// with the same contents would be ordered. + pub fn sort_all_objects(&mut self) { + #[cfg(feature = "preserve_order")] + { + match self { + Value::Object(map) => { + map.sort_keys(); + map.values_mut().for_each(Value::sort_all_objects); + } + Value::Array(list) => { + list.iter_mut().for_each(Value::sort_all_objects); + } + _ => {} + } + } + } +} + +/// The default value is `Value::Null`. +/// +/// This is useful for handling omitted `Value` fields when deserializing. +/// +/// # Examples +/// +/// ``` +/// # use serde::Deserialize; +/// use serde_json::Value; +/// +/// #[derive(Deserialize)] +/// struct Settings { +/// level: i32, +/// #[serde(default)] +/// extras: Value, +/// } +/// +/// # fn try_main() -> Result<(), serde_json::Error> { +/// let data = r#" { "level": 42 } "#; +/// let s: Settings = serde_json::from_str(data)?; +/// +/// assert_eq!(s.level, 42); +/// assert_eq!(s.extras, Value::Null); +/// # +/// # Ok(()) +/// # } +/// # +/// # try_main().unwrap() +/// ``` +impl Default for Value { + fn default() -> Value { + Value::Null + } +} + +impl Default for &Value { + fn default() -> Self { + const DEFAULT: Value = Value::Null; + &DEFAULT + } +} + +mod de; +mod from; +mod index; +mod partial_eq; +mod ser; + +/// Convert a `T` into `serde_json::Value` which is an enum that can represent +/// any valid JSON data. +/// +/// # Example +/// +/// ``` +/// use serde::Serialize; +/// use serde_json::json; +/// use std::error::Error; +/// +/// #[derive(Serialize)] +/// struct User { +/// fingerprint: String, +/// location: String, +/// } +/// +/// fn compare_json_values() -> Result<(), Box> { +/// let u = User { +/// fingerprint: "0xF9BA143B95FF6D82".to_owned(), +/// location: "Menlo Park, CA".to_owned(), +/// }; +/// +/// // The type of `expected` is `serde_json::Value` +/// let expected = json!({ +/// "fingerprint": "0xF9BA143B95FF6D82", +/// "location": "Menlo Park, CA", +/// }); +/// +/// let v = serde_json::to_value(u).unwrap(); +/// assert_eq!(v, expected); +/// +/// Ok(()) +/// } +/// # +/// # compare_json_values().unwrap(); +/// ``` +/// +/// # Errors +/// +/// This conversion can fail if `T`'s implementation of `Serialize` decides to +/// fail, or if `T` contains a map with non-string keys. +/// +/// ``` +/// use std::collections::BTreeMap; +/// +/// fn main() { +/// // The keys in this map are vectors, not strings. +/// let mut map = BTreeMap::new(); +/// map.insert(vec![32, 64], "x86"); +/// +/// println!("{}", serde_json::to_value(map).unwrap_err()); +/// } +/// ``` +// Taking by value is more friendly to iterator adapters, option and result +// consumers, etc. See https://github.com/serde-rs/json/pull/149. +pub fn to_value(value: T) -> Result +where + T: Serialize, +{ + value.serialize(Serializer) +} + +/// Interpret a `serde_json::Value` as an instance of type `T`. +/// +/// # Example +/// +/// ``` +/// use serde::Deserialize; +/// use serde_json::json; +/// +/// #[derive(Deserialize, Debug)] +/// struct User { +/// fingerprint: String, +/// location: String, +/// } +/// +/// fn main() { +/// // The type of `j` is `serde_json::Value` +/// let j = json!({ +/// "fingerprint": "0xF9BA143B95FF6D82", +/// "location": "Menlo Park, CA" +/// }); +/// +/// let u: User = serde_json::from_value(j).unwrap(); +/// println!("{:#?}", u); +/// } +/// ``` +/// +/// # Errors +/// +/// This conversion can fail if the structure of the Value does not match the +/// structure expected by `T`, for example if `T` is a struct type but the Value +/// contains something other than a JSON map. It can also fail if the structure +/// is correct but `T`'s implementation of `Deserialize` decides that something +/// is wrong with the data, for example required struct fields are missing from +/// the JSON map or some number is too big to fit in the expected primitive +/// type. +pub fn from_value(value: Value) -> Result +where + T: DeserializeOwned, +{ + T::deserialize(value) +} diff --git a/third_party/crates/serde_json-1.0.151/src/value/partial_eq.rs b/third_party/crates/serde_json-1.0.151/src/value/partial_eq.rs new file mode 100644 index 0000000..8626eed --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/value/partial_eq.rs @@ -0,0 +1,103 @@ +use super::Value; +use alloc::string::String; + +fn eq_i64(value: &Value, other: i64) -> bool { + value.as_i64() == Some(other) +} + +fn eq_u64(value: &Value, other: u64) -> bool { + value.as_u64() == Some(other) +} + +fn eq_f32(value: &Value, other: f32) -> bool { + match value { + Value::Number(n) => n.as_f32() == Some(other), + _ => false, + } +} + +fn eq_f64(value: &Value, other: f64) -> bool { + value.as_f64() == Some(other) +} + +fn eq_bool(value: &Value, other: bool) -> bool { + value.as_bool() == Some(other) +} + +fn eq_str(value: &Value, other: &str) -> bool { + value.as_str() == Some(other) +} + +impl PartialEq for Value { + fn eq(&self, other: &str) -> bool { + eq_str(self, other) + } +} + +impl PartialEq<&str> for Value { + fn eq(&self, other: &&str) -> bool { + eq_str(self, *other) + } +} + +impl PartialEq for str { + fn eq(&self, other: &Value) -> bool { + eq_str(other, self) + } +} + +impl PartialEq for &str { + fn eq(&self, other: &Value) -> bool { + eq_str(other, *self) + } +} + +impl PartialEq for Value { + fn eq(&self, other: &String) -> bool { + eq_str(self, other.as_str()) + } +} + +impl PartialEq for String { + fn eq(&self, other: &Value) -> bool { + eq_str(other, self.as_str()) + } +} + +macro_rules! partialeq_numeric { + ($($eq:ident [$($ty:ty)*])*) => { + $($( + impl PartialEq<$ty> for Value { + fn eq(&self, other: &$ty) -> bool { + $eq(self, *other as _) + } + } + + impl PartialEq for $ty { + fn eq(&self, other: &Value) -> bool { + $eq(other, *self as _) + } + } + + impl<'a> PartialEq<$ty> for &'a Value { + fn eq(&self, other: &$ty) -> bool { + $eq(*self, *other as _) + } + } + + impl<'a> PartialEq<$ty> for &'a mut Value { + fn eq(&self, other: &$ty) -> bool { + $eq(*self, *other as _) + } + } + )*)* + } +} + +partialeq_numeric! { + eq_i64[i8 i16 i32 i64 isize] + eq_u64[u8 u16 u32 u64 usize] + eq_f32[f32] + eq_f64[f64] + eq_bool[bool] +} diff --git a/third_party/crates/serde_json-1.0.151/src/value/ser.rs b/third_party/crates/serde_json-1.0.151/src/value/ser.rs new file mode 100644 index 0000000..d5e2e84 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/src/value/ser.rs @@ -0,0 +1,1063 @@ +use crate::error::{Error, ErrorCode, Result}; +use crate::map::Map; +use crate::value::{to_value, Value}; +use alloc::borrow::ToOwned; +use alloc::string::{String, ToString}; +use alloc::vec::Vec; +use core::fmt::Display; +use core::result; +use serde::ser::{Impossible, Serialize}; + +impl Serialize for Value { + #[inline] + fn serialize(&self, serializer: S) -> result::Result + where + S: ::serde::Serializer, + { + match self { + Value::Null => serializer.serialize_unit(), + Value::Bool(b) => serializer.serialize_bool(*b), + Value::Number(n) => n.serialize(serializer), + Value::String(s) => serializer.serialize_str(s), + Value::Array(v) => v.serialize(serializer), + #[cfg(any(feature = "std", feature = "alloc"))] + Value::Object(m) => { + use serde::ser::SerializeMap; + let mut map = tri!(serializer.serialize_map(Some(m.len()))); + for (k, v) in m { + tri!(map.serialize_entry(k, v)); + } + map.end() + } + #[cfg(not(any(feature = "std", feature = "alloc")))] + Value::Object(_) => unreachable!(), + } + } +} + +/// Serializer whose output is a `Value`. +/// +/// This is the serializer that backs [`serde_json::to_value`][crate::to_value]. +/// Unlike the main serde_json serializer which goes from some serializable +/// value of type `T` to JSON text, this one goes from `T` to +/// `serde_json::Value`. +/// +/// The `to_value` function is implementable as: +/// +/// ``` +/// use serde::Serialize; +/// use serde_json::{Error, Value}; +/// +/// pub fn to_value(input: T) -> Result +/// where +/// T: Serialize, +/// { +/// input.serialize(serde_json::value::Serializer) +/// } +/// ``` +pub struct Serializer; + +impl serde::Serializer for Serializer { + type Ok = Value; + type Error = Error; + + type SerializeSeq = SerializeVec; + type SerializeTuple = SerializeVec; + type SerializeTupleStruct = SerializeVec; + type SerializeTupleVariant = SerializeTupleVariant; + type SerializeMap = SerializeMap; + type SerializeStruct = SerializeMap; + type SerializeStructVariant = SerializeStructVariant; + + #[inline] + fn serialize_bool(self, value: bool) -> Result { + Ok(Value::Bool(value)) + } + + #[inline] + fn serialize_i8(self, value: i8) -> Result { + self.serialize_i64(value as i64) + } + + #[inline] + fn serialize_i16(self, value: i16) -> Result { + self.serialize_i64(value as i64) + } + + #[inline] + fn serialize_i32(self, value: i32) -> Result { + self.serialize_i64(value as i64) + } + + fn serialize_i64(self, value: i64) -> Result { + Ok(Value::Number(value.into())) + } + + fn serialize_i128(self, value: i128) -> Result { + #[cfg(feature = "arbitrary_precision")] + { + Ok(Value::Number(value.into())) + } + + #[cfg(not(feature = "arbitrary_precision"))] + { + if let Ok(value) = u64::try_from(value) { + Ok(Value::Number(value.into())) + } else if let Ok(value) = i64::try_from(value) { + Ok(Value::Number(value.into())) + } else { + Err(Error::syntax(ErrorCode::NumberOutOfRange, 0, 0)) + } + } + } + + #[inline] + fn serialize_u8(self, value: u8) -> Result { + self.serialize_u64(value as u64) + } + + #[inline] + fn serialize_u16(self, value: u16) -> Result { + self.serialize_u64(value as u64) + } + + #[inline] + fn serialize_u32(self, value: u32) -> Result { + self.serialize_u64(value as u64) + } + + #[inline] + fn serialize_u64(self, value: u64) -> Result { + Ok(Value::Number(value.into())) + } + + fn serialize_u128(self, value: u128) -> Result { + #[cfg(feature = "arbitrary_precision")] + { + Ok(Value::Number(value.into())) + } + + #[cfg(not(feature = "arbitrary_precision"))] + { + if let Ok(value) = u64::try_from(value) { + Ok(Value::Number(value.into())) + } else { + Err(Error::syntax(ErrorCode::NumberOutOfRange, 0, 0)) + } + } + } + + #[inline] + fn serialize_f32(self, float: f32) -> Result { + Ok(Value::from(float)) + } + + #[inline] + fn serialize_f64(self, float: f64) -> Result { + Ok(Value::from(float)) + } + + #[inline] + fn serialize_char(self, value: char) -> Result { + let mut s = String::new(); + s.push(value); + Ok(Value::String(s)) + } + + #[inline] + fn serialize_str(self, value: &str) -> Result { + Ok(Value::String(value.to_owned())) + } + + fn serialize_bytes(self, value: &[u8]) -> Result { + let vec = value.iter().map(|&b| Value::Number(b.into())).collect(); + Ok(Value::Array(vec)) + } + + #[inline] + fn serialize_unit(self) -> Result { + Ok(Value::Null) + } + + #[inline] + fn serialize_unit_struct(self, _name: &'static str) -> Result { + self.serialize_unit() + } + + #[inline] + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result { + self.serialize_str(variant) + } + + #[inline] + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result + where + T: ?Sized + Serialize, + { + let mut values = Map::new(); + values.insert(String::from(variant), tri!(to_value(value))); + Ok(Value::Object(values)) + } + + #[inline] + fn serialize_none(self) -> Result { + self.serialize_unit() + } + + #[inline] + fn serialize_some(self, value: &T) -> Result + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + fn serialize_seq(self, len: Option) -> Result { + Ok(SerializeVec { + vec: Vec::with_capacity(len.unwrap_or(0)), + }) + } + + fn serialize_tuple(self, len: usize) -> Result { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + len: usize, + ) -> Result { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + Ok(SerializeTupleVariant { + name: String::from(variant), + vec: Vec::with_capacity(len), + }) + } + + fn serialize_map(self, len: Option) -> Result { + Ok(SerializeMap::Map { + map: Map::with_capacity(len.unwrap_or(0)), + next_key: None, + }) + } + + fn serialize_struct(self, name: &'static str, len: usize) -> Result { + match name { + #[cfg(feature = "arbitrary_precision")] + crate::number::TOKEN => Ok(SerializeMap::Number { out_value: None }), + #[cfg(feature = "raw_value")] + crate::raw::TOKEN => Ok(SerializeMap::RawValue { out_value: None }), + _ => self.serialize_map(Some(len)), + } + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + _len: usize, + ) -> Result { + Ok(SerializeStructVariant { + name: String::from(variant), + map: Map::new(), + }) + } + + fn collect_str(self, value: &T) -> Result + where + T: ?Sized + Display, + { + Ok(Value::String(value.to_string())) + } +} + +pub struct SerializeVec { + vec: Vec, +} + +pub struct SerializeTupleVariant { + name: String, + vec: Vec, +} + +pub enum SerializeMap { + Map { + map: Map, + next_key: Option, + }, + #[cfg(feature = "arbitrary_precision")] + Number { out_value: Option }, + #[cfg(feature = "raw_value")] + RawValue { out_value: Option }, +} + +pub struct SerializeStructVariant { + name: String, + map: Map, +} + +impl serde::ser::SerializeSeq for SerializeVec { + type Ok = Value; + type Error = Error; + + fn serialize_element(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + self.vec.push(tri!(to_value(value))); + Ok(()) + } + + fn end(self) -> Result { + Ok(Value::Array(self.vec)) + } +} + +impl serde::ser::SerializeTuple for SerializeVec { + type Ok = Value; + type Error = Error; + + fn serialize_element(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + serde::ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result { + serde::ser::SerializeSeq::end(self) + } +} + +impl serde::ser::SerializeTupleStruct for SerializeVec { + type Ok = Value; + type Error = Error; + + fn serialize_field(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + serde::ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result { + serde::ser::SerializeSeq::end(self) + } +} + +impl serde::ser::SerializeTupleVariant for SerializeTupleVariant { + type Ok = Value; + type Error = Error; + + fn serialize_field(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + self.vec.push(tri!(to_value(value))); + Ok(()) + } + + fn end(self) -> Result { + let mut object = Map::new(); + + object.insert(self.name, Value::Array(self.vec)); + + Ok(Value::Object(object)) + } +} + +impl serde::ser::SerializeMap for SerializeMap { + type Ok = Value; + type Error = Error; + + fn serialize_key(&mut self, key: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + match self { + SerializeMap::Map { next_key, .. } => { + *next_key = Some(tri!(key.serialize(MapKeySerializer))); + Ok(()) + } + #[cfg(feature = "arbitrary_precision")] + SerializeMap::Number { .. } => unreachable!(), + #[cfg(feature = "raw_value")] + SerializeMap::RawValue { .. } => unreachable!(), + } + } + + fn serialize_value(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + match self { + SerializeMap::Map { map, next_key } => { + let key = next_key.take(); + // Panic because this indicates a bug in the program rather than an + // expected failure. + let key = key.expect("serialize_value called before serialize_key"); + map.insert(key, tri!(to_value(value))); + Ok(()) + } + #[cfg(feature = "arbitrary_precision")] + SerializeMap::Number { .. } => unreachable!(), + #[cfg(feature = "raw_value")] + SerializeMap::RawValue { .. } => unreachable!(), + } + } + + fn end(self) -> Result { + match self { + SerializeMap::Map { map, .. } => Ok(Value::Object(map)), + #[cfg(feature = "arbitrary_precision")] + SerializeMap::Number { .. } => unreachable!(), + #[cfg(feature = "raw_value")] + SerializeMap::RawValue { .. } => unreachable!(), + } + } +} + +struct MapKeySerializer; + +fn key_must_be_a_string() -> Error { + Error::syntax(ErrorCode::KeyMustBeAString, 0, 0) +} + +fn float_key_must_be_finite() -> Error { + Error::syntax(ErrorCode::FloatKeyMustBeFinite, 0, 0) +} + +impl serde::Serializer for MapKeySerializer { + type Ok = String; + type Error = Error; + + type SerializeSeq = Impossible; + type SerializeTuple = Impossible; + type SerializeTupleStruct = Impossible; + type SerializeTupleVariant = Impossible; + type SerializeMap = Impossible; + type SerializeStruct = Impossible; + type SerializeStructVariant = Impossible; + + #[inline] + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result { + Ok(variant.to_owned()) + } + + #[inline] + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + fn serialize_bool(self, value: bool) -> Result { + Ok(if value { "true" } else { "false" }.to_owned()) + } + + fn serialize_i8(self, value: i8) -> Result { + Ok(itoa::Buffer::new().format(value).to_owned()) + } + + fn serialize_i16(self, value: i16) -> Result { + Ok(itoa::Buffer::new().format(value).to_owned()) + } + + fn serialize_i32(self, value: i32) -> Result { + Ok(itoa::Buffer::new().format(value).to_owned()) + } + + fn serialize_i64(self, value: i64) -> Result { + Ok(itoa::Buffer::new().format(value).to_owned()) + } + + fn serialize_i128(self, value: i128) -> Result { + Ok(itoa::Buffer::new().format(value).to_owned()) + } + + fn serialize_u8(self, value: u8) -> Result { + Ok(itoa::Buffer::new().format(value).to_owned()) + } + + fn serialize_u16(self, value: u16) -> Result { + Ok(itoa::Buffer::new().format(value).to_owned()) + } + + fn serialize_u32(self, value: u32) -> Result { + Ok(itoa::Buffer::new().format(value).to_owned()) + } + + fn serialize_u64(self, value: u64) -> Result { + Ok(itoa::Buffer::new().format(value).to_owned()) + } + + fn serialize_u128(self, value: u128) -> Result { + Ok(itoa::Buffer::new().format(value).to_owned()) + } + + fn serialize_f32(self, value: f32) -> Result { + if value.is_finite() { + Ok(zmij::Buffer::new().format_finite(value).to_owned()) + } else { + Err(float_key_must_be_finite()) + } + } + + fn serialize_f64(self, value: f64) -> Result { + if value.is_finite() { + Ok(zmij::Buffer::new().format_finite(value).to_owned()) + } else { + Err(float_key_must_be_finite()) + } + } + + #[inline] + fn serialize_char(self, value: char) -> Result { + Ok({ + let mut s = String::new(); + s.push(value); + s + }) + } + + #[inline] + fn serialize_str(self, value: &str) -> Result { + Ok(value.to_owned()) + } + + fn serialize_bytes(self, _value: &[u8]) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_unit(self) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result + where + T: ?Sized + Serialize, + { + Err(key_must_be_a_string()) + } + + fn serialize_none(self) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_some(self, _value: &T) -> Result + where + T: ?Sized + Serialize, + { + Err(key_must_be_a_string()) + } + + fn serialize_seq(self, _len: Option) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_tuple(self, _len: usize) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_map(self, _len: Option) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(key_must_be_a_string()) + } + + fn collect_str(self, value: &T) -> Result + where + T: ?Sized + Display, + { + Ok(value.to_string()) + } +} + +impl serde::ser::SerializeStruct for SerializeMap { + type Ok = Value; + type Error = Error; + + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + match self { + SerializeMap::Map { .. } => serde::ser::SerializeMap::serialize_entry(self, key, value), + #[cfg(feature = "arbitrary_precision")] + SerializeMap::Number { out_value } => { + if key == crate::number::TOKEN { + *out_value = Some(tri!(value.serialize(NumberValueEmitter))); + Ok(()) + } else { + Err(invalid_number()) + } + } + #[cfg(feature = "raw_value")] + SerializeMap::RawValue { out_value } => { + if key == crate::raw::TOKEN { + *out_value = Some(tri!(value.serialize(RawValueEmitter))); + Ok(()) + } else { + Err(invalid_raw_value()) + } + } + } + } + + fn end(self) -> Result { + match self { + SerializeMap::Map { .. } => serde::ser::SerializeMap::end(self), + #[cfg(feature = "arbitrary_precision")] + SerializeMap::Number { out_value, .. } => { + Ok(out_value.expect("number value was not emitted")) + } + #[cfg(feature = "raw_value")] + SerializeMap::RawValue { out_value, .. } => { + Ok(out_value.expect("raw value was not emitted")) + } + } + } +} + +impl serde::ser::SerializeStructVariant for SerializeStructVariant { + type Ok = Value; + type Error = Error; + + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + self.map.insert(String::from(key), tri!(to_value(value))); + Ok(()) + } + + fn end(self) -> Result { + let mut object = Map::new(); + + object.insert(self.name, Value::Object(self.map)); + + Ok(Value::Object(object)) + } +} + +#[cfg(feature = "arbitrary_precision")] +struct NumberValueEmitter; + +#[cfg(feature = "arbitrary_precision")] +fn invalid_number() -> Error { + Error::syntax(ErrorCode::InvalidNumber, 0, 0) +} + +#[cfg(feature = "arbitrary_precision")] +impl serde::ser::Serializer for NumberValueEmitter { + type Ok = Value; + type Error = Error; + + type SerializeSeq = Impossible; + type SerializeTuple = Impossible; + type SerializeTupleStruct = Impossible; + type SerializeTupleVariant = Impossible; + type SerializeMap = Impossible; + type SerializeStruct = Impossible; + type SerializeStructVariant = Impossible; + + fn serialize_bool(self, _v: bool) -> Result { + Err(invalid_number()) + } + + fn serialize_i8(self, _v: i8) -> Result { + Err(invalid_number()) + } + + fn serialize_i16(self, _v: i16) -> Result { + Err(invalid_number()) + } + + fn serialize_i32(self, _v: i32) -> Result { + Err(invalid_number()) + } + + fn serialize_i64(self, _v: i64) -> Result { + Err(invalid_number()) + } + + fn serialize_u8(self, _v: u8) -> Result { + Err(invalid_number()) + } + + fn serialize_u16(self, _v: u16) -> Result { + Err(invalid_number()) + } + + fn serialize_u32(self, _v: u32) -> Result { + Err(invalid_number()) + } + + fn serialize_u64(self, _v: u64) -> Result { + Err(invalid_number()) + } + + fn serialize_f32(self, _v: f32) -> Result { + Err(invalid_number()) + } + + fn serialize_f64(self, _v: f64) -> Result { + Err(invalid_number()) + } + + fn serialize_char(self, _v: char) -> Result { + Err(invalid_number()) + } + + fn serialize_str(self, value: &str) -> Result { + let n = tri!(value.to_owned().parse()); + Ok(Value::Number(n)) + } + + fn serialize_bytes(self, _value: &[u8]) -> Result { + Err(invalid_number()) + } + + fn serialize_none(self) -> Result { + Err(invalid_number()) + } + + fn serialize_some(self, _value: &T) -> Result + where + T: ?Sized + Serialize, + { + Err(invalid_number()) + } + + fn serialize_unit(self) -> Result { + Err(invalid_number()) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result { + Err(invalid_number()) + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + ) -> Result { + Err(invalid_number()) + } + + fn serialize_newtype_struct(self, _name: &'static str, _value: &T) -> Result + where + T: ?Sized + Serialize, + { + Err(invalid_number()) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result + where + T: ?Sized + Serialize, + { + Err(invalid_number()) + } + + fn serialize_seq(self, _len: Option) -> Result { + Err(invalid_number()) + } + + fn serialize_tuple(self, _len: usize) -> Result { + Err(invalid_number()) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + Err(invalid_number()) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(invalid_number()) + } + + fn serialize_map(self, _len: Option) -> Result { + Err(invalid_number()) + } + + fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { + Err(invalid_number()) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(invalid_number()) + } +} + +#[cfg(feature = "raw_value")] +struct RawValueEmitter; + +#[cfg(feature = "raw_value")] +fn invalid_raw_value() -> Error { + Error::syntax(ErrorCode::ExpectedSomeValue, 0, 0) +} + +#[cfg(feature = "raw_value")] +impl serde::ser::Serializer for RawValueEmitter { + type Ok = Value; + type Error = Error; + + type SerializeSeq = Impossible; + type SerializeTuple = Impossible; + type SerializeTupleStruct = Impossible; + type SerializeTupleVariant = Impossible; + type SerializeMap = Impossible; + type SerializeStruct = Impossible; + type SerializeStructVariant = Impossible; + + fn serialize_bool(self, _v: bool) -> Result { + Err(invalid_raw_value()) + } + + fn serialize_i8(self, _v: i8) -> Result { + Err(invalid_raw_value()) + } + + fn serialize_i16(self, _v: i16) -> Result { + Err(invalid_raw_value()) + } + + fn serialize_i32(self, _v: i32) -> Result { + Err(invalid_raw_value()) + } + + fn serialize_i64(self, _v: i64) -> Result { + Err(invalid_raw_value()) + } + + fn serialize_u8(self, _v: u8) -> Result { + Err(invalid_raw_value()) + } + + fn serialize_u16(self, _v: u16) -> Result { + Err(invalid_raw_value()) + } + + fn serialize_u32(self, _v: u32) -> Result { + Err(invalid_raw_value()) + } + + fn serialize_u64(self, _v: u64) -> Result { + Err(invalid_raw_value()) + } + + fn serialize_f32(self, _v: f32) -> Result { + Err(invalid_raw_value()) + } + + fn serialize_f64(self, _v: f64) -> Result { + Err(invalid_raw_value()) + } + + fn serialize_char(self, _v: char) -> Result { + Err(invalid_raw_value()) + } + + fn serialize_str(self, value: &str) -> Result { + crate::from_str(value) + } + + fn serialize_bytes(self, _value: &[u8]) -> Result { + Err(invalid_raw_value()) + } + + fn serialize_none(self) -> Result { + Err(invalid_raw_value()) + } + + fn serialize_some(self, _value: &T) -> Result + where + T: ?Sized + Serialize, + { + Err(invalid_raw_value()) + } + + fn serialize_unit(self) -> Result { + Err(invalid_raw_value()) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result { + Err(invalid_raw_value()) + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + ) -> Result { + Err(invalid_raw_value()) + } + + fn serialize_newtype_struct(self, _name: &'static str, _value: &T) -> Result + where + T: ?Sized + Serialize, + { + Err(invalid_raw_value()) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result + where + T: ?Sized + Serialize, + { + Err(invalid_raw_value()) + } + + fn serialize_seq(self, _len: Option) -> Result { + Err(invalid_raw_value()) + } + + fn serialize_tuple(self, _len: usize) -> Result { + Err(invalid_raw_value()) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + Err(invalid_raw_value()) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(invalid_raw_value()) + } + + fn serialize_map(self, _len: Option) -> Result { + Err(invalid_raw_value()) + } + + fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { + Err(invalid_raw_value()) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(invalid_raw_value()) + } + + fn collect_str(self, value: &T) -> Result + where + T: ?Sized + Display, + { + self.serialize_str(&value.to_string()) + } +} diff --git a/third_party/crates/serde_json-1.0.151/tests/compiletest.rs b/third_party/crates/serde_json-1.0.151/tests/compiletest.rs new file mode 100644 index 0000000..23a6a06 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/compiletest.rs @@ -0,0 +1,7 @@ +#[rustversion::attr(not(nightly), ignore = "requires nightly")] +#[cfg_attr(miri, ignore = "incompatible with miri")] +#[test] +fn ui() { + let t = trybuild::TestCases::new(); + t.compile_fail("tests/ui/*.rs"); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/debug.rs b/third_party/crates/serde_json-1.0.151/tests/debug.rs new file mode 100644 index 0000000..b804d8d --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/debug.rs @@ -0,0 +1,83 @@ +#![allow(clippy::uninlined_format_args)] + +use indoc::indoc; +use serde_json::{json, Number, Value}; + +#[test] +fn number() { + assert_eq!(format!("{:?}", Number::from(1)), "Number(1)"); + assert_eq!(format!("{:?}", Number::from(-1)), "Number(-1)"); + assert_eq!( + format!("{:?}", Number::from_f64(1.0).unwrap()), + "Number(1.0)" + ); +} + +#[test] +fn value_null() { + assert_eq!(format!("{:?}", json!(null)), "Null"); +} + +#[test] +fn value_bool() { + assert_eq!(format!("{:?}", json!(true)), "Bool(true)"); + assert_eq!(format!("{:?}", json!(false)), "Bool(false)"); +} + +#[test] +fn value_number() { + assert_eq!(format!("{:?}", json!(1)), "Number(1)"); + assert_eq!(format!("{:?}", json!(-1)), "Number(-1)"); + assert_eq!(format!("{:?}", json!(1.0)), "Number(1.0)"); + assert_eq!(Number::from_f64(1.0).unwrap().to_string(), "1.0"); // not just "1" + assert_eq!(Number::from_f64(12e40).unwrap().to_string(), "1.2e+41"); +} + +#[test] +fn value_string() { + assert_eq!(format!("{:?}", json!("s")), "String(\"s\")"); +} + +#[test] +fn value_array() { + assert_eq!(format!("{:?}", json!([])), "Array []"); +} + +#[test] +fn value_object() { + assert_eq!(format!("{:?}", json!({})), "Object {}"); +} + +#[test] +fn error() { + let err = serde_json::from_str::("{0}").unwrap_err(); + let expected = "Error(\"key must be a string\", line: 1, column: 2)"; + assert_eq!(format!("{:?}", err), expected); +} + +#[test] +fn indented() { + let j = json!({ + "Array": [true], + "Bool": true, + "EmptyArray": [], + "EmptyObject": {}, + "Null": null, + "Number": 1, + "String": "...", + }); + let expected = indoc! {r#" + Object { + "Array": Array [ + Bool(true), + ], + "Bool": Bool(true), + "EmptyArray": Array [], + "EmptyObject": Object {}, + "Null": Null, + "Number": Number(1), + "String": String("..."), + }"# + }; + assert_eq!(format!("{:#?}", j), expected); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/lexical.rs b/third_party/crates/serde_json-1.0.151/tests/lexical.rs new file mode 100644 index 0000000..7796795 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/lexical.rs @@ -0,0 +1,49 @@ +#![allow( + clippy::cast_lossless, + clippy::cast_possible_truncation, + clippy::cast_possible_wrap, + clippy::cast_precision_loss, + clippy::cast_sign_loss, + clippy::comparison_chain, + clippy::doc_markdown, + clippy::excessive_precision, + clippy::float_cmp, + clippy::if_not_else, + clippy::let_underscore_untyped, + clippy::module_name_repetitions, + clippy::needless_late_init, + clippy::question_mark, + clippy::shadow_unrelated, + clippy::similar_names, + clippy::single_match_else, + clippy::too_many_lines, + clippy::unreadable_literal, + clippy::unseparated_literal_suffix, + clippy::wildcard_imports +)] + +extern crate alloc; + +#[path = "../src/lexical/mod.rs"] +mod lexical; + +#[path = "lexical/algorithm.rs"] +mod algorithm; + +#[path = "lexical/exponent.rs"] +mod exponent; + +#[path = "lexical/float.rs"] +mod float; + +#[path = "lexical/math.rs"] +mod math; + +#[path = "lexical/num.rs"] +mod num; + +#[path = "lexical/parse.rs"] +mod parse; + +#[path = "lexical/rounding.rs"] +mod rounding; diff --git a/third_party/crates/serde_json-1.0.151/tests/lexical/algorithm.rs b/third_party/crates/serde_json-1.0.151/tests/lexical/algorithm.rs new file mode 100644 index 0000000..7f3a2c6 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/lexical/algorithm.rs @@ -0,0 +1,110 @@ +// Adapted from https://github.com/Alexhuszagh/rust-lexical. + +use crate::lexical::algorithm::*; +use crate::lexical::num::Float; + +#[test] +fn float_fast_path_test() { + // valid + let mantissa = (1 << f32::MANTISSA_SIZE) - 1; + let (min_exp, max_exp) = f32::exponent_limit(); + for exp in min_exp..=max_exp { + let f = fast_path::(mantissa, exp); + assert!(f.is_some(), "should be valid {:?}.", (mantissa, exp)); + } + + // Check slightly above valid exponents + let f = fast_path::(123, 15); + assert_eq!(f, Some(1.23e+17)); + + // Exponent is 1 too high, pushes over the mantissa. + let f = fast_path::(123, 16); + assert!(f.is_none()); + + // Mantissa is too large, checked_mul should overflow. + let f = fast_path::(mantissa, 11); + assert!(f.is_none()); + + // invalid exponents + let (min_exp, max_exp) = f32::exponent_limit(); + let f = fast_path::(mantissa, min_exp - 1); + assert!(f.is_none(), "exponent under min_exp"); + + let f = fast_path::(mantissa, max_exp + 1); + assert!(f.is_none(), "exponent above max_exp"); +} + +#[test] +fn double_fast_path_test() { + // valid + let mantissa = (1 << f64::MANTISSA_SIZE) - 1; + let (min_exp, max_exp) = f64::exponent_limit(); + for exp in min_exp..=max_exp { + let f = fast_path::(mantissa, exp); + assert!(f.is_some(), "should be valid {:?}.", (mantissa, exp)); + } + + // invalid exponents + let (min_exp, max_exp) = f64::exponent_limit(); + let f = fast_path::(mantissa, min_exp - 1); + assert!(f.is_none(), "exponent under min_exp"); + + let f = fast_path::(mantissa, max_exp + 1); + assert!(f.is_none(), "exponent above max_exp"); + + assert_eq!( + Some(0.04628372940652459), + fast_path::(4628372940652459, -17) + ); + assert_eq!(None, fast_path::(26383446160308229, -272)); +} + +#[test] +fn moderate_path_test() { + let (f, valid) = moderate_path::(1234567890, -1, false); + assert!(valid, "should be valid"); + assert_eq!(f.into_float::(), 123456789.0); + + let (f, valid) = moderate_path::(1234567891, -1, false); + assert!(valid, "should be valid"); + assert_eq!(f.into_float::(), 123456789.1); + + let (f, valid) = moderate_path::(12345678912, -2, false); + assert!(valid, "should be valid"); + assert_eq!(f.into_float::(), 123456789.12); + + let (f, valid) = moderate_path::(123456789123, -3, false); + assert!(valid, "should be valid"); + assert_eq!(f.into_float::(), 123456789.123); + + let (f, valid) = moderate_path::(1234567891234, -4, false); + assert!(valid, "should be valid"); + assert_eq!(f.into_float::(), 123456789.1234); + + let (f, valid) = moderate_path::(12345678912345, -5, false); + assert!(valid, "should be valid"); + assert_eq!(f.into_float::(), 123456789.12345); + + let (f, valid) = moderate_path::(123456789123456, -6, false); + assert!(valid, "should be valid"); + assert_eq!(f.into_float::(), 123456789.123456); + + let (f, valid) = moderate_path::(1234567891234567, -7, false); + assert!(valid, "should be valid"); + assert_eq!(f.into_float::(), 123456789.1234567); + + let (f, valid) = moderate_path::(12345678912345679, -8, false); + assert!(valid, "should be valid"); + assert_eq!(f.into_float::(), 123456789.12345679); + + let (f, valid) = moderate_path::(4628372940652459, -17, false); + assert!(valid, "should be valid"); + assert_eq!(f.into_float::(), 0.04628372940652459); + + let (f, valid) = moderate_path::(26383446160308229, -272, false); + assert!(valid, "should be valid"); + assert_eq!(f.into_float::(), 2.6383446160308229e-256); + + let (_, valid) = moderate_path::(26383446160308230, -272, false); + assert!(!valid, "should be invalid"); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/lexical/exponent.rs b/third_party/crates/serde_json-1.0.151/tests/lexical/exponent.rs new file mode 100644 index 0000000..c109ff0 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/lexical/exponent.rs @@ -0,0 +1,36 @@ +// Adapted from https://github.com/Alexhuszagh/rust-lexical. + +use crate::lexical::exponent::*; + +#[test] +fn scientific_exponent_test() { + // 0 digits in the integer + assert_eq!(scientific_exponent(0, 0, 5), -6); + assert_eq!(scientific_exponent(10, 0, 5), 4); + assert_eq!(scientific_exponent(-10, 0, 5), -16); + + // >0 digits in the integer + assert_eq!(scientific_exponent(0, 1, 5), 0); + assert_eq!(scientific_exponent(0, 2, 5), 1); + assert_eq!(scientific_exponent(0, 2, 20), 1); + assert_eq!(scientific_exponent(10, 2, 20), 11); + assert_eq!(scientific_exponent(-10, 2, 20), -9); + + // Underflow + assert_eq!(scientific_exponent(i32::MIN, 0, 0), i32::MIN); + assert_eq!(scientific_exponent(i32::MIN, 0, 5), i32::MIN); + + // Overflow + assert_eq!(scientific_exponent(i32::MAX, 0, 0), i32::MAX - 1); + assert_eq!(scientific_exponent(i32::MAX, 5, 0), i32::MAX); +} + +#[test] +fn mantissa_exponent_test() { + assert_eq!(mantissa_exponent(10, 5, 0), 5); + assert_eq!(mantissa_exponent(0, 5, 0), -5); + assert_eq!(mantissa_exponent(i32::MAX, 5, 0), i32::MAX - 5); + assert_eq!(mantissa_exponent(i32::MAX, 0, 5), i32::MAX); + assert_eq!(mantissa_exponent(i32::MIN, 5, 0), i32::MIN); + assert_eq!(mantissa_exponent(i32::MIN, 0, 5), i32::MIN + 5); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/lexical/float.rs b/third_party/crates/serde_json-1.0.151/tests/lexical/float.rs new file mode 100644 index 0000000..c87e7e1 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/lexical/float.rs @@ -0,0 +1,581 @@ +// Adapted from https://github.com/Alexhuszagh/rust-lexical. + +use crate::lexical::float::ExtendedFloat; +use crate::lexical::rounding::round_nearest_tie_even; +use std::{f32, f64}; + +// NORMALIZE + +fn check_normalize(mant: u64, exp: i32, shift: u32, r_mant: u64, r_exp: i32) { + let mut x = ExtendedFloat { mant, exp }; + assert_eq!(x.normalize(), shift); + assert_eq!( + x, + ExtendedFloat { + mant: r_mant, + exp: r_exp + } + ); +} + +#[test] +fn normalize_test() { + // F32 + // 0 + check_normalize(0, 0, 0, 0, 0); + + // min value + check_normalize(1, -149, 63, 9223372036854775808, -212); + + // 1.0e-40 + check_normalize(71362, -149, 47, 10043308644012916736, -196); + + // 1.0e-20 + check_normalize(12379400, -90, 40, 13611294244890214400, -130); + + // 1.0 + check_normalize(8388608, -23, 40, 9223372036854775808, -63); + + // 1e20 + check_normalize(11368684, 43, 40, 12500000250510966784, 3); + + // max value + check_normalize(16777213, 104, 40, 18446740775174668288, 64); + + // F64 + + // min value + check_normalize(1, -1074, 63, 9223372036854775808, -1137); + + // 1.0e-250 + check_normalize(6448907850777164, -883, 11, 13207363278391631872, -894); + + // 1.0e-150 + check_normalize(7371020360979573, -551, 11, 15095849699286165504, -562); + + // 1.0e-45 + check_normalize(6427752177035961, -202, 11, 13164036458569648128, -213); + + // 1.0e-40 + check_normalize(4903985730770844, -185, 11, 10043362776618688512, -196); + + // 1.0e-20 + check_normalize(6646139978924579, -119, 11, 13611294676837537792, -130); + + // 1.0 + check_normalize(4503599627370496, -52, 11, 9223372036854775808, -63); + + // 1e20 + check_normalize(6103515625000000, 14, 11, 12500000000000000000, 3); + + // 1e40 + check_normalize(8271806125530277, 80, 11, 16940658945086007296, 69); + + // 1e150 + check_normalize(5503284107318959, 446, 11, 11270725851789228032, 435); + + // 1e250 + check_normalize(6290184345309700, 778, 11, 12882297539194265600, 767); + + // max value + check_normalize(9007199254740991, 971, 11, 18446744073709549568, 960); +} + +// ROUND + +fn check_round_to_f32(mant: u64, exp: i32, r_mant: u64, r_exp: i32) { + let mut x = ExtendedFloat { mant, exp }; + x.round_to_native::(round_nearest_tie_even); + assert_eq!( + x, + ExtendedFloat { + mant: r_mant, + exp: r_exp + } + ); +} + +#[test] +fn round_to_f32_test() { + // This is lossy, so some of these values are **slightly** rounded. + + // underflow + check_round_to_f32(9223372036854775808, -213, 0, -149); + + // min value + check_round_to_f32(9223372036854775808, -212, 1, -149); + + // 1.0e-40 + check_round_to_f32(10043308644012916736, -196, 71362, -149); + + // 1.0e-20 + check_round_to_f32(13611294244890214400, -130, 12379400, -90); + + // 1.0 + check_round_to_f32(9223372036854775808, -63, 8388608, -23); + + // 1e20 + check_round_to_f32(12500000250510966784, 3, 11368684, 43); + + // max value + check_round_to_f32(18446740775174668288, 64, 16777213, 104); + + // overflow + check_round_to_f32(18446740775174668288, 65, 16777213, 105); +} + +fn check_round_to_f64(mant: u64, exp: i32, r_mant: u64, r_exp: i32) { + let mut x = ExtendedFloat { mant, exp }; + x.round_to_native::(round_nearest_tie_even); + assert_eq!( + x, + ExtendedFloat { + mant: r_mant, + exp: r_exp + } + ); +} + +#[test] +fn round_to_f64_test() { + // This is lossy, so some of these values are **slightly** rounded. + + // underflow + check_round_to_f64(9223372036854775808, -1138, 0, -1074); + + // min value + check_round_to_f64(9223372036854775808, -1137, 1, -1074); + + // 1.0e-250 + check_round_to_f64(15095849699286165504, -562, 7371020360979573, -551); + + // 1.0e-150 + check_round_to_f64(15095849699286165504, -562, 7371020360979573, -551); + + // 1.0e-45 + check_round_to_f64(13164036458569648128, -213, 6427752177035961, -202); + + // 1.0e-40 + check_round_to_f64(10043362776618688512, -196, 4903985730770844, -185); + + // 1.0e-20 + check_round_to_f64(13611294676837537792, -130, 6646139978924579, -119); + + // 1.0 + check_round_to_f64(9223372036854775808, -63, 4503599627370496, -52); + + // 1e20 + check_round_to_f64(12500000000000000000, 3, 6103515625000000, 14); + + // 1e40 + check_round_to_f64(16940658945086007296, 69, 8271806125530277, 80); + + // 1e150 + check_round_to_f64(11270725851789228032, 435, 5503284107318959, 446); + + // 1e250 + check_round_to_f64(12882297539194265600, 767, 6290184345309700, 778); + + // max value + check_round_to_f64(18446744073709549568, 960, 9007199254740991, 971); + + // Bug fixes + // 1.2345e-308 + check_round_to_f64(10234494226754558294, -1086, 2498655817078750, -1074); +} + +fn assert_normalized_eq(mut x: ExtendedFloat, mut y: ExtendedFloat) { + x.normalize(); + y.normalize(); + assert_eq!(x, y); +} + +#[test] +fn from_float() { + let values: [f32; 26] = [ + 1e-40, 2e-40, 1e-35, 2e-35, 1e-30, 2e-30, 1e-25, 2e-25, 1e-20, 2e-20, 1e-15, 2e-15, 1e-10, + 2e-10, 1e-5, 2e-5, 1.0, 2.0, 1e5, 2e5, 1e10, 2e10, 1e15, 2e15, 1e20, 2e20, + ]; + for value in &values { + assert_normalized_eq( + ExtendedFloat::from_float(*value), + ExtendedFloat::from_float(*value as f64), + ); + } +} + +// TO + +// Sample of interesting numbers to check during standard test builds. +const INTEGERS: [u64; 32] = [ + 0, // 0x0 + 1, // 0x1 + 7, // 0x7 + 15, // 0xF + 112, // 0x70 + 119, // 0x77 + 127, // 0x7F + 240, // 0xF0 + 247, // 0xF7 + 255, // 0xFF + 2032, // 0x7F0 + 2039, // 0x7F7 + 2047, // 0x7FF + 4080, // 0xFF0 + 4087, // 0xFF7 + 4095, // 0xFFF + 65520, // 0xFFF0 + 65527, // 0xFFF7 + 65535, // 0xFFFF + 1048560, // 0xFFFF0 + 1048567, // 0xFFFF7 + 1048575, // 0xFFFFF + 16777200, // 0xFFFFF0 + 16777207, // 0xFFFFF7 + 16777215, // 0xFFFFFF + 268435440, // 0xFFFFFF0 + 268435447, // 0xFFFFFF7 + 268435455, // 0xFFFFFFF + 4294967280, // 0xFFFFFFF0 + 4294967287, // 0xFFFFFFF7 + 4294967295, // 0xFFFFFFFF + 18446744073709551615, // 0xFFFFFFFFFFFFFFFF +]; + +#[test] +fn to_f32_test() { + // underflow + let x = ExtendedFloat { + mant: 9223372036854775808, + exp: -213, + }; + assert_eq!(x.into_float::(), 0.0); + + // min value + let x = ExtendedFloat { + mant: 9223372036854775808, + exp: -212, + }; + assert_eq!(x.into_float::(), 1e-45); + + // 1.0e-40 + let x = ExtendedFloat { + mant: 10043308644012916736, + exp: -196, + }; + assert_eq!(x.into_float::(), 1e-40); + + // 1.0e-20 + let x = ExtendedFloat { + mant: 13611294244890214400, + exp: -130, + }; + assert_eq!(x.into_float::(), 1e-20); + + // 1.0 + let x = ExtendedFloat { + mant: 9223372036854775808, + exp: -63, + }; + assert_eq!(x.into_float::(), 1.0); + + // 1e20 + let x = ExtendedFloat { + mant: 12500000250510966784, + exp: 3, + }; + assert_eq!(x.into_float::(), 1e20); + + // max value + let x = ExtendedFloat { + mant: 18446740775174668288, + exp: 64, + }; + assert_eq!(x.into_float::(), 3.402823e38); + + // almost max, high exp + let x = ExtendedFloat { + mant: 1048575, + exp: 108, + }; + assert_eq!(x.into_float::(), 3.4028204e38); + + // max value + 1 + let x = ExtendedFloat { + mant: 16777216, + exp: 104, + }; + assert_eq!(x.into_float::(), f32::INFINITY); + + // max value + 1 + let x = ExtendedFloat { + mant: 1048576, + exp: 108, + }; + assert_eq!(x.into_float::(), f32::INFINITY); + + // 1e40 + let x = ExtendedFloat { + mant: 16940658945086007296, + exp: 69, + }; + assert_eq!(x.into_float::(), f32::INFINITY); + + // Integers. + for int in &INTEGERS { + let fp = ExtendedFloat { mant: *int, exp: 0 }; + assert_eq!(fp.into_float::(), *int as f32, "{:?} as f32", *int); + } +} + +#[test] +fn to_f64_test() { + // underflow + let x = ExtendedFloat { + mant: 9223372036854775808, + exp: -1138, + }; + assert_eq!(x.into_float::(), 0.0); + + // min value + let x = ExtendedFloat { + mant: 9223372036854775808, + exp: -1137, + }; + assert_eq!(x.into_float::(), 5e-324); + + // 1.0e-250 + let x = ExtendedFloat { + mant: 13207363278391631872, + exp: -894, + }; + assert_eq!(x.into_float::(), 1e-250); + + // 1.0e-150 + let x = ExtendedFloat { + mant: 15095849699286165504, + exp: -562, + }; + assert_eq!(x.into_float::(), 1e-150); + + // 1.0e-45 + let x = ExtendedFloat { + mant: 13164036458569648128, + exp: -213, + }; + assert_eq!(x.into_float::(), 1e-45); + + // 1.0e-40 + let x = ExtendedFloat { + mant: 10043362776618688512, + exp: -196, + }; + assert_eq!(x.into_float::(), 1e-40); + + // 1.0e-20 + let x = ExtendedFloat { + mant: 13611294676837537792, + exp: -130, + }; + assert_eq!(x.into_float::(), 1e-20); + + // 1.0 + let x = ExtendedFloat { + mant: 9223372036854775808, + exp: -63, + }; + assert_eq!(x.into_float::(), 1.0); + + // 1e20 + let x = ExtendedFloat { + mant: 12500000000000000000, + exp: 3, + }; + assert_eq!(x.into_float::(), 1e20); + + // 1e40 + let x = ExtendedFloat { + mant: 16940658945086007296, + exp: 69, + }; + assert_eq!(x.into_float::(), 1e40); + + // 1e150 + let x = ExtendedFloat { + mant: 11270725851789228032, + exp: 435, + }; + assert_eq!(x.into_float::(), 1e150); + + // 1e250 + let x = ExtendedFloat { + mant: 12882297539194265600, + exp: 767, + }; + assert_eq!(x.into_float::(), 1e250); + + // max value + let x = ExtendedFloat { + mant: 9007199254740991, + exp: 971, + }; + assert_eq!(x.into_float::(), 1.7976931348623157e308); + + // max value + let x = ExtendedFloat { + mant: 18446744073709549568, + exp: 960, + }; + assert_eq!(x.into_float::(), 1.7976931348623157e308); + + // overflow + let x = ExtendedFloat { + mant: 9007199254740992, + exp: 971, + }; + assert_eq!(x.into_float::(), f64::INFINITY); + + // overflow + let x = ExtendedFloat { + mant: 18446744073709549568, + exp: 961, + }; + assert_eq!(x.into_float::(), f64::INFINITY); + + // Underflow + // Adapted from failures in strtod. + let x = ExtendedFloat { + exp: -1139, + mant: 18446744073709550712, + }; + assert_eq!(x.into_float::(), 0.0); + + let x = ExtendedFloat { + exp: -1139, + mant: 18446744073709551460, + }; + assert_eq!(x.into_float::(), 0.0); + + let x = ExtendedFloat { + exp: -1138, + mant: 9223372036854776103, + }; + assert_eq!(x.into_float::(), 5e-324); + + // Integers. + for int in &INTEGERS { + let fp = ExtendedFloat { mant: *int, exp: 0 }; + assert_eq!(fp.into_float::(), *int as f64, "{:?} as f64", *int); + } +} + +// OPERATIONS + +fn check_mul(a: ExtendedFloat, b: ExtendedFloat, c: ExtendedFloat) { + let r = a.mul(&b); + assert_eq!(r, c); +} + +#[test] +fn mul_test() { + // Normalized (64-bit mantissa) + let a = ExtendedFloat { + mant: 13164036458569648128, + exp: -213, + }; + let b = ExtendedFloat { + mant: 9223372036854775808, + exp: -62, + }; + let c = ExtendedFloat { + mant: 6582018229284824064, + exp: -211, + }; + check_mul(a, b, c); + + // Check with integers + // 64-bit mantissa + let mut a = ExtendedFloat { mant: 10, exp: 0 }; + let mut b = ExtendedFloat { mant: 10, exp: 0 }; + a.normalize(); + b.normalize(); + assert_eq!(a.mul(&b).into_float::(), 100.0); + + // Check both values need high bits set. + let a = ExtendedFloat { + mant: 1 << 32, + exp: -31, + }; + let b = ExtendedFloat { + mant: 1 << 32, + exp: -31, + }; + assert_eq!(a.mul(&b).into_float::(), 4.0); + + // Check both values need high bits set. + let a = ExtendedFloat { + mant: 10 << 31, + exp: -31, + }; + let b = ExtendedFloat { + mant: 10 << 31, + exp: -31, + }; + assert_eq!(a.mul(&b).into_float::(), 100.0); +} + +fn check_imul(mut a: ExtendedFloat, b: ExtendedFloat, c: ExtendedFloat) { + a.imul(&b); + assert_eq!(a, c); +} + +#[test] +fn imul_test() { + // Normalized (64-bit mantissa) + let a = ExtendedFloat { + mant: 13164036458569648128, + exp: -213, + }; + let b = ExtendedFloat { + mant: 9223372036854775808, + exp: -62, + }; + let c = ExtendedFloat { + mant: 6582018229284824064, + exp: -211, + }; + check_imul(a, b, c); + + // Check with integers + // 64-bit mantissa + let mut a = ExtendedFloat { mant: 10, exp: 0 }; + let mut b = ExtendedFloat { mant: 10, exp: 0 }; + a.normalize(); + b.normalize(); + a.imul(&b); + assert_eq!(a.into_float::(), 100.0); + + // Check both values need high bits set. + let mut a = ExtendedFloat { + mant: 1 << 32, + exp: -31, + }; + let b = ExtendedFloat { + mant: 1 << 32, + exp: -31, + }; + a.imul(&b); + assert_eq!(a.into_float::(), 4.0); + + // Check both values need high bits set. + let mut a = ExtendedFloat { + mant: 10 << 31, + exp: -31, + }; + let b = ExtendedFloat { + mant: 10 << 31, + exp: -31, + }; + a.imul(&b); + assert_eq!(a.into_float::(), 100.0); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/lexical/math.rs b/third_party/crates/serde_json-1.0.151/tests/lexical/math.rs new file mode 100644 index 0000000..454eaa6 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/lexical/math.rs @@ -0,0 +1,211 @@ +// Adapted from https://github.com/Alexhuszagh/rust-lexical. + +use crate::lexical::math::{Limb, Math}; +use std::cmp; + +#[derive(Clone, Default)] +struct Bigint { + data: Vec, +} + +impl Math for Bigint { + fn data(&self) -> &Vec { + &self.data + } + + fn data_mut(&mut self) -> &mut Vec { + &mut self.data + } +} + +#[cfg(fast_arithmetic = "32")] +pub(crate) fn from_u32(x: &[u32]) -> Vec { + x.iter().cloned().collect() +} + +#[cfg(fast_arithmetic = "64")] +pub(crate) fn from_u32(x: &[u32]) -> Vec { + let mut v = Vec::::default(); + for xi in x.chunks(2) { + match xi.len() { + 1 => v.push(xi[0] as u64), + 2 => v.push(((xi[1] as u64) << 32) | (xi[0] as u64)), + _ => unreachable!(), + } + } + + v +} + +#[test] +fn compare_test() { + // Simple + let x = Bigint { + data: from_u32(&[1]), + }; + let y = Bigint { + data: from_u32(&[2]), + }; + assert_eq!(x.compare(&y), cmp::Ordering::Less); + assert_eq!(x.compare(&x), cmp::Ordering::Equal); + assert_eq!(y.compare(&x), cmp::Ordering::Greater); + + // Check asymmetric + let x = Bigint { + data: from_u32(&[5, 1]), + }; + let y = Bigint { + data: from_u32(&[2]), + }; + assert_eq!(x.compare(&y), cmp::Ordering::Greater); + assert_eq!(x.compare(&x), cmp::Ordering::Equal); + assert_eq!(y.compare(&x), cmp::Ordering::Less); + + // Check when we use reverse ordering properly. + let x = Bigint { + data: from_u32(&[5, 1, 9]), + }; + let y = Bigint { + data: from_u32(&[6, 2, 8]), + }; + assert_eq!(x.compare(&y), cmp::Ordering::Greater); + assert_eq!(x.compare(&x), cmp::Ordering::Equal); + assert_eq!(y.compare(&x), cmp::Ordering::Less); + + // Complex scenario, check it properly uses reverse ordering. + let x = Bigint { + data: from_u32(&[0, 1, 9]), + }; + let y = Bigint { + data: from_u32(&[4294967295, 0, 9]), + }; + assert_eq!(x.compare(&y), cmp::Ordering::Greater); + assert_eq!(x.compare(&x), cmp::Ordering::Equal); + assert_eq!(y.compare(&x), cmp::Ordering::Less); +} + +#[test] +fn hi64_test() { + assert_eq!(Bigint::from_u64(0xA).hi64(), (0xA000000000000000, false)); + assert_eq!(Bigint::from_u64(0xAB).hi64(), (0xAB00000000000000, false)); + assert_eq!( + Bigint::from_u64(0xAB00000000).hi64(), + (0xAB00000000000000, false) + ); + assert_eq!( + Bigint::from_u64(0xA23456789A).hi64(), + (0xA23456789A000000, false) + ); +} + +#[test] +fn bit_length_test() { + let x = Bigint { + data: from_u32(&[0, 0, 0, 1]), + }; + assert_eq!(x.bit_length(), 97); + + let x = Bigint { + data: from_u32(&[0, 0, 0, 3]), + }; + assert_eq!(x.bit_length(), 98); + + let x = Bigint { + data: from_u32(&[1 << 31]), + }; + assert_eq!(x.bit_length(), 32); +} + +#[test] +fn iadd_small_test() { + // Overflow check (single) + // This should set all the internal data values to 0, the top + // value to (1<<31), and the bottom value to (4>>1). + // This is because the max_value + 1 leads to all 0s, we set the + // topmost bit to 1. + let mut x = Bigint { + data: from_u32(&[4294967295]), + }; + x.iadd_small(5); + assert_eq!(x.data, from_u32(&[4, 1])); + + // No overflow, single value + let mut x = Bigint { + data: from_u32(&[5]), + }; + x.iadd_small(7); + assert_eq!(x.data, from_u32(&[12])); + + // Single carry, internal overflow + let mut x = Bigint::from_u64(0x80000000FFFFFFFF); + x.iadd_small(7); + assert_eq!(x.data, from_u32(&[6, 0x80000001])); + + // Double carry, overflow + let mut x = Bigint::from_u64(0xFFFFFFFFFFFFFFFF); + x.iadd_small(7); + assert_eq!(x.data, from_u32(&[6, 0, 1])); +} + +#[test] +fn imul_small_test() { + // No overflow check, 1-int. + let mut x = Bigint { + data: from_u32(&[5]), + }; + x.imul_small(7); + assert_eq!(x.data, from_u32(&[35])); + + // No overflow check, 2-ints. + let mut x = Bigint::from_u64(0x4000000040000); + x.imul_small(5); + assert_eq!(x.data, from_u32(&[0x00140000, 0x140000])); + + // Overflow, 1 carry. + let mut x = Bigint { + data: from_u32(&[0x33333334]), + }; + x.imul_small(5); + assert_eq!(x.data, from_u32(&[4, 1])); + + // Overflow, 1 carry, internal. + let mut x = Bigint::from_u64(0x133333334); + x.imul_small(5); + assert_eq!(x.data, from_u32(&[4, 6])); + + // Overflow, 2 carries. + let mut x = Bigint::from_u64(0x3333333333333334); + x.imul_small(5); + assert_eq!(x.data, from_u32(&[4, 0, 1])); +} + +#[test] +fn shl_test() { + // Pattern generated via `''.join(["1" +"0"*i for i in range(20)])` + let mut big = Bigint { + data: from_u32(&[0xD2210408]), + }; + big.ishl(5); + assert_eq!(big.data, from_u32(&[0x44208100, 0x1A])); + big.ishl(32); + assert_eq!(big.data, from_u32(&[0, 0x44208100, 0x1A])); + big.ishl(27); + assert_eq!(big.data, from_u32(&[0, 0, 0xD2210408])); + + // 96-bits of previous pattern + let mut big = Bigint { + data: from_u32(&[0x20020010, 0x8040100, 0xD2210408]), + }; + big.ishl(5); + assert_eq!(big.data, from_u32(&[0x400200, 0x802004, 0x44208101, 0x1A])); + big.ishl(32); + assert_eq!( + big.data, + from_u32(&[0, 0x400200, 0x802004, 0x44208101, 0x1A]) + ); + big.ishl(27); + assert_eq!( + big.data, + from_u32(&[0, 0, 0x20020010, 0x8040100, 0xD2210408]) + ); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/lexical/num.rs b/third_party/crates/serde_json-1.0.151/tests/lexical/num.rs new file mode 100644 index 0000000..e7d0865 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/lexical/num.rs @@ -0,0 +1,75 @@ +// Adapted from https://github.com/Alexhuszagh/rust-lexical. + +use crate::lexical::num::{AsPrimitive, Float, Integer, Number}; + +fn check_as_primitive(t: T) { + let _: u32 = t.as_u32(); + let _: u64 = t.as_u64(); + let _: u128 = t.as_u128(); + let _: usize = t.as_usize(); + let _: f32 = t.as_f32(); + let _: f64 = t.as_f64(); +} + +#[test] +fn as_primitive_test() { + check_as_primitive(1u32); + check_as_primitive(1u64); + check_as_primitive(1u128); + check_as_primitive(1usize); + check_as_primitive(1f32); + check_as_primitive(1f64); +} + +fn check_number(x: T, y: T) { + // Copy, partialeq, partialord + let _ = x; + assert!(x < y); + assert!(x != y); + + // Operations + let _ = y + x; + + // Conversions already tested. +} + +#[test] +fn number_test() { + check_number(1u32, 5); + check_number(1u64, 5); + check_number(1u128, 5); + check_number(1usize, 5); + check_number(1f32, 5.0); + check_number(1f64, 5.0); +} + +fn check_integer(x: T) { + // Bitwise operations + let _ = x & T::ZERO; +} + +#[test] +fn integer_test() { + check_integer(65u32); + check_integer(65u64); + check_integer(65u128); + check_integer(65usize); +} + +fn check_float(x: T) { + // Check functions + let _ = x.pow10(5); + let _ = x.to_bits(); + assert!(T::from_bits(x.to_bits()) == x); + + // Check properties + let _ = x.to_bits() & T::EXPONENT_MASK; + let _ = x.to_bits() & T::HIDDEN_BIT_MASK; + let _ = x.to_bits() & T::MANTISSA_MASK; +} + +#[test] +fn float_test() { + check_float(123f32); + check_float(123f64); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/lexical/parse.rs b/third_party/crates/serde_json-1.0.151/tests/lexical/parse.rs new file mode 100644 index 0000000..03ec1a9 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/lexical/parse.rs @@ -0,0 +1,204 @@ +// Adapted from https://github.com/Alexhuszagh/rust-lexical. + +use crate::lexical::num::Float; +use crate::lexical::{parse_concise_float, parse_truncated_float}; +use core::f64; +use core::fmt::Debug; + +fn check_concise_float(mantissa: u64, exponent: i32, expected: F) +where + F: Float + Debug, +{ + assert_eq!(parse_concise_float::(mantissa, exponent), expected); +} + +fn check_truncated_float(integer: &str, fraction: &str, exponent: i32, expected: F) +where + F: Float + Debug, +{ + let integer = integer.as_bytes(); + let fraction = fraction.as_bytes(); + assert_eq!( + parse_truncated_float::(integer, fraction, exponent), + expected, + ); +} + +#[test] +fn parse_f32_test() { + check_concise_float(0, 0, 0.0_f32); + check_concise_float(12345, -4, 1.2345_f32); + check_concise_float(12345, -3, 12.345_f32); + check_concise_float(123456789, -4, 12345.6789_f32); + check_concise_float(12345, 6, 1.2345e10_f32); + check_concise_float(12345, -42, 1.2345e-38_f32); + + // Check expected rounding, using borderline cases. + // Round-down, halfway + check_concise_float(16777216, 0, 16777216.0_f32); + check_concise_float(16777217, 0, 16777216.0_f32); + check_concise_float(16777218, 0, 16777218.0_f32); + check_concise_float(33554432, 0, 33554432.0_f32); + check_concise_float(33554434, 0, 33554432.0_f32); + check_concise_float(33554436, 0, 33554436.0_f32); + check_concise_float(17179869184, 0, 17179869184.0_f32); + check_concise_float(17179870208, 0, 17179869184.0_f32); + check_concise_float(17179871232, 0, 17179871232.0_f32); + + // Round-up, halfway + check_concise_float(16777218, 0, 16777218.0_f32); + check_concise_float(16777219, 0, 16777220.0_f32); + check_concise_float(16777220, 0, 16777220.0_f32); + + check_concise_float(33554436, 0, 33554436.0_f32); + check_concise_float(33554438, 0, 33554440.0_f32); + check_concise_float(33554440, 0, 33554440.0_f32); + + check_concise_float(17179871232, 0, 17179871232.0_f32); + check_concise_float(17179872256, 0, 17179873280.0_f32); + check_concise_float(17179873280, 0, 17179873280.0_f32); + + // Round-up, above halfway + check_concise_float(33554435, 0, 33554436.0_f32); + check_concise_float(17179870209, 0, 17179871232.0_f32); + + // Check exactly halfway, round-up at halfway + check_truncated_float("1", "00000017881393432617187499", 0, 1.0000001_f32); + check_truncated_float("1", "000000178813934326171875", 0, 1.0000002_f32); + check_truncated_float("1", "00000017881393432617187501", 0, 1.0000002_f32); +} + +#[test] +fn parse_f64_test() { + check_concise_float(0, 0, 0.0_f64); + check_concise_float(12345, -4, 1.2345_f64); + check_concise_float(12345, -3, 12.345_f64); + check_concise_float(123456789, -4, 12345.6789_f64); + check_concise_float(12345, 6, 1.2345e10_f64); + check_concise_float(12345, -312, 1.2345e-308_f64); + + // Check expected rounding, using borderline cases. + // Round-down, halfway + check_concise_float(9007199254740992, 0, 9007199254740992.0_f64); + check_concise_float(9007199254740993, 0, 9007199254740992.0_f64); + check_concise_float(9007199254740994, 0, 9007199254740994.0_f64); + + check_concise_float(18014398509481984, 0, 18014398509481984.0_f64); + check_concise_float(18014398509481986, 0, 18014398509481984.0_f64); + check_concise_float(18014398509481988, 0, 18014398509481988.0_f64); + + check_concise_float(9223372036854775808, 0, 9223372036854775808.0_f64); + check_concise_float(9223372036854776832, 0, 9223372036854775808.0_f64); + check_concise_float(9223372036854777856, 0, 9223372036854777856.0_f64); + + check_truncated_float( + "11417981541647679048466287755595961091061972992", + "", + 0, + 11417981541647679048466287755595961091061972992.0_f64, + ); + check_truncated_float( + "11417981541647680316116887983825362587765178368", + "", + 0, + 11417981541647679048466287755595961091061972992.0_f64, + ); + check_truncated_float( + "11417981541647681583767488212054764084468383744", + "", + 0, + 11417981541647681583767488212054764084468383744.0_f64, + ); + + // Round-up, halfway + check_concise_float(9007199254740994, 0, 9007199254740994.0_f64); + check_concise_float(9007199254740995, 0, 9007199254740996.0_f64); + check_concise_float(9007199254740996, 0, 9007199254740996.0_f64); + + check_concise_float(18014398509481988, 0, 18014398509481988.0_f64); + check_concise_float(18014398509481990, 0, 18014398509481992.0_f64); + check_concise_float(18014398509481992, 0, 18014398509481992.0_f64); + + check_concise_float(9223372036854777856, 0, 9223372036854777856.0_f64); + check_concise_float(9223372036854778880, 0, 9223372036854779904.0_f64); + check_concise_float(9223372036854779904, 0, 9223372036854779904.0_f64); + + check_truncated_float( + "11417981541647681583767488212054764084468383744", + "", + 0, + 11417981541647681583767488212054764084468383744.0_f64, + ); + check_truncated_float( + "11417981541647682851418088440284165581171589120", + "", + 0, + 11417981541647684119068688668513567077874794496.0_f64, + ); + check_truncated_float( + "11417981541647684119068688668513567077874794496", + "", + 0, + 11417981541647684119068688668513567077874794496.0_f64, + ); + + // Round-up, above halfway + check_concise_float(9223372036854776833, 0, 9223372036854777856.0_f64); + check_truncated_float( + "11417981541647680316116887983825362587765178369", + "", + 0, + 11417981541647681583767488212054764084468383744.0_f64, + ); + + // Rounding error + // Adapted from failures in strtod. + check_concise_float(22250738585072014, -324, 2.2250738585072014e-308_f64); + check_truncated_float("2", "2250738585072011360574097967091319759348195463516456480234261097248222220210769455165295239081350879141491589130396211068700864386945946455276572074078206217433799881410632673292535522868813721490129811224514518898490572223072852551331557550159143974763979834118019993239625482890171070818506906306666559949382757725720157630626906633326475653000092458883164330377797918696120494973903778297049050510806099407302629371289589500035837999672072543043602840788957717961509455167482434710307026091446215722898802581825451803257070188608721131280795122334262883686223215037756666225039825343359745688844239002654981983854879482922068947216898310996983658468140228542433306603398508864458040010349339704275671864433837704860378616227717385456230658746790140867233276367187499", -308, 2.225073858507201e-308_f64); + check_truncated_float("2", "22507385850720113605740979670913197593481954635164564802342610972482222202107694551652952390813508791414915891303962110687008643869459464552765720740782062174337998814106326732925355228688137214901298112245145188984905722230728525513315575501591439747639798341180199932396254828901710708185069063066665599493827577257201576306269066333264756530000924588831643303777979186961204949739037782970490505108060994073026293712895895000358379996720725430436028407889577179615094551674824347103070260914462157228988025818254518032570701886087211312807951223342628836862232150377566662250398253433597456888442390026549819838548794829220689472168983109969836584681402285424333066033985088644580400103493397042756718644338377048603786162277173854562306587467901408672332763671875", -308, 2.2250738585072014e-308_f64); + check_truncated_float("2", "2250738585072011360574097967091319759348195463516456480234261097248222220210769455165295239081350879141491589130396211068700864386945946455276572074078206217433799881410632673292535522868813721490129811224514518898490572223072852551331557550159143974763979834118019993239625482890171070818506906306666559949382757725720157630626906633326475653000092458883164330377797918696120494973903778297049050510806099407302629371289589500035837999672072543043602840788957717961509455167482434710307026091446215722898802581825451803257070188608721131280795122334262883686223215037756666225039825343359745688844239002654981983854879482922068947216898310996983658468140228542433306603398508864458040010349339704275671864433837704860378616227717385456230658746790140867233276367187501", -308, 2.2250738585072014e-308_f64); + check_truncated_float("179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791", "9999999999999999999999999999999999999999999999999999999999999999999999", 0, 1.7976931348623157e+308_f64); + check_truncated_float("7", "4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984374999", -324, 5.0e-324_f64); + check_truncated_float("7", "4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375", -324, 1.0e-323_f64); + check_truncated_float("7", "4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375001", -324, 1.0e-323_f64); + check_truncated_float("", "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125", 0, 0.0_f64); + + // Rounding error + // Adapted from: + // https://www.exploringbinary.com/how-glibc-strtod-works/ + check_truncated_float("", "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072008890245868760858598876504231122409594654935248025624400092282356951787758888037591552642309780950434312085877387158357291821993020294379224223559819827501242041788969571311791082261043971979604000454897391938079198936081525613113376149842043271751033627391549782731594143828136275113838604094249464942286316695429105080201815926642134996606517803095075913058719846423906068637102005108723282784678843631944515866135041223479014792369585208321597621066375401613736583044193603714778355306682834535634005074073040135602968046375918583163124224521599262546494300836851861719422417646455137135420132217031370496583210154654068035397417906022589503023501937519773030945763173210852507299305089761582519159720757232455434770912461317493580281734466552734375", 0, 2.2250738585072011e-308_f64); + + // Rounding error + // Adapted from test-parse-random failures. + check_concise_float(1009, -31, 1.009e-28_f64); + check_concise_float(18294, 304, f64::INFINITY); + + // Rounding error + // Adapted from a @dangrabcad's issue #20. + check_concise_float(7689539722041643, 149, 7.689539722041643e164_f64); + check_truncated_float("768953972204164300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "", 0, 7.689539722041643e164_f64); + check_truncated_float("768953972204164300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0", 0, 7.689539722041643e164_f64); + + // Check other cases similar to @dangrabcad's issue #20. + check_truncated_float("9223372036854776833", "0", 0, 9223372036854777856.0_f64); + check_truncated_float( + "11417981541647680316116887983825362587765178369", + "0", + 0, + 11417981541647681583767488212054764084468383744.0_f64, + ); + check_concise_float(90071992547409950, -1, 9007199254740996.0_f64); + check_concise_float(180143985094819900, -1, 18014398509481992.0_f64); + check_truncated_float("9223372036854778880", "0", 0, 9223372036854779904.0_f64); + check_truncated_float( + "11417981541647682851418088440284165581171589120", + "0", + 0, + 11417981541647684119068688668513567077874794496.0_f64, + ); + + // Check other cases ostensibly identified via proptest. + check_truncated_float("71610528364411830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0", 0, 71610528364411830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0_f64); + check_truncated_float("126769393745745060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0", 0, 126769393745745060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0_f64); + check_truncated_float("38652960461239320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0", 0, 38652960461239320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0_f64); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/lexical/rounding.rs b/third_party/crates/serde_json-1.0.151/tests/lexical/rounding.rs new file mode 100644 index 0000000..7ea1771 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/lexical/rounding.rs @@ -0,0 +1,316 @@ +// Adapted from https://github.com/Alexhuszagh/rust-lexical. + +use crate::lexical::float::ExtendedFloat; +use crate::lexical::num::Float; +use crate::lexical::rounding::*; + +// MASKS + +#[test] +fn lower_n_mask_test() { + assert_eq!(lower_n_mask(0u64), 0b0); + assert_eq!(lower_n_mask(1u64), 0b1); + assert_eq!(lower_n_mask(2u64), 0b11); + assert_eq!(lower_n_mask(10u64), 0b1111111111); + assert_eq!(lower_n_mask(32u64), 0b11111111111111111111111111111111); +} + +#[test] +fn lower_n_halfway_test() { + assert_eq!(lower_n_halfway(0u64), 0b0); + assert_eq!(lower_n_halfway(1u64), 0b1); + assert_eq!(lower_n_halfway(2u64), 0b10); + assert_eq!(lower_n_halfway(10u64), 0b1000000000); + assert_eq!(lower_n_halfway(32u64), 0b10000000000000000000000000000000); +} + +#[test] +fn nth_bit_test() { + assert_eq!(nth_bit(0u64), 0b1); + assert_eq!(nth_bit(1u64), 0b10); + assert_eq!(nth_bit(2u64), 0b100); + assert_eq!(nth_bit(10u64), 0b10000000000); + assert_eq!(nth_bit(31u64), 0b10000000000000000000000000000000); +} + +#[test] +fn internal_n_mask_test() { + assert_eq!(internal_n_mask(1u64, 0u64), 0b0); + assert_eq!(internal_n_mask(1u64, 1u64), 0b1); + assert_eq!(internal_n_mask(2u64, 1u64), 0b10); + assert_eq!(internal_n_mask(4u64, 2u64), 0b1100); + assert_eq!(internal_n_mask(10u64, 2u64), 0b1100000000); + assert_eq!(internal_n_mask(10u64, 4u64), 0b1111000000); + assert_eq!( + internal_n_mask(32u64, 4u64), + 0b11110000000000000000000000000000 + ); +} + +// NEAREST ROUNDING + +#[test] +fn round_nearest_test() { + // Check exactly halfway (b'1100000') + let mut fp = ExtendedFloat { mant: 0x60, exp: 0 }; + let (above, halfway) = round_nearest(&mut fp, 6); + assert!(!above); + assert!(halfway); + assert_eq!(fp.mant, 1); + + // Check above halfway (b'1100001') + let mut fp = ExtendedFloat { mant: 0x61, exp: 0 }; + let (above, halfway) = round_nearest(&mut fp, 6); + assert!(above); + assert!(!halfway); + assert_eq!(fp.mant, 1); + + // Check below halfway (b'1011111') + let mut fp = ExtendedFloat { mant: 0x5F, exp: 0 }; + let (above, halfway) = round_nearest(&mut fp, 6); + assert!(!above); + assert!(!halfway); + assert_eq!(fp.mant, 1); +} + +// DIRECTED ROUNDING + +#[test] +fn round_downward_test() { + // b0000000 + let mut fp = ExtendedFloat { mant: 0x00, exp: 0 }; + round_downward(&mut fp, 6); + assert_eq!(fp.mant, 0); + + // b1000000 + let mut fp = ExtendedFloat { mant: 0x40, exp: 0 }; + round_downward(&mut fp, 6); + assert_eq!(fp.mant, 1); + + // b1100000 + let mut fp = ExtendedFloat { mant: 0x60, exp: 0 }; + round_downward(&mut fp, 6); + assert_eq!(fp.mant, 1); + + // b1110000 + let mut fp = ExtendedFloat { mant: 0x70, exp: 0 }; + round_downward(&mut fp, 6); + assert_eq!(fp.mant, 1); +} + +#[test] +fn round_nearest_tie_even_test() { + // Check round-up, halfway + let mut fp = ExtendedFloat { mant: 0x60, exp: 0 }; + round_nearest_tie_even(&mut fp, 6); + assert_eq!(fp.mant, 2); + + // Check round-down, halfway + let mut fp = ExtendedFloat { mant: 0x20, exp: 0 }; + round_nearest_tie_even(&mut fp, 6); + assert_eq!(fp.mant, 0); + + // Check round-up, above halfway + let mut fp = ExtendedFloat { mant: 0x61, exp: 0 }; + round_nearest_tie_even(&mut fp, 6); + assert_eq!(fp.mant, 2); + + let mut fp = ExtendedFloat { mant: 0x21, exp: 0 }; + round_nearest_tie_even(&mut fp, 6); + assert_eq!(fp.mant, 1); + + // Check round-down, below halfway + let mut fp = ExtendedFloat { mant: 0x5F, exp: 0 }; + round_nearest_tie_even(&mut fp, 6); + assert_eq!(fp.mant, 1); + + let mut fp = ExtendedFloat { mant: 0x1F, exp: 0 }; + round_nearest_tie_even(&mut fp, 6); + assert_eq!(fp.mant, 0); +} + +// HIGH-LEVEL + +#[test] +fn round_to_float_test() { + // Denormal + let mut fp = ExtendedFloat { + mant: 1 << 63, + exp: f64::DENORMAL_EXPONENT - 15, + }; + round_to_float::(&mut fp, round_nearest_tie_even); + assert_eq!(fp.mant, 1 << 48); + assert_eq!(fp.exp, f64::DENORMAL_EXPONENT); + + // Halfway, round-down (b'1000000000000000000000000000000000000000000000000000010000000000') + let mut fp = ExtendedFloat { + mant: 0x8000000000000400, + exp: -63, + }; + round_to_float::(&mut fp, round_nearest_tie_even); + assert_eq!(fp.mant, 1 << 52); + assert_eq!(fp.exp, -52); + + // Halfway, round-up (b'1000000000000000000000000000000000000000000000000000110000000000') + let mut fp = ExtendedFloat { + mant: 0x8000000000000C00, + exp: -63, + }; + round_to_float::(&mut fp, round_nearest_tie_even); + assert_eq!(fp.mant, (1 << 52) + 2); + assert_eq!(fp.exp, -52); + + // Above halfway + let mut fp = ExtendedFloat { + mant: 0x8000000000000401, + exp: -63, + }; + round_to_float::(&mut fp, round_nearest_tie_even); + assert_eq!(fp.mant, (1 << 52) + 1); + assert_eq!(fp.exp, -52); + + let mut fp = ExtendedFloat { + mant: 0x8000000000000C01, + exp: -63, + }; + round_to_float::(&mut fp, round_nearest_tie_even); + assert_eq!(fp.mant, (1 << 52) + 2); + assert_eq!(fp.exp, -52); + + // Below halfway + let mut fp = ExtendedFloat { + mant: 0x80000000000003FF, + exp: -63, + }; + round_to_float::(&mut fp, round_nearest_tie_even); + assert_eq!(fp.mant, 1 << 52); + assert_eq!(fp.exp, -52); + + let mut fp = ExtendedFloat { + mant: 0x8000000000000BFF, + exp: -63, + }; + round_to_float::(&mut fp, round_nearest_tie_even); + assert_eq!(fp.mant, (1 << 52) + 1); + assert_eq!(fp.exp, -52); +} + +#[test] +fn avoid_overflow_test() { + // Avoid overflow, fails by 1 + let mut fp = ExtendedFloat { + mant: 0xFFFFFFFFFFFF, + exp: f64::MAX_EXPONENT + 5, + }; + avoid_overflow::(&mut fp); + assert_eq!(fp.mant, 0xFFFFFFFFFFFF); + assert_eq!(fp.exp, f64::MAX_EXPONENT + 5); + + // Avoid overflow, succeeds + let mut fp = ExtendedFloat { + mant: 0xFFFFFFFFFFFF, + exp: f64::MAX_EXPONENT + 4, + }; + avoid_overflow::(&mut fp); + assert_eq!(fp.mant, 0x1FFFFFFFFFFFE0); + assert_eq!(fp.exp, f64::MAX_EXPONENT - 1); +} + +#[test] +fn round_to_native_test() { + // Overflow + let mut fp = ExtendedFloat { + mant: 0xFFFFFFFFFFFF, + exp: f64::MAX_EXPONENT + 4, + }; + round_to_native::(&mut fp, round_nearest_tie_even); + assert_eq!(fp.mant, 0x1FFFFFFFFFFFE0); + assert_eq!(fp.exp, f64::MAX_EXPONENT - 1); + + // Need denormal + let mut fp = ExtendedFloat { + mant: 1, + exp: f64::DENORMAL_EXPONENT + 48, + }; + round_to_native::(&mut fp, round_nearest_tie_even); + assert_eq!(fp.mant, 1 << 48); + assert_eq!(fp.exp, f64::DENORMAL_EXPONENT); + + // Halfway, round-down (b'10000000000000000000000000000000000000000000000000000100000') + let mut fp = ExtendedFloat { + mant: 0x400000000000020, + exp: -58, + }; + round_to_native::(&mut fp, round_nearest_tie_even); + assert_eq!(fp.mant, 1 << 52); + assert_eq!(fp.exp, -52); + + // Halfway, round-up (b'10000000000000000000000000000000000000000000000000001100000') + let mut fp = ExtendedFloat { + mant: 0x400000000000060, + exp: -58, + }; + round_to_native::(&mut fp, round_nearest_tie_even); + assert_eq!(fp.mant, (1 << 52) + 2); + assert_eq!(fp.exp, -52); + + // Above halfway + let mut fp = ExtendedFloat { + mant: 0x400000000000021, + exp: -58, + }; + round_to_native::(&mut fp, round_nearest_tie_even); + assert_eq!(fp.mant, (1 << 52) + 1); + assert_eq!(fp.exp, -52); + + let mut fp = ExtendedFloat { + mant: 0x400000000000061, + exp: -58, + }; + round_to_native::(&mut fp, round_nearest_tie_even); + assert_eq!(fp.mant, (1 << 52) + 2); + assert_eq!(fp.exp, -52); + + // Below halfway + let mut fp = ExtendedFloat { + mant: 0x40000000000001F, + exp: -58, + }; + round_to_native::(&mut fp, round_nearest_tie_even); + assert_eq!(fp.mant, 1 << 52); + assert_eq!(fp.exp, -52); + + let mut fp = ExtendedFloat { + mant: 0x40000000000005F, + exp: -58, + }; + round_to_native::(&mut fp, round_nearest_tie_even); + assert_eq!(fp.mant, (1 << 52) + 1); + assert_eq!(fp.exp, -52); + + // Underflow + // Adapted from failures in strtod. + let mut fp = ExtendedFloat { + exp: -1139, + mant: 18446744073709550712, + }; + round_to_native::(&mut fp, round_nearest_tie_even); + assert_eq!(fp.mant, 0); + assert_eq!(fp.exp, 0); + + let mut fp = ExtendedFloat { + exp: -1139, + mant: 18446744073709551460, + }; + round_to_native::(&mut fp, round_nearest_tie_even); + assert_eq!(fp.mant, 0); + assert_eq!(fp.exp, 0); + + let mut fp = ExtendedFloat { + exp: -1138, + mant: 9223372036854776103, + }; + round_to_native::(&mut fp, round_nearest_tie_even); + assert_eq!(fp.mant, 1); + assert_eq!(fp.exp, -1074); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/macros/mod.rs b/third_party/crates/serde_json-1.0.151/tests/macros/mod.rs new file mode 100644 index 0000000..aaf820f --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/macros/mod.rs @@ -0,0 +1,61 @@ +#![allow(unused_macro_rules)] + +macro_rules! json_str { + ([]) => { + "[]" + }; + ([ $e0:tt $(, $e:tt)* $(,)? ]) => { + concat!("[", + json_str!($e0), + $(",", json_str!($e),)* + "]") + }; + ({}) => { + "{}" + }; + ({ $k0:tt : $v0:tt $(, $k:tt : $v:tt)* $(,)? }) => { + concat!("{", + stringify!($k0), ":", json_str!($v0), + $(",", stringify!($k), ":", json_str!($v),)* + "}") + }; + (($other:tt)) => { + $other + }; + ($other:tt) => { + stringify!($other) + }; +} + +macro_rules! pretty_str { + ($json:tt) => { + pretty_str_impl!("", $json) + }; +} + +macro_rules! pretty_str_impl { + ($indent:expr, []) => { + "[]" + }; + ($indent:expr, [ $e0:tt $(, $e:tt)* $(,)? ]) => { + concat!("[\n ", + $indent, pretty_str_impl!(concat!(" ", $indent), $e0), + $(",\n ", $indent, pretty_str_impl!(concat!(" ", $indent), $e),)* + "\n", $indent, "]") + }; + ($indent:expr, {}) => { + "{}" + }; + ($indent:expr, { $k0:tt : $v0:tt $(, $k:tt : $v:tt)* $(,)? }) => { + concat!("{\n ", + $indent, stringify!($k0), ": ", pretty_str_impl!(concat!(" ", $indent), $v0), + $(",\n ", $indent, stringify!($k), ": ", pretty_str_impl!(concat!(" ", $indent), $v),)* + "\n", $indent, "}") + }; + ($indent:expr, ($other:tt)) => { + $other + }; + ($indent:expr, $other:tt) => { + stringify!($other) + }; +} diff --git a/third_party/crates/serde_json-1.0.151/tests/map.rs b/third_party/crates/serde_json-1.0.151/tests/map.rs new file mode 100644 index 0000000..aa3cb25 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/map.rs @@ -0,0 +1,57 @@ +use serde_json::{from_str, Map, Value}; + +#[test] +fn test_preserve_order() { + // Sorted order + #[cfg(not(feature = "preserve_order"))] + const EXPECTED: &[&str] = &["a", "b", "c"]; + + // Insertion order + #[cfg(feature = "preserve_order")] + const EXPECTED: &[&str] = &["b", "a", "c"]; + + let v: Value = from_str(r#"{"b":null,"a":null,"c":null}"#).unwrap(); + let keys: Vec<_> = v.as_object().unwrap().keys().collect(); + assert_eq!(keys, EXPECTED); +} + +#[test] +#[cfg(feature = "preserve_order")] +fn test_shift_insert() { + let mut v: Value = from_str(r#"{"b":null,"a":null,"c":null}"#).unwrap(); + let val = v.as_object_mut().unwrap(); + val.shift_insert(0, "d".to_owned(), Value::Null); + + let keys: Vec<_> = val.keys().collect(); + assert_eq!(keys, &["d", "b", "a", "c"]); +} + +#[test] +fn test_append() { + // Sorted order + #[cfg(not(feature = "preserve_order"))] + const EXPECTED: &[&str] = &["a", "b", "c"]; + + // Insertion order + #[cfg(feature = "preserve_order")] + const EXPECTED: &[&str] = &["b", "a", "c"]; + + let mut v: Value = from_str(r#"{"b":null,"a":null,"c":null}"#).unwrap(); + let val = v.as_object_mut().unwrap(); + let mut m = Map::new(); + m.append(val); + let keys: Vec<_> = m.keys().collect(); + + assert_eq!(keys, EXPECTED); + assert!(val.is_empty()); +} + +#[test] +fn test_retain() { + let mut v: Value = from_str(r#"{"b":null,"a":null,"c":null}"#).unwrap(); + let val = v.as_object_mut().unwrap(); + val.retain(|k, _| k.as_str() != "b"); + + let keys: Vec<_> = val.keys().collect(); + assert_eq!(keys, &["a", "c"]); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/regression.rs b/third_party/crates/serde_json-1.0.151/tests/regression.rs new file mode 100644 index 0000000..315bb15 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/regression.rs @@ -0,0 +1,5 @@ +#![allow(clippy::elidable_lifetime_names, clippy::needless_lifetimes)] + +mod regression { + automod::dir!("tests/regression"); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/regression/issue1004.rs b/third_party/crates/serde_json-1.0.151/tests/regression/issue1004.rs new file mode 100644 index 0000000..c09fb96 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/regression/issue1004.rs @@ -0,0 +1,12 @@ +#![cfg(feature = "arbitrary_precision")] + +#[test] +fn test() { + let float = 5.55f32; + let value = serde_json::to_value(float).unwrap(); + let json = serde_json::to_string(&value).unwrap(); + + // If the f32 were cast to f64 by Value before serialization, then this + // would incorrectly serialize as 5.550000190734863. + assert_eq!(json, "5.55"); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/regression/issue520.rs b/third_party/crates/serde_json-1.0.151/tests/regression/issue520.rs new file mode 100644 index 0000000..730ecc6 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/regression/issue520.rs @@ -0,0 +1,20 @@ +#![allow(clippy::float_cmp)] + +use serde_derive::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug)] +#[serde(tag = "type", content = "data")] +enum E { + Float(f32), +} + +#[test] +fn test() { + let e = E::Float(159.1); + let v = serde_json::to_value(e).unwrap(); + let e = serde_json::from_value::(v).unwrap(); + + match e { + E::Float(f) => assert_eq!(f, 159.1), + } +} diff --git a/third_party/crates/serde_json-1.0.151/tests/regression/issue795.rs b/third_party/crates/serde_json-1.0.151/tests/regression/issue795.rs new file mode 100644 index 0000000..411e8af --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/regression/issue795.rs @@ -0,0 +1,62 @@ +#![allow(clippy::assertions_on_result_states)] + +use serde::de::{ + Deserialize, Deserializer, EnumAccess, IgnoredAny, MapAccess, VariantAccess, Visitor, +}; +use serde_json::json; +use std::fmt; + +#[derive(Debug)] +pub enum Enum { + Variant { + #[allow(dead_code)] + x: u8, + }, +} + +impl<'de> Deserialize<'de> for Enum { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct EnumVisitor; + + impl<'de> Visitor<'de> for EnumVisitor { + type Value = Enum; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("enum Enum") + } + + fn visit_enum(self, data: A) -> Result + where + A: EnumAccess<'de>, + { + let (IgnoredAny, variant) = data.variant()?; + variant.struct_variant(&["x"], self) + } + + fn visit_map(self, mut data: A) -> Result + where + A: MapAccess<'de>, + { + let mut x = 0; + if let Some((IgnoredAny, value)) = data.next_entry()? { + x = value; + } + Ok(Enum::Variant { x }) + } + } + + deserializer.deserialize_enum("Enum", &["Variant"], EnumVisitor) + } +} + +#[test] +fn test() { + let s = r#" {"Variant":{"x":0,"y":0}} "#; + assert!(serde_json::from_str::(s).is_err()); + + let j = json!({"Variant":{"x":0,"y":0}}); + assert!(serde_json::from_value::(j).is_err()); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/regression/issue845.rs b/third_party/crates/serde_json-1.0.151/tests/regression/issue845.rs new file mode 100644 index 0000000..7b6564d --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/regression/issue845.rs @@ -0,0 +1,74 @@ +#![allow(clippy::trait_duplication_in_bounds)] // https://github.com/rust-lang/rust-clippy/issues/8757 + +use serde::{Deserialize, Deserializer}; +use std::fmt::{self, Display}; +use std::marker::PhantomData; +use std::str::FromStr; + +pub struct NumberVisitor { + marker: PhantomData, +} + +impl<'de, T> serde::de::Visitor<'de> for NumberVisitor +where + T: TryFrom + TryFrom + FromStr, + >::Error: Display, + >::Error: Display, + ::Err: Display, +{ + type Value = T; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("an integer or string") + } + + fn visit_u64(self, v: u64) -> Result + where + E: serde::de::Error, + { + T::try_from(v).map_err(serde::de::Error::custom) + } + + fn visit_i64(self, v: i64) -> Result + where + E: serde::de::Error, + { + T::try_from(v).map_err(serde::de::Error::custom) + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + v.parse().map_err(serde::de::Error::custom) + } +} + +fn deserialize_integer_or_string<'de, D, T>(deserializer: D) -> Result +where + D: Deserializer<'de>, + T: TryFrom + TryFrom + FromStr, + >::Error: Display, + >::Error: Display, + ::Err: Display, +{ + deserializer.deserialize_any(NumberVisitor { + marker: PhantomData, + }) +} + +#[derive(Deserialize, Debug)] +pub struct Struct { + #[serde(deserialize_with = "deserialize_integer_or_string")] + #[allow(dead_code)] + pub i: i64, +} + +#[test] +fn test() { + let j = r#" {"i":100} "#; + println!("{:?}", serde_json::from_str::(j).unwrap()); + + let j = r#" {"i":"100"} "#; + println!("{:?}", serde_json::from_str::(j).unwrap()); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/regression/issue953.rs b/third_party/crates/serde_json-1.0.151/tests/regression/issue953.rs new file mode 100644 index 0000000..771aa52 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/regression/issue953.rs @@ -0,0 +1,9 @@ +use serde_json::Value; + +#[test] +fn test() { + let x1 = serde_json::from_str::("18446744073709551615."); + assert!(x1.is_err()); + let x2 = serde_json::from_str::("18446744073709551616."); + assert!(x2.is_err()); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/regression/issue979.rs b/third_party/crates/serde_json-1.0.151/tests/regression/issue979.rs new file mode 100644 index 0000000..e17359a --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/regression/issue979.rs @@ -0,0 +1,29 @@ +use serde::de::{Deserializer, EnumAccess, VariantAccess, Visitor}; +use std::fmt; + +struct EnumVisitor; + +impl<'de> Visitor<'de> for EnumVisitor { + type Value = (Vec, ()); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("enum") + } + + fn visit_enum(self, data: A) -> Result + where + A: EnumAccess<'de>, + { + let (key, variant) = data.variant()?; + variant.newtype_variant::<()>()?; + Ok((key, ())) + } +} + +#[test] +fn test() { + let mut de = serde_json::Deserializer::from_str("{[true]: null}"); + let err = de.deserialize_enum("name", &[], EnumVisitor).unwrap_err(); + + assert!(err.to_string().contains("key must be a string")); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/stream.rs b/third_party/crates/serde_json-1.0.151/tests/stream.rs new file mode 100644 index 0000000..fa52ced --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/stream.rs @@ -0,0 +1,182 @@ +#![allow(clippy::assertions_on_result_states)] + +use serde_json::{json, Deserializer, Value}; + +// Rustfmt issue https://github.com/rust-lang-nursery/rustfmt/issues/2740 +#[rustfmt::skip] +macro_rules! test_stream { + ($data:expr, $ty:ty, |$stream:ident| $test:block) => { + { + let de = Deserializer::from_str($data); + let mut $stream = de.into_iter::<$ty>(); + assert_eq!($stream.byte_offset(), 0); + $test + } + { + let de = Deserializer::from_slice($data.as_bytes()); + let mut $stream = de.into_iter::<$ty>(); + assert_eq!($stream.byte_offset(), 0); + $test + } + { + let mut bytes = $data.as_bytes(); + let de = Deserializer::from_reader(&mut bytes); + let mut $stream = de.into_iter::<$ty>(); + assert_eq!($stream.byte_offset(), 0); + $test + } + }; +} + +#[test] +fn test_json_stream_newlines() { + let data = "{\"x\":39} {\"x\":40}{\"x\":41}\n{\"x\":42}"; + + test_stream!(data, Value, |stream| { + assert_eq!(stream.next().unwrap().unwrap()["x"], 39); + assert_eq!(stream.byte_offset(), 8); + + assert_eq!(stream.next().unwrap().unwrap()["x"], 40); + assert_eq!(stream.byte_offset(), 17); + + assert_eq!(stream.next().unwrap().unwrap()["x"], 41); + assert_eq!(stream.byte_offset(), 25); + + assert_eq!(stream.next().unwrap().unwrap()["x"], 42); + assert_eq!(stream.byte_offset(), 34); + + assert!(stream.next().is_none()); + assert_eq!(stream.byte_offset(), 34); + }); +} + +#[test] +fn test_json_stream_trailing_whitespaces() { + let data = "{\"x\":42} \t\n"; + + test_stream!(data, Value, |stream| { + assert_eq!(stream.next().unwrap().unwrap()["x"], 42); + assert_eq!(stream.byte_offset(), 8); + + assert!(stream.next().is_none()); + assert_eq!(stream.byte_offset(), 11); + }); +} + +#[test] +fn test_json_stream_truncated() { + let data = "{\"x\":40}\n{\"x\":"; + + test_stream!(data, Value, |stream| { + assert_eq!(stream.next().unwrap().unwrap()["x"], 40); + assert_eq!(stream.byte_offset(), 8); + + assert!(stream.next().unwrap().unwrap_err().is_eof()); + assert_eq!(stream.byte_offset(), 9); + }); +} + +#[test] +fn test_json_stream_truncated_decimal() { + let data = "{\"x\":4."; + + test_stream!(data, Value, |stream| { + assert!(stream.next().unwrap().unwrap_err().is_eof()); + assert_eq!(stream.byte_offset(), 0); + }); +} + +#[test] +fn test_json_stream_truncated_negative() { + let data = "{\"x\":-"; + + test_stream!(data, Value, |stream| { + assert!(stream.next().unwrap().unwrap_err().is_eof()); + assert_eq!(stream.byte_offset(), 0); + }); +} + +#[test] +fn test_json_stream_truncated_exponent() { + let data = "{\"x\":4e"; + + test_stream!(data, Value, |stream| { + assert!(stream.next().unwrap().unwrap_err().is_eof()); + assert_eq!(stream.byte_offset(), 0); + }); +} + +#[test] +fn test_json_stream_empty() { + let data = ""; + + test_stream!(data, Value, |stream| { + assert!(stream.next().is_none()); + assert_eq!(stream.byte_offset(), 0); + }); +} + +#[test] +fn test_json_stream_primitive() { + let data = "{} true{}1[]\nfalse\"hey\"2 "; + + test_stream!(data, Value, |stream| { + assert_eq!(stream.next().unwrap().unwrap(), json!({})); + assert_eq!(stream.byte_offset(), 2); + + assert_eq!(stream.next().unwrap().unwrap(), true); + assert_eq!(stream.byte_offset(), 7); + + assert_eq!(stream.next().unwrap().unwrap(), json!({})); + assert_eq!(stream.byte_offset(), 9); + + assert_eq!(stream.next().unwrap().unwrap(), 1); + assert_eq!(stream.byte_offset(), 10); + + assert_eq!(stream.next().unwrap().unwrap(), json!([])); + assert_eq!(stream.byte_offset(), 12); + + assert_eq!(stream.next().unwrap().unwrap(), false); + assert_eq!(stream.byte_offset(), 18); + + assert_eq!(stream.next().unwrap().unwrap(), "hey"); + assert_eq!(stream.byte_offset(), 23); + + assert_eq!(stream.next().unwrap().unwrap(), 2); + assert_eq!(stream.byte_offset(), 24); + + assert!(stream.next().is_none()); + assert_eq!(stream.byte_offset(), 25); + }); +} + +#[test] +fn test_json_stream_invalid_literal() { + let data = "truefalse"; + + test_stream!(data, Value, |stream| { + let second = stream.next().unwrap().unwrap_err(); + assert_eq!(second.to_string(), "trailing characters at line 1 column 5"); + }); +} + +#[test] +fn test_json_stream_invalid_number() { + let data = "1true"; + + test_stream!(data, Value, |stream| { + let second = stream.next().unwrap().unwrap_err(); + assert_eq!(second.to_string(), "trailing characters at line 1 column 2"); + }); +} + +#[test] +fn test_error() { + let data = "true wrong false"; + + test_stream!(data, Value, |stream| { + assert_eq!(stream.next().unwrap().unwrap(), true); + assert!(stream.next().unwrap().is_err()); + assert!(stream.next().is_none()); + }); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/test.rs b/third_party/crates/serde_json-1.0.151/tests/test.rs new file mode 100644 index 0000000..28dcfdb --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/test.rs @@ -0,0 +1,2617 @@ +#![allow( + clippy::assertions_on_result_states, + clippy::byte_char_slices, + clippy::cast_precision_loss, + clippy::derive_partial_eq_without_eq, + clippy::excessive_precision, + clippy::float_cmp, + clippy::incompatible_msrv, // https://github.com/rust-lang/rust-clippy/issues/12257 + clippy::items_after_statements, + clippy::large_digit_groups, + clippy::let_underscore_untyped, + clippy::shadow_unrelated, + clippy::too_many_lines, + clippy::uninlined_format_args, + clippy::unreadable_literal, + clippy::unseparated_literal_suffix, + clippy::vec_init_then_push, + clippy::zero_sized_map_values +)] + +#[macro_use] +mod macros; + +#[cfg(feature = "raw_value")] +use ref_cast::RefCast; +use serde::de::{self, IgnoredAny, IntoDeserializer}; +use serde::ser::{self, SerializeMap, SerializeSeq, Serializer}; +use serde::{Deserialize, Serialize}; +use serde_bytes::{ByteBuf, Bytes}; +#[cfg(feature = "raw_value")] +use serde_json::value::RawValue; +use serde_json::{ + from_reader, from_slice, from_str, from_value, json, to_string, to_string_pretty, to_value, + to_vec, Deserializer, Number, Value, +}; +use std::collections::BTreeMap; +#[cfg(feature = "raw_value")] +use std::collections::HashMap; +use std::fmt::{self, Debug}; +use std::hash::BuildHasher; +#[cfg(feature = "raw_value")] +use std::hash::{Hash, Hasher}; +use std::io; +use std::iter; +use std::marker::PhantomData; +use std::mem; +use std::str::FromStr; +use std::{f32, f64}; + +macro_rules! treemap { + () => { + BTreeMap::new() + }; + ($($k:expr => $v:expr),+ $(,)?) => { + { + let mut m = BTreeMap::new(); + $( + m.insert($k, $v); + )+ + m + } + }; +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +enum Animal { + Dog, + Frog(String, Vec), + Cat { age: usize, name: String }, + AntHive(Vec), +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +struct Inner { + a: (), + b: usize, + c: Vec, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +struct Outer { + inner: Vec, +} + +fn test_encode_ok(errors: &[(T, &str)]) +where + T: PartialEq + Debug + ser::Serialize, +{ + for &(ref value, out) in errors { + let out = out.to_string(); + + let s = to_string(value).unwrap(); + assert_eq!(s, out); + + let v = to_value(value).unwrap(); + let s = to_string(&v).unwrap(); + assert_eq!(s, out); + } +} + +fn test_pretty_encode_ok(errors: &[(T, &str)]) +where + T: PartialEq + Debug + ser::Serialize, +{ + for &(ref value, out) in errors { + let out = out.to_string(); + + let s = to_string_pretty(value).unwrap(); + assert_eq!(s, out); + + let v = to_value(value).unwrap(); + let s = to_string_pretty(&v).unwrap(); + assert_eq!(s, out); + } +} + +#[test] +fn test_write_null() { + let tests = &[((), "null")]; + test_encode_ok(tests); + test_pretty_encode_ok(tests); +} + +#[test] +fn test_write_u64() { + let tests = &[(3u64, "3"), (u64::MAX, &u64::MAX.to_string())]; + test_encode_ok(tests); + test_pretty_encode_ok(tests); +} + +#[test] +fn test_write_i64() { + let tests = &[ + (3i64, "3"), + (-2i64, "-2"), + (-1234i64, "-1234"), + (i64::MIN, &i64::MIN.to_string()), + ]; + test_encode_ok(tests); + test_pretty_encode_ok(tests); +} + +#[test] +fn test_write_f64() { + let tests = &[ + (3.0, "3.0"), + (3.1, "3.1"), + (-1.5, "-1.5"), + (0.5, "0.5"), + (f64::MIN, "-1.7976931348623157e+308"), + (f64::MAX, "1.7976931348623157e+308"), + (f64::EPSILON, "2.220446049250313e-16"), + ]; + test_encode_ok(tests); + test_pretty_encode_ok(tests); +} + +#[test] +fn test_encode_nonfinite_float_yields_null() { + let v = to_value(f64::NAN.copysign(1.0)).unwrap(); + assert!(v.is_null()); + + let v = to_value(f64::NAN.copysign(-1.0)).unwrap(); + assert!(v.is_null()); + + let v = to_value(f64::INFINITY).unwrap(); + assert!(v.is_null()); + + let v = to_value(-f64::INFINITY).unwrap(); + assert!(v.is_null()); + + let v = to_value(f32::NAN.copysign(1.0)).unwrap(); + assert!(v.is_null()); + + let v = to_value(f32::NAN.copysign(-1.0)).unwrap(); + assert!(v.is_null()); + + let v = to_value(f32::INFINITY).unwrap(); + assert!(v.is_null()); + + let v = to_value(-f32::INFINITY).unwrap(); + assert!(v.is_null()); +} + +#[test] +fn test_write_str() { + let tests = &[("", "\"\""), ("foo", "\"foo\"")]; + test_encode_ok(tests); + test_pretty_encode_ok(tests); +} + +#[test] +fn test_write_bool() { + let tests = &[(true, "true"), (false, "false")]; + test_encode_ok(tests); + test_pretty_encode_ok(tests); +} + +#[test] +fn test_write_char() { + let tests = &[ + ('n', "\"n\""), + ('"', "\"\\\"\""), + ('\\', "\"\\\\\""), + ('/', "\"/\""), + ('\x08', "\"\\b\""), + ('\x0C', "\"\\f\""), + ('\n', "\"\\n\""), + ('\r', "\"\\r\""), + ('\t', "\"\\t\""), + ('\x0B', "\"\\u000b\""), + ('\u{3A3}', "\"\u{3A3}\""), + ]; + test_encode_ok(tests); + test_pretty_encode_ok(tests); +} + +#[test] +fn test_write_list() { + test_encode_ok(&[ + (vec![], "[]"), + (vec![true], "[true]"), + (vec![true, false], "[true,false]"), + ]); + + test_encode_ok(&[ + (vec![vec![], vec![], vec![]], "[[],[],[]]"), + (vec![vec![1, 2, 3], vec![], vec![]], "[[1,2,3],[],[]]"), + (vec![vec![], vec![1, 2, 3], vec![]], "[[],[1,2,3],[]]"), + (vec![vec![], vec![], vec![1, 2, 3]], "[[],[],[1,2,3]]"), + ]); + + test_pretty_encode_ok(&[ + (vec![vec![], vec![], vec![]], pretty_str!([[], [], []])), + ( + vec![vec![1, 2, 3], vec![], vec![]], + pretty_str!([[1, 2, 3], [], []]), + ), + ( + vec![vec![], vec![1, 2, 3], vec![]], + pretty_str!([[], [1, 2, 3], []]), + ), + ( + vec![vec![], vec![], vec![1, 2, 3]], + pretty_str!([[], [], [1, 2, 3]]), + ), + ]); + + test_pretty_encode_ok(&[ + (vec![], "[]"), + (vec![true], pretty_str!([true])), + (vec![true, false], pretty_str!([true, false])), + ]); + + let long_test_list = json!([false, null, ["foo\nbar", 3.5]]); + + test_encode_ok(&[( + long_test_list.clone(), + json_str!([false, null, ["foo\nbar", 3.5]]), + )]); + + test_pretty_encode_ok(&[( + long_test_list, + pretty_str!([false, null, ["foo\nbar", 3.5]]), + )]); +} + +#[test] +fn test_write_object() { + test_encode_ok(&[ + (treemap!(), "{}"), + (treemap!("a".to_owned() => true), "{\"a\":true}"), + ( + treemap!( + "a".to_owned() => true, + "b".to_owned() => false, + ), + "{\"a\":true,\"b\":false}", + ), + ]); + + test_encode_ok(&[ + ( + treemap![ + "a".to_owned() => treemap![], + "b".to_owned() => treemap![], + "c".to_owned() => treemap![], + ], + "{\"a\":{},\"b\":{},\"c\":{}}", + ), + ( + treemap![ + "a".to_owned() => treemap![ + "a".to_owned() => treemap!["a" => vec![1,2,3]], + "b".to_owned() => treemap![], + "c".to_owned() => treemap![], + ], + "b".to_owned() => treemap![], + "c".to_owned() => treemap![], + ], + "{\"a\":{\"a\":{\"a\":[1,2,3]},\"b\":{},\"c\":{}},\"b\":{},\"c\":{}}", + ), + ( + treemap![ + "a".to_owned() => treemap![], + "b".to_owned() => treemap![ + "a".to_owned() => treemap!["a" => vec![1,2,3]], + "b".to_owned() => treemap![], + "c".to_owned() => treemap![], + ], + "c".to_owned() => treemap![], + ], + "{\"a\":{},\"b\":{\"a\":{\"a\":[1,2,3]},\"b\":{},\"c\":{}},\"c\":{}}", + ), + ( + treemap![ + "a".to_owned() => treemap![], + "b".to_owned() => treemap![], + "c".to_owned() => treemap![ + "a".to_owned() => treemap!["a" => vec![1,2,3]], + "b".to_owned() => treemap![], + "c".to_owned() => treemap![], + ], + ], + "{\"a\":{},\"b\":{},\"c\":{\"a\":{\"a\":[1,2,3]},\"b\":{},\"c\":{}}}", + ), + ]); + + test_encode_ok(&[(treemap!['c' => ()], "{\"c\":null}")]); + + test_pretty_encode_ok(&[ + ( + treemap![ + "a".to_owned() => treemap![], + "b".to_owned() => treemap![], + "c".to_owned() => treemap![], + ], + pretty_str!({ + "a": {}, + "b": {}, + "c": {} + }), + ), + ( + treemap![ + "a".to_owned() => treemap![ + "a".to_owned() => treemap!["a" => vec![1,2,3]], + "b".to_owned() => treemap![], + "c".to_owned() => treemap![], + ], + "b".to_owned() => treemap![], + "c".to_owned() => treemap![], + ], + pretty_str!({ + "a": { + "a": { + "a": [ + 1, + 2, + 3 + ] + }, + "b": {}, + "c": {} + }, + "b": {}, + "c": {} + }), + ), + ( + treemap![ + "a".to_owned() => treemap![], + "b".to_owned() => treemap![ + "a".to_owned() => treemap!["a" => vec![1,2,3]], + "b".to_owned() => treemap![], + "c".to_owned() => treemap![], + ], + "c".to_owned() => treemap![], + ], + pretty_str!({ + "a": {}, + "b": { + "a": { + "a": [ + 1, + 2, + 3 + ] + }, + "b": {}, + "c": {} + }, + "c": {} + }), + ), + ( + treemap![ + "a".to_owned() => treemap![], + "b".to_owned() => treemap![], + "c".to_owned() => treemap![ + "a".to_owned() => treemap!["a" => vec![1,2,3]], + "b".to_owned() => treemap![], + "c".to_owned() => treemap![], + ], + ], + pretty_str!({ + "a": {}, + "b": {}, + "c": { + "a": { + "a": [ + 1, + 2, + 3 + ] + }, + "b": {}, + "c": {} + } + }), + ), + ]); + + test_pretty_encode_ok(&[ + (treemap!(), "{}"), + ( + treemap!("a".to_owned() => true), + pretty_str!({ + "a": true + }), + ), + ( + treemap!( + "a".to_owned() => true, + "b".to_owned() => false, + ), + pretty_str!( { + "a": true, + "b": false + }), + ), + ]); + + let complex_obj = json!({ + "b": [ + {"c": "\x0c\x1f\r"}, + {"d": ""} + ] + }); + + test_encode_ok(&[( + complex_obj.clone(), + json_str!({ + "b": [ + { + "c": (r#""\f\u001f\r""#) + }, + { + "d": "" + } + ] + }), + )]); + + test_pretty_encode_ok(&[( + complex_obj, + pretty_str!({ + "b": [ + { + "c": (r#""\f\u001f\r""#) + }, + { + "d": "" + } + ] + }), + )]); +} + +#[test] +fn test_write_tuple() { + test_encode_ok(&[((5,), "[5]")]); + + test_pretty_encode_ok(&[((5,), pretty_str!([5]))]); + + test_encode_ok(&[((5, (6, "abc")), "[5,[6,\"abc\"]]")]); + + test_pretty_encode_ok(&[((5, (6, "abc")), pretty_str!([5, [6, "abc"]]))]); +} + +#[test] +fn test_write_enum() { + test_encode_ok(&[ + (Animal::Dog, "\"Dog\""), + ( + Animal::Frog("Henry".to_owned(), vec![]), + "{\"Frog\":[\"Henry\",[]]}", + ), + ( + Animal::Frog("Henry".to_owned(), vec![349]), + "{\"Frog\":[\"Henry\",[349]]}", + ), + ( + Animal::Frog("Henry".to_owned(), vec![349, 102]), + "{\"Frog\":[\"Henry\",[349,102]]}", + ), + ( + Animal::Cat { + age: 5, + name: "Kate".to_owned(), + }, + "{\"Cat\":{\"age\":5,\"name\":\"Kate\"}}", + ), + ( + Animal::AntHive(vec!["Bob".to_owned(), "Stuart".to_owned()]), + "{\"AntHive\":[\"Bob\",\"Stuart\"]}", + ), + ]); + + test_pretty_encode_ok(&[ + (Animal::Dog, "\"Dog\""), + ( + Animal::Frog("Henry".to_owned(), vec![]), + pretty_str!({ + "Frog": [ + "Henry", + [] + ] + }), + ), + ( + Animal::Frog("Henry".to_owned(), vec![349]), + pretty_str!({ + "Frog": [ + "Henry", + [ + 349 + ] + ] + }), + ), + ( + Animal::Frog("Henry".to_owned(), vec![349, 102]), + pretty_str!({ + "Frog": [ + "Henry", + [ + 349, + 102 + ] + ] + }), + ), + ]); +} + +#[test] +fn test_write_option() { + test_encode_ok(&[(None, "null"), (Some("jodhpurs"), "\"jodhpurs\"")]); + + test_encode_ok(&[ + (None, "null"), + (Some(vec!["foo", "bar"]), "[\"foo\",\"bar\"]"), + ]); + + test_pretty_encode_ok(&[(None, "null"), (Some("jodhpurs"), "\"jodhpurs\"")]); + + test_pretty_encode_ok(&[ + (None, "null"), + (Some(vec!["foo", "bar"]), pretty_str!(["foo", "bar"])), + ]); +} + +#[test] +fn test_write_newtype_struct() { + #[derive(Serialize, PartialEq, Debug)] + struct Newtype(BTreeMap); + + let inner = Newtype(treemap!(String::from("inner") => 123)); + let outer = treemap!(String::from("outer") => to_value(&inner).unwrap()); + + test_encode_ok(&[(inner, r#"{"inner":123}"#)]); + + test_encode_ok(&[(outer, r#"{"outer":{"inner":123}}"#)]); +} + +#[test] +fn test_deserialize_number_to_untagged_enum() { + #[derive(Eq, PartialEq, Deserialize, Debug)] + #[serde(untagged)] + enum E { + N(i64), + } + + assert_eq!(E::N(0), E::deserialize(Number::from(0)).unwrap()); +} + +fn test_parse_ok(tests: Vec<(&str, T)>) +where + T: Clone + Debug + PartialEq + ser::Serialize + de::DeserializeOwned, +{ + for (s, value) in tests { + let v: T = from_str(s).unwrap(); + assert_eq!(v, value.clone()); + + let v: T = from_slice(s.as_bytes()).unwrap(); + assert_eq!(v, value.clone()); + + // Make sure we can deserialize into a `Value`. + let json_value: Value = from_str(s).unwrap(); + assert_eq!(json_value, to_value(&value).unwrap()); + + // Make sure we can deserialize from a `&Value`. + let v = T::deserialize(&json_value).unwrap(); + assert_eq!(v, value); + + // Make sure we can deserialize from a `Value`. + let v: T = from_value(json_value.clone()).unwrap(); + assert_eq!(v, value); + + // Make sure we can round trip back to `Value`. + let json_value2: Value = from_value(json_value.clone()).unwrap(); + assert_eq!(json_value2, json_value); + + // Make sure we can fully ignore. + let twoline = s.to_owned() + "\n3735928559"; + let mut de = Deserializer::from_str(&twoline); + IgnoredAny::deserialize(&mut de).unwrap(); + assert_eq!(0xDEAD_BEEF, u64::deserialize(&mut de).unwrap()); + + // Make sure every prefix is an EOF error, except that a prefix of a + // number may be a valid number. + if !json_value.is_number() { + for (i, _) in s.trim_end().char_indices() { + assert!(from_str::(&s[..i]).unwrap_err().is_eof()); + assert!(from_str::(&s[..i]).unwrap_err().is_eof()); + } + } + } +} + +// For testing representations that the deserializer accepts but the serializer +// never generates. These do not survive a round-trip through Value. +fn test_parse_unusual_ok(tests: Vec<(&str, T)>) +where + T: Clone + Debug + PartialEq + ser::Serialize + de::DeserializeOwned, +{ + for (s, value) in tests { + let v: T = from_str(s).unwrap(); + assert_eq!(v, value.clone()); + + let v: T = from_slice(s.as_bytes()).unwrap(); + assert_eq!(v, value.clone()); + } +} + +macro_rules! test_parse_err { + ($name:ident::<$($ty:ty),*>($arg:expr) => $expected:expr) => { + let actual = $name::<$($ty),*>($arg).unwrap_err().to_string(); + assert_eq!(actual, $expected, "unexpected {} error", stringify!($name)); + }; +} + +fn test_parse_err(errors: &[(&str, &'static str)]) +where + T: Debug + PartialEq + de::DeserializeOwned, +{ + for &(s, err) in errors { + test_parse_err!(from_str::(s) => err); + test_parse_err!(from_slice::(s.as_bytes()) => err); + } +} + +fn test_parse_slice_err(errors: &[(&[u8], &'static str)]) +where + T: Debug + PartialEq + de::DeserializeOwned, +{ + for &(s, err) in errors { + test_parse_err!(from_slice::(s) => err); + } +} + +fn test_fromstr_parse_err(errors: &[(&str, &'static str)]) +where + T: Debug + PartialEq + FromStr, + ::Err: ToString, +{ + for &(s, err) in errors { + let actual = s.parse::().unwrap_err().to_string(); + assert_eq!(actual, err, "unexpected parsing error"); + } +} + +#[test] +fn test_parse_null() { + test_parse_err::<()>(&[ + ("n", "EOF while parsing a value at line 1 column 1"), + ("nul", "EOF while parsing a value at line 1 column 3"), + ("nulla", "trailing characters at line 1 column 5"), + ]); + + test_parse_ok(vec![("null", ())]); +} + +#[test] +fn test_parse_bool() { + test_parse_err::(&[ + ("t", "EOF while parsing a value at line 1 column 1"), + ("truz", "expected ident at line 1 column 4"), + ("f", "EOF while parsing a value at line 1 column 1"), + ("faz", "expected ident at line 1 column 3"), + ("truea", "trailing characters at line 1 column 5"), + ("falsea", "trailing characters at line 1 column 6"), + ]); + + test_parse_ok(vec![ + ("true", true), + (" true ", true), + ("false", false), + (" false ", false), + ]); +} + +#[test] +fn test_parse_char() { + test_parse_err::(&[ + ( + "\"ab\"", + "invalid value: string \"ab\", expected a character at line 1 column 4", + ), + ( + "10", + "invalid type: integer `10`, expected a character at line 1 column 2", + ), + ]); + + test_parse_ok(vec![ + ("\"n\"", 'n'), + ("\"\\\"\"", '"'), + ("\"\\\\\"", '\\'), + ("\"/\"", '/'), + ("\"\\b\"", '\x08'), + ("\"\\f\"", '\x0C'), + ("\"\\n\"", '\n'), + ("\"\\r\"", '\r'), + ("\"\\t\"", '\t'), + ("\"\\u000b\"", '\x0B'), + ("\"\\u000B\"", '\x0B'), + ("\"\u{3A3}\"", '\u{3A3}'), + ]); +} + +#[test] +fn test_parse_number_errors() { + test_parse_err::(&[ + ("+", "expected value at line 1 column 1"), + (".", "expected value at line 1 column 1"), + ("-", "EOF while parsing a value at line 1 column 1"), + ("00", "invalid number at line 1 column 2"), + ("0x80", "trailing characters at line 1 column 2"), + ("\\0", "expected value at line 1 column 1"), + (".0", "expected value at line 1 column 1"), + ("0.", "EOF while parsing a value at line 1 column 2"), + ("1.", "EOF while parsing a value at line 1 column 2"), + ("1.a", "invalid number at line 1 column 3"), + ("1.e1", "invalid number at line 1 column 3"), + ("1e", "EOF while parsing a value at line 1 column 2"), + ("1e+", "EOF while parsing a value at line 1 column 3"), + ("1a", "trailing characters at line 1 column 2"), + ( + "100e777777777777777777777777777", + "number out of range at line 1 column 14", + ), + ( + "-100e777777777777777777777777777", + "number out of range at line 1 column 15", + ), + ( + "1000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000", // 1e309 + "number out of range at line 1 column 310", + ), + ( + "1000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + .0e9", // 1e309 + "number out of range at line 1 column 305", + ), + ( + "1000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + e9", // 1e309 + "number out of range at line 1 column 303", + ), + ]); +} + +#[test] +fn test_parse_i64() { + test_parse_ok(vec![ + ("-2", -2), + ("-1234", -1234), + (" -1234 ", -1234), + (&i64::MIN.to_string(), i64::MIN), + (&i64::MAX.to_string(), i64::MAX), + ]); +} + +#[test] +fn test_parse_u64() { + test_parse_ok(vec![ + ("0", 0u64), + ("3", 3u64), + ("1234", 1234), + (&u64::MAX.to_string(), u64::MAX), + ]); +} + +#[test] +fn test_parse_negative_zero() { + for negative_zero in &[ + "-0", + "-0.0", + "-0e2", + "-0.0e2", + "-1e-400", + "-1e-4000000000000000000000000000000000000000000000000", + ] { + assert!( + from_str::(negative_zero).unwrap().is_sign_negative(), + "should have been negative: {:?}", + negative_zero, + ); + assert!( + from_str::(negative_zero).unwrap().is_sign_negative(), + "should have been negative: {:?}", + negative_zero, + ); + } +} + +#[test] +fn test_parse_f64() { + test_parse_ok(vec![ + ("0.0", 0.0f64), + ("3.0", 3.0f64), + ("3.1", 3.1), + ("-1.2", -1.2), + ("0.4", 0.4), + // Edge case from: + // https://github.com/serde-rs/json/issues/536#issuecomment-583714900 + ("2.638344616030823e-256", 2.638344616030823e-256), + ]); + + #[cfg(not(feature = "arbitrary_precision"))] + test_parse_ok(vec![ + // With arbitrary-precision enabled, this parses as Number{"3.00"} + // but the float is Number{"3.0"} + ("3.00", 3.0f64), + ("0.4e5", 0.4e5), + ("0.4e+5", 0.4e5), + ("0.4e15", 0.4e15), + ("0.4e+15", 0.4e15), + ("0.4e-01", 0.4e-1), + (" 0.4e-01 ", 0.4e-1), + ("0.4e-001", 0.4e-1), + ("0.4e-0", 0.4e0), + ("0.00e00", 0.0), + ("0.00e+00", 0.0), + ("0.00e-00", 0.0), + ("3.5E-2147483647", 0.0), + ("0.0100000000000000000001", 0.01), + ( + &format!("{}", (i64::MIN as f64) - 1.0), + (i64::MIN as f64) - 1.0, + ), + ( + &format!("{}", (u64::MAX as f64) + 1.0), + (u64::MAX as f64) + 1.0, + ), + (&format!("{}", f64::EPSILON), f64::EPSILON), + ( + "0.0000000000000000000000000000000000000000000000000123e50", + 1.23, + ), + ("100e-777777777777777777777777777", 0.0), + ( + "1010101010101010101010101010101010101010", + 10101010101010101010e20, + ), + ( + "0.1010101010101010101010101010101010101010", + 0.1010101010101010101, + ), + ("0e1000000000000000000000000000000000000000000000", 0.0), + ( + "1000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 00000000", + 1e308, + ), + ( + "1000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + .0e8", + 1e308, + ), + ( + "1000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + e8", + 1e308, + ), + ( + "1000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000e-10", + 1e308, + ), + ]); +} + +#[test] +fn test_value_as_f64() { + let v = serde_json::from_str::("1e1000"); + + #[cfg(not(feature = "arbitrary_precision"))] + assert!(v.is_err()); + + #[cfg(feature = "arbitrary_precision")] + assert_eq!(v.unwrap().as_f64(), None); +} + +// Test roundtrip with some values that were not perfectly roundtripped by the +// old f64 deserializer. +#[cfg(feature = "float_roundtrip")] +#[test] +fn test_roundtrip_f64() { + for &float in &[ + // Samples from quickcheck-ing roundtrip with `input: f64`. Comments + // indicate the value returned by the old deserializer. + 51.24817837550540_4, // 51.2481783755054_1 + -93.3113703768803_3, // -93.3113703768803_2 + -36.5739948427534_36, // -36.5739948427534_4 + 52.31400820410624_4, // 52.31400820410624_ + 97.4536532003468_5, // 97.4536532003468_4 + // Samples from `rng.next_u64` + `f64::from_bits` + `is_finite` filter. + 2.0030397744267762e-253, + 7.101215824554616e260, + 1.769268377902049e74, + -1.6727517818542075e58, + 3.9287532173373315e299, + ] { + let json = serde_json::to_string(&float).unwrap(); + let output: f64 = serde_json::from_str(&json).unwrap(); + assert_eq!(float, output); + } +} + +#[test] +fn test_roundtrip_f32() { + // This number has 1 ULP error if parsed via f64 and converted to f32. + // https://github.com/serde-rs/json/pull/671#issuecomment-628534468 + let float = 7.038531e-26; + let json = serde_json::to_string(&float).unwrap(); + let output: f32 = serde_json::from_str(&json).unwrap(); + assert_eq!(float, output); +} + +#[test] +fn test_serialize_char() { + let value = json!( + ({ + let mut map = BTreeMap::new(); + map.insert('c', ()); + map + }) + ); + assert_eq!(&Value::Null, value.get("c").unwrap()); +} + +#[cfg(feature = "arbitrary_precision")] +#[test] +fn test_malicious_number() { + #[derive(Serialize)] + #[serde(rename = "$serde_json::private::Number")] + struct S { + #[serde(rename = "$serde_json::private::Number")] + f: &'static str, + } + + let actual = serde_json::to_value(&S { f: "not a number" }) + .unwrap_err() + .to_string(); + assert_eq!(actual, "invalid number at line 1 column 1"); +} + +#[test] +fn test_parse_number() { + test_parse_ok(vec![ + ("0.0", Number::from_f64(0.0f64).unwrap()), + ("3.0", Number::from_f64(3.0f64).unwrap()), + ("3.1", Number::from_f64(3.1).unwrap()), + ("-1.2", Number::from_f64(-1.2).unwrap()), + ("0.4", Number::from_f64(0.4).unwrap()), + ]); + + test_fromstr_parse_err::(&[ + (" 1.0", "invalid number at line 1 column 1"), + ("1.0 ", "invalid number at line 1 column 4"), + ("\t1.0", "invalid number at line 1 column 1"), + ("1.0\t", "invalid number at line 1 column 4"), + ]); + + #[cfg(feature = "arbitrary_precision")] + test_parse_ok(vec![ + ("1e999", Number::from_string_unchecked("1e+999".to_owned())), + ("1e+999", Number::from_string_unchecked("1e+999".to_owned())), + ( + "-1e999", + Number::from_string_unchecked("-1e+999".to_owned()), + ), + ("1e-999", Number::from_string_unchecked("1e-999".to_owned())), + ("1E999", Number::from_string_unchecked("1e+999".to_owned())), + ("1E+999", Number::from_string_unchecked("1e+999".to_owned())), + ( + "-1E999", + Number::from_string_unchecked("-1e+999".to_owned()), + ), + ("1E-999", Number::from_string_unchecked("1e-999".to_owned())), + ("1E+000", Number::from_string_unchecked("1e+000".to_owned())), + ( + "2.3e999", + Number::from_string_unchecked("2.3e+999".to_owned()), + ), + ( + "-2.3e999", + Number::from_string_unchecked("-2.3e+999".to_owned()), + ), + ]); +} + +#[test] +fn test_parse_string() { + test_parse_err::(&[ + ("\"", "EOF while parsing a string at line 1 column 1"), + ("\"lol", "EOF while parsing a string at line 1 column 4"), + ("\"lol\"a", "trailing characters at line 1 column 6"), + ( + "\"\\uD83C\\uFFFF\"", + "lone leading surrogate in hex escape at line 1 column 13", + ), + ( + "\"\n\"", + "control character (\\u0000-\\u001F) found while parsing a string at line 2 column 0", + ), + ( + "\"\x1F\"", + "control character (\\u0000-\\u001F) found while parsing a string at line 1 column 2", + ), + ]); + + test_parse_slice_err::(&[ + ( + &[b'"', 159, 146, 150, b'"'], + "invalid unicode code point at line 1 column 5", + ), + ( + &[b'"', b'\\', b'n', 159, 146, 150, b'"'], + "invalid unicode code point at line 1 column 7", + ), + ( + &[b'"', b'\\', b'u', 48, 48, 51], + "EOF while parsing a string at line 1 column 6", + ), + ( + &[b'"', b'\\', b'u', 250, 48, 51, 48, b'"'], + "invalid escape at line 1 column 7", + ), + ( + &[b'"', b'\\', b'u', 48, 250, 51, 48, b'"'], + "invalid escape at line 1 column 7", + ), + ( + &[b'"', b'\\', b'u', 48, 48, 250, 48, b'"'], + "invalid escape at line 1 column 7", + ), + ( + &[b'"', b'\\', b'u', 48, 48, 51, 250, b'"'], + "invalid escape at line 1 column 7", + ), + ( + &[b'"', b'\n', b'"'], + "control character (\\u0000-\\u001F) found while parsing a string at line 2 column 0", + ), + ( + &[b'"', b'\x1F', b'"'], + "control character (\\u0000-\\u001F) found while parsing a string at line 1 column 2", + ), + ]); + + test_parse_ok(vec![ + ("\"\"", String::new()), + ("\"foo\"", "foo".to_owned()), + (" \"foo\" ", "foo".to_owned()), + ("\"\\\"\"", "\"".to_owned()), + ("\"\\b\"", "\x08".to_owned()), + ("\"\\n\"", "\n".to_owned()), + ("\"\\r\"", "\r".to_owned()), + ("\"\\t\"", "\t".to_owned()), + ("\"\\u12ab\"", "\u{12ab}".to_owned()), + ("\"\\uAB12\"", "\u{AB12}".to_owned()), + ("\"\\uD83C\\uDF95\"", "\u{1F395}".to_owned()), + ]); +} + +#[test] +fn test_parse_list() { + test_parse_err::>(&[ + ("[", "EOF while parsing a list at line 1 column 1"), + ("[ ", "EOF while parsing a list at line 1 column 2"), + ("[1", "EOF while parsing a list at line 1 column 2"), + ("[1,", "EOF while parsing a value at line 1 column 3"), + ("[1,]", "trailing comma at line 1 column 4"), + ("[1 2]", "expected `,` or `]` at line 1 column 4"), + ("[]a", "trailing characters at line 1 column 3"), + ]); + + test_parse_ok(vec![ + ("[]", vec![]), + ("[ ]", vec![]), + ("[null]", vec![()]), + (" [ null ] ", vec![()]), + ]); + + test_parse_ok(vec![("[true]", vec![true])]); + + test_parse_ok(vec![("[3,1]", vec![3u64, 1]), (" [ 3 , 1 ] ", vec![3, 1])]); + + test_parse_ok(vec![("[[3], [1, 2]]", vec![vec![3u64], vec![1, 2]])]); + + test_parse_ok(vec![("[1]", (1u64,))]); + + test_parse_ok(vec![("[1, 2]", (1u64, 2u64))]); + + test_parse_ok(vec![("[1, 2, 3]", (1u64, 2u64, 3u64))]); + + test_parse_ok(vec![("[1, [2, 3]]", (1u64, (2u64, 3u64)))]); +} + +#[test] +fn test_parse_object() { + test_parse_err::>(&[ + ("{", "EOF while parsing an object at line 1 column 1"), + ("{ ", "EOF while parsing an object at line 1 column 2"), + ("{1", "key must be a string at line 1 column 2"), + ("{ \"a\"", "EOF while parsing an object at line 1 column 5"), + ("{\"a\"", "EOF while parsing an object at line 1 column 4"), + ("{\"a\" ", "EOF while parsing an object at line 1 column 5"), + ("{\"a\" 1", "expected `:` at line 1 column 6"), + ("{\"a\":", "EOF while parsing a value at line 1 column 5"), + ("{\"a\":1", "EOF while parsing an object at line 1 column 6"), + ("{\"a\":1 1", "expected `,` or `}` at line 1 column 8"), + ("{\"a\":1,", "EOF while parsing a value at line 1 column 7"), + ("{}a", "trailing characters at line 1 column 3"), + ]); + + test_parse_ok(vec![ + ("{}", treemap!()), + ("{ }", treemap!()), + ("{\"a\":3}", treemap!("a".to_owned() => 3u64)), + ("{ \"a\" : 3 }", treemap!("a".to_owned() => 3)), + ( + "{\"a\":3,\"b\":4}", + treemap!("a".to_owned() => 3, "b".to_owned() => 4), + ), + ( + " { \"a\" : 3 , \"b\" : 4 } ", + treemap!("a".to_owned() => 3, "b".to_owned() => 4), + ), + ]); + + test_parse_ok(vec![( + "{\"a\": {\"b\": 3, \"c\": 4}}", + treemap!( + "a".to_owned() => treemap!( + "b".to_owned() => 3u64, + "c".to_owned() => 4, + ), + ), + )]); + + test_parse_ok(vec![("{\"c\":null}", treemap!('c' => ()))]); +} + +#[test] +fn test_parse_struct() { + test_parse_err::(&[ + ( + "5", + "invalid type: integer `5`, expected struct Outer at line 1 column 1", + ), + ( + "\"hello\"", + "invalid type: string \"hello\", expected struct Outer at line 1 column 7", + ), + ( + "{\"inner\": true}", + "invalid type: boolean `true`, expected a sequence at line 1 column 14", + ), + ("{}", "missing field `inner` at line 1 column 2"), + ( + r#"{"inner": [{"b": 42, "c": []}]}"#, + "missing field `a` at line 1 column 29", + ), + ]); + + test_parse_ok(vec![ + ( + "{ + \"inner\": [] + }", + Outer { inner: vec![] }, + ), + ( + "{ + \"inner\": [ + { \"a\": null, \"b\": 2, \"c\": [\"abc\", \"xyz\"] } + ] + }", + Outer { + inner: vec![Inner { + a: (), + b: 2, + c: vec!["abc".to_owned(), "xyz".to_owned()], + }], + }, + ), + ]); + + let v: Outer = from_str( + "[ + [ + [ null, 2, [\"abc\", \"xyz\"] ] + ] + ]", + ) + .unwrap(); + + assert_eq!( + v, + Outer { + inner: vec![Inner { + a: (), + b: 2, + c: vec!["abc".to_owned(), "xyz".to_owned()], + }], + } + ); + + let j = json!([null, 2, []]); + Inner::deserialize(&j).unwrap(); + Inner::deserialize(j).unwrap(); +} + +#[test] +fn test_parse_option() { + test_parse_ok(vec![ + ("null", None::), + ("\"jodhpurs\"", Some("jodhpurs".to_owned())), + ]); + + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + struct Foo { + x: Option, + } + + let value: Foo = from_str("{}").unwrap(); + assert_eq!(value, Foo { x: None }); + + test_parse_ok(vec![ + ("{\"x\": null}", Foo { x: None }), + ("{\"x\": 5}", Foo { x: Some(5) }), + ]); +} + +#[test] +fn test_parse_enum_errors() { + test_parse_err::( + &[ + ("{}", "expected value at line 1 column 2"), + ("[]", "expected value at line 1 column 1"), + ("\"unknown\"", + "unknown variant `unknown`, expected one of `Dog`, `Frog`, `Cat`, `AntHive` at line 1 column 9"), + ("{\"unknown\":null}", + "unknown variant `unknown`, expected one of `Dog`, `Frog`, `Cat`, `AntHive` at line 1 column 10"), + ("{\"Dog\":", "EOF while parsing a value at line 1 column 7"), + ("{\"Dog\":}", "expected value at line 1 column 8"), + ("{\"Dog\":{}}", "invalid type: map, expected unit at line 1 column 7"), + ("\"Frog\"", "invalid type: unit variant, expected tuple variant"), + ("\"Frog\" 0 ", "invalid type: unit variant, expected tuple variant"), + ("{\"Frog\":{}}", + "invalid type: map, expected tuple variant Animal::Frog at line 1 column 8"), + ("{\"Cat\":[]}", "invalid length 0, expected struct variant Animal::Cat with 2 elements at line 1 column 9"), + ("{\"Cat\":[0]}", "invalid length 1, expected struct variant Animal::Cat with 2 elements at line 1 column 10"), + ("{\"Cat\":[0, \"\", 2]}", "trailing characters at line 1 column 16"), + ("{\"Cat\":{\"age\": 5, \"name\": \"Kate\", \"foo\":\"bar\"}", + "unknown field `foo`, expected `age` or `name` at line 1 column 39"), + + // JSON does not allow trailing commas in data structures + ("{\"Cat\":[0, \"Kate\",]}", "trailing comma at line 1 column 19"), + ("{\"Cat\":{\"age\": 2, \"name\": \"Kate\",}}", + "trailing comma at line 1 column 34"), + ], + ); +} + +#[test] +fn test_parse_enum() { + test_parse_ok(vec![ + ("\"Dog\"", Animal::Dog), + (" \"Dog\" ", Animal::Dog), + ( + "{\"Frog\":[\"Henry\",[]]}", + Animal::Frog("Henry".to_owned(), vec![]), + ), + ( + " { \"Frog\": [ \"Henry\" , [ 349, 102 ] ] } ", + Animal::Frog("Henry".to_owned(), vec![349, 102]), + ), + ( + "{\"Cat\": {\"age\": 5, \"name\": \"Kate\"}}", + Animal::Cat { + age: 5, + name: "Kate".to_owned(), + }, + ), + ( + " { \"Cat\" : { \"age\" : 5 , \"name\" : \"Kate\" } } ", + Animal::Cat { + age: 5, + name: "Kate".to_owned(), + }, + ), + ( + " { \"AntHive\" : [\"Bob\", \"Stuart\"] } ", + Animal::AntHive(vec!["Bob".to_owned(), "Stuart".to_owned()]), + ), + ]); + + test_parse_unusual_ok(vec![ + ("{\"Dog\":null}", Animal::Dog), + (" { \"Dog\" : null } ", Animal::Dog), + ]); + + test_parse_ok(vec![( + concat!( + "{", + " \"a\": \"Dog\",", + " \"b\": {\"Frog\":[\"Henry\", []]}", + "}" + ), + treemap!( + "a".to_owned() => Animal::Dog, + "b".to_owned() => Animal::Frog("Henry".to_owned(), vec![]), + ), + )]); +} + +#[test] +fn test_parse_trailing_whitespace() { + test_parse_ok(vec![ + ("[1, 2] ", vec![1u64, 2]), + ("[1, 2]\n", vec![1, 2]), + ("[1, 2]\t", vec![1, 2]), + ("[1, 2]\t \n", vec![1, 2]), + ]); +} + +#[test] +fn test_multiline_errors() { + test_parse_err::>(&[( + "{\n \"foo\":\n \"bar\"", + "EOF while parsing an object at line 3 column 6", + )]); +} + +#[test] +fn test_missing_option_field() { + #[derive(Debug, PartialEq, Deserialize)] + struct Foo { + x: Option, + } + + let value: Foo = from_str("{}").unwrap(); + assert_eq!(value, Foo { x: None }); + + let value: Foo = from_str("{\"x\": 5}").unwrap(); + assert_eq!(value, Foo { x: Some(5) }); + + let value: Foo = from_value(json!({})).unwrap(); + assert_eq!(value, Foo { x: None }); + + let value: Foo = from_value(json!({"x": 5})).unwrap(); + assert_eq!(value, Foo { x: Some(5) }); +} + +#[test] +fn test_missing_nonoption_field() { + #[derive(Debug, PartialEq, Deserialize)] + struct Foo { + x: u32, + } + + test_parse_err::(&[("{}", "missing field `x` at line 1 column 2")]); +} + +#[test] +fn test_missing_renamed_field() { + #[derive(Debug, PartialEq, Deserialize)] + struct Foo { + #[serde(rename = "y")] + x: Option, + } + + let value: Foo = from_str("{}").unwrap(); + assert_eq!(value, Foo { x: None }); + + let value: Foo = from_str("{\"y\": 5}").unwrap(); + assert_eq!(value, Foo { x: Some(5) }); + + let value: Foo = from_value(json!({})).unwrap(); + assert_eq!(value, Foo { x: None }); + + let value: Foo = from_value(json!({"y": 5})).unwrap(); + assert_eq!(value, Foo { x: Some(5) }); +} + +#[test] +fn test_serialize_seq_with_no_len() { + #[derive(Clone, Debug, PartialEq)] + struct MyVec(Vec); + + impl ser::Serialize for MyVec + where + T: ser::Serialize, + { + fn serialize(&self, serializer: S) -> Result + where + S: ser::Serializer, + { + let mut seq = serializer.serialize_seq(None)?; + for elem in &self.0 { + seq.serialize_element(elem)?; + } + seq.end() + } + } + + struct Visitor { + marker: PhantomData>, + } + + impl<'de, T> de::Visitor<'de> for Visitor + where + T: de::Deserialize<'de>, + { + type Value = MyVec; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("array") + } + + fn visit_unit(self) -> Result, E> + where + E: de::Error, + { + Ok(MyVec(Vec::new())) + } + + fn visit_seq(self, mut visitor: V) -> Result, V::Error> + where + V: de::SeqAccess<'de>, + { + let mut values = Vec::new(); + + while let Some(value) = visitor.next_element()? { + values.push(value); + } + + Ok(MyVec(values)) + } + } + + impl<'de, T> de::Deserialize<'de> for MyVec + where + T: de::Deserialize<'de>, + { + fn deserialize(deserializer: D) -> Result, D::Error> + where + D: de::Deserializer<'de>, + { + deserializer.deserialize_map(Visitor { + marker: PhantomData, + }) + } + } + + let mut vec = Vec::new(); + vec.push(MyVec(Vec::new())); + vec.push(MyVec(Vec::new())); + let vec: MyVec> = MyVec(vec); + + test_encode_ok(&[(vec.clone(), "[[],[]]")]); + + let s = to_string_pretty(&vec).unwrap(); + let expected = pretty_str!([[], []]); + assert_eq!(s, expected); +} + +#[test] +fn test_serialize_map_with_no_len() { + #[derive(Clone, Debug, PartialEq)] + struct MyMap(BTreeMap); + + impl ser::Serialize for MyMap + where + K: ser::Serialize + Ord, + V: ser::Serialize, + { + fn serialize(&self, serializer: S) -> Result + where + S: ser::Serializer, + { + let mut map = serializer.serialize_map(None)?; + for (k, v) in &self.0 { + map.serialize_entry(k, v)?; + } + map.end() + } + } + + struct Visitor { + marker: PhantomData>, + } + + impl<'de, K, V> de::Visitor<'de> for Visitor + where + K: de::Deserialize<'de> + Eq + Ord, + V: de::Deserialize<'de>, + { + type Value = MyMap; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("map") + } + + fn visit_unit(self) -> Result, E> + where + E: de::Error, + { + Ok(MyMap(BTreeMap::new())) + } + + fn visit_map(self, mut visitor: Visitor) -> Result, Visitor::Error> + where + Visitor: de::MapAccess<'de>, + { + let mut values = BTreeMap::new(); + + while let Some((key, value)) = visitor.next_entry()? { + values.insert(key, value); + } + + Ok(MyMap(values)) + } + } + + impl<'de, K, V> de::Deserialize<'de> for MyMap + where + K: de::Deserialize<'de> + Eq + Ord, + V: de::Deserialize<'de>, + { + fn deserialize(deserializer: D) -> Result, D::Error> + where + D: de::Deserializer<'de>, + { + deserializer.deserialize_map(Visitor { + marker: PhantomData, + }) + } + } + + let mut map = BTreeMap::new(); + map.insert("a", MyMap(BTreeMap::new())); + map.insert("b", MyMap(BTreeMap::new())); + let map: MyMap<_, MyMap> = MyMap(map); + + test_encode_ok(&[(map.clone(), "{\"a\":{},\"b\":{}}")]); + + let s = to_string_pretty(&map).unwrap(); + let expected = pretty_str!({ + "a": {}, + "b": {} + }); + assert_eq!(s, expected); +} + +#[cfg(not(miri))] +#[test] +fn test_deserialize_from_stream() { + use serde_json::to_writer; + use std::net::{TcpListener, TcpStream}; + use std::thread; + + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct Message { + message: String, + } + + let l = TcpListener::bind("localhost:20000").unwrap(); + + thread::spawn(|| { + let l = l; + for stream in l.incoming() { + let mut stream = stream.unwrap(); + let read_stream = stream.try_clone().unwrap(); + + let mut de = Deserializer::from_reader(read_stream); + let request = Message::deserialize(&mut de).unwrap(); + let response = Message { + message: request.message, + }; + to_writer(&mut stream, &response).unwrap(); + } + }); + + let mut stream = TcpStream::connect("localhost:20000").unwrap(); + let request = Message { + message: "hi there".to_owned(), + }; + to_writer(&mut stream, &request).unwrap(); + + let mut de = Deserializer::from_reader(stream); + let response = Message::deserialize(&mut de).unwrap(); + + assert_eq!(request, response); +} + +#[test] +fn test_serialize_rejects_adt_keys() { + let map = treemap!( + Some("a") => 2, + Some("b") => 4, + None => 6, + ); + + let err = to_vec(&map).unwrap_err(); + assert_eq!(err.to_string(), "key must be a string"); +} + +#[test] +fn test_bytes_ser() { + let buf = vec![]; + let bytes = Bytes::new(&buf); + assert_eq!(to_string(&bytes).unwrap(), "[]".to_owned()); + + let buf = vec![1, 2, 3]; + let bytes = Bytes::new(&buf); + assert_eq!(to_string(&bytes).unwrap(), "[1,2,3]".to_owned()); +} + +#[test] +fn test_byte_buf_ser() { + let bytes = ByteBuf::new(); + assert_eq!(to_string(&bytes).unwrap(), "[]".to_owned()); + + let bytes = ByteBuf::from(vec![1, 2, 3]); + assert_eq!(to_string(&bytes).unwrap(), "[1,2,3]".to_owned()); +} + +#[test] +fn test_byte_buf_de() { + let bytes = ByteBuf::new(); + let v: ByteBuf = from_str("[]").unwrap(); + assert_eq!(v, bytes); + + let bytes = ByteBuf::from(vec![1, 2, 3]); + let v: ByteBuf = from_str("[1, 2, 3]").unwrap(); + assert_eq!(v, bytes); +} + +#[test] +fn test_byte_buf_de_invalid_surrogates() { + let bytes = ByteBuf::from(vec![237, 160, 188]); + let v: ByteBuf = from_str(r#""\ud83c""#).unwrap(); + assert_eq!(v, bytes); + + let bytes = ByteBuf::from(vec![237, 160, 188, 10]); + let v: ByteBuf = from_str(r#""\ud83c\n""#).unwrap(); + assert_eq!(v, bytes); + + let bytes = ByteBuf::from(vec![237, 160, 188, 32]); + let v: ByteBuf = from_str(r#""\ud83c ""#).unwrap(); + assert_eq!(v, bytes); + + let res = from_str::(r#""\ud83c\!""#); + assert!(res.is_err()); + + let res = from_str::(r#""\ud83c\u""#); + assert!(res.is_err()); + + // lone trailing surrogate + let bytes = ByteBuf::from(vec![237, 176, 129]); + let v: ByteBuf = from_str(r#""\udc01""#).unwrap(); + assert_eq!(v, bytes); + + // leading surrogate followed by other leading surrogate + let bytes = ByteBuf::from(vec![237, 160, 188, 237, 160, 188]); + let v: ByteBuf = from_str(r#""\ud83c\ud83c""#).unwrap(); + assert_eq!(v, bytes); + + // leading surrogate followed by "a" (U+0061) in \u encoding + let bytes = ByteBuf::from(vec![237, 160, 188, 97]); + let v: ByteBuf = from_str(r#""\ud83c\u0061""#).unwrap(); + assert_eq!(v, bytes); + + // leading surrogate followed by U+0080 + let bytes = ByteBuf::from(vec![237, 160, 188, 194, 128]); + let v: ByteBuf = from_str(r#""\ud83c\u0080""#).unwrap(); + assert_eq!(v, bytes); + + // leading surrogate followed by U+FFFF + let bytes = ByteBuf::from(vec![237, 160, 188, 239, 191, 191]); + let v: ByteBuf = from_str(r#""\ud83c\uffff""#).unwrap(); + assert_eq!(v, bytes); +} + +#[test] +fn test_byte_buf_de_surrogate_pair() { + // leading surrogate followed by trailing surrogate + let bytes = ByteBuf::from(vec![240, 159, 128, 128]); + let v: ByteBuf = from_str(r#""\ud83c\udc00""#).unwrap(); + assert_eq!(v, bytes); + + // leading surrogate followed by a surrogate pair + let bytes = ByteBuf::from(vec![237, 160, 188, 240, 159, 128, 128]); + let v: ByteBuf = from_str(r#""\ud83c\ud83c\udc00""#).unwrap(); + assert_eq!(v, bytes); +} + +#[cfg(feature = "raw_value")] +#[test] +fn test_raw_de_invalid_surrogates() { + use serde_json::value::RawValue; + + assert!(from_str::>(r#""\ud83c""#).is_ok()); + assert!(from_str::>(r#""\ud83c\n""#).is_ok()); + assert!(from_str::>(r#""\ud83c ""#).is_ok()); + assert!(from_str::>(r#""\udc01 ""#).is_ok()); + assert!(from_str::>(r#""\udc01\!""#).is_err()); + assert!(from_str::>(r#""\udc01\u""#).is_err()); + assert!(from_str::>(r#""\ud83c\ud83c""#).is_ok()); + assert!(from_str::>(r#""\ud83c\u0061""#).is_ok()); + assert!(from_str::>(r#""\ud83c\u0080""#).is_ok()); + assert!(from_str::>(r#""\ud83c\uffff""#).is_ok()); +} + +#[cfg(feature = "raw_value")] +#[test] +fn test_raw_de_surrogate_pair() { + use serde_json::value::RawValue; + + assert!(from_str::>(r#""\ud83c\udc00""#).is_ok()); +} + +#[test] +fn test_byte_buf_de_multiple() { + let s: Vec = from_str(r#"["ab\nc", "cd\ne"]"#).unwrap(); + let a = ByteBuf::from(b"ab\nc".to_vec()); + let b = ByteBuf::from(b"cd\ne".to_vec()); + assert_eq!(vec![a, b], s); +} + +#[test] +fn test_json_pointer() { + // Test case taken from https://tools.ietf.org/html/rfc6901#page-5 + let data: Value = from_str( + r#"{ + "foo": ["bar", "baz"], + "": 0, + "a/b": 1, + "c%d": 2, + "e^f": 3, + "g|h": 4, + "i\\j": 5, + "k\"l": 6, + " ": 7, + "m~n": 8 + }"#, + ) + .unwrap(); + assert_eq!(data.pointer("").unwrap(), &data); + assert_eq!(data.pointer("/foo").unwrap(), &json!(["bar", "baz"])); + assert_eq!(data.pointer("/foo/0").unwrap(), &json!("bar")); + assert_eq!(data.pointer("/").unwrap(), &json!(0)); + assert_eq!(data.pointer("/a~1b").unwrap(), &json!(1)); + assert_eq!(data.pointer("/c%d").unwrap(), &json!(2)); + assert_eq!(data.pointer("/e^f").unwrap(), &json!(3)); + assert_eq!(data.pointer("/g|h").unwrap(), &json!(4)); + assert_eq!(data.pointer("/i\\j").unwrap(), &json!(5)); + assert_eq!(data.pointer("/k\"l").unwrap(), &json!(6)); + assert_eq!(data.pointer("/ ").unwrap(), &json!(7)); + assert_eq!(data.pointer("/m~0n").unwrap(), &json!(8)); + // Invalid pointers + assert!(data.pointer("/unknown").is_none()); + assert!(data.pointer("/e^f/ertz").is_none()); + assert!(data.pointer("/foo/00").is_none()); + assert!(data.pointer("/foo/01").is_none()); +} + +#[test] +fn test_json_pointer_mut() { + // Test case taken from https://tools.ietf.org/html/rfc6901#page-5 + let mut data: Value = from_str( + r#"{ + "foo": ["bar", "baz"], + "": 0, + "a/b": 1, + "c%d": 2, + "e^f": 3, + "g|h": 4, + "i\\j": 5, + "k\"l": 6, + " ": 7, + "m~n": 8 + }"#, + ) + .unwrap(); + + // Basic pointer checks + assert_eq!(data.pointer_mut("/foo").unwrap(), &json!(["bar", "baz"])); + assert_eq!(data.pointer_mut("/foo/0").unwrap(), &json!("bar")); + assert_eq!(data.pointer_mut("/").unwrap(), 0); + assert_eq!(data.pointer_mut("/a~1b").unwrap(), 1); + assert_eq!(data.pointer_mut("/c%d").unwrap(), 2); + assert_eq!(data.pointer_mut("/e^f").unwrap(), 3); + assert_eq!(data.pointer_mut("/g|h").unwrap(), 4); + assert_eq!(data.pointer_mut("/i\\j").unwrap(), 5); + assert_eq!(data.pointer_mut("/k\"l").unwrap(), 6); + assert_eq!(data.pointer_mut("/ ").unwrap(), 7); + assert_eq!(data.pointer_mut("/m~0n").unwrap(), 8); + + // Invalid pointers + assert!(data.pointer_mut("/unknown").is_none()); + assert!(data.pointer_mut("/e^f/ertz").is_none()); + assert!(data.pointer_mut("/foo/00").is_none()); + assert!(data.pointer_mut("/foo/01").is_none()); + + // Mutable pointer checks + *data.pointer_mut("/").unwrap() = 100.into(); + assert_eq!(data.pointer("/").unwrap(), 100); + *data.pointer_mut("/foo/0").unwrap() = json!("buzz"); + assert_eq!(data.pointer("/foo/0").unwrap(), &json!("buzz")); + + // Example of ownership stealing + assert_eq!( + data.pointer_mut("/a~1b") + .map(|m| mem::replace(m, json!(null))) + .unwrap(), + 1 + ); + assert_eq!(data.pointer("/a~1b").unwrap(), &json!(null)); + + // Need to compare against a clone so we don't anger the borrow checker + // by taking out two references to a mutable value + let mut d2 = data.clone(); + assert_eq!(data.pointer_mut("").unwrap(), &mut d2); +} + +#[test] +fn test_stack_overflow() { + let brackets: String = iter::repeat('[') + .take(127) + .chain(iter::repeat(']').take(127)) + .collect(); + let _: Value = from_str(&brackets).unwrap(); + + let brackets = "[".repeat(129); + test_parse_err::(&[(&brackets, "recursion limit exceeded at line 1 column 128")]); +} + +#[test] +#[cfg(feature = "unbounded_depth")] +fn test_disable_recursion_limit() { + let brackets: String = iter::repeat('[') + .take(140) + .chain(iter::repeat(']').take(140)) + .collect(); + + let mut deserializer = Deserializer::from_str(&brackets); + deserializer.disable_recursion_limit(); + Value::deserialize(&mut deserializer).unwrap(); +} + +#[test] +fn test_integer_key() { + // map with integer keys + let map = treemap!( + 1 => 2, + -1 => 6, + ); + let j = r#"{"-1":6,"1":2}"#; + test_encode_ok(&[(&map, j)]); + test_parse_ok(vec![(j, map)]); + + test_parse_err::>(&[ + ( + r#"{"x":null}"#, + "invalid value: expected key to be a number in quotes at line 1 column 2", + ), + ( + r#"{" 123":null}"#, + "invalid value: expected key to be a number in quotes at line 1 column 2", + ), + (r#"{"123 ":null}"#, "expected `\"` at line 1 column 6"), + ]); + + let err = from_value::>(json!({" 123":null})).unwrap_err(); + assert_eq!( + err.to_string(), + "invalid value: expected key to be a number in quotes", + ); + + let err = from_value::>(json!({"123 ":null})).unwrap_err(); + assert_eq!( + err.to_string(), + "invalid value: expected key to be a number in quotes", + ); +} + +#[test] +fn test_integer128_key() { + let map = treemap! { + 100000000000000000000000000000000000000u128 => (), + }; + let j = r#"{"100000000000000000000000000000000000000":null}"#; + assert_eq!(to_string(&map).unwrap(), j); + assert_eq!(from_str::>(j).unwrap(), map); +} + +#[test] +fn test_float_key() { + #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone)] + struct Float; + impl Serialize for Float { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_f32(1.23) + } + } + impl<'de> Deserialize<'de> for Float { + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + f32::deserialize(deserializer).map(|_| Float) + } + } + + // map with float key + let map = treemap!(Float => "x".to_owned()); + let j = r#"{"1.23":"x"}"#; + + test_encode_ok(&[(&map, j)]); + test_parse_ok(vec![(j, map)]); + + let j = r#"{"x": null}"#; + test_parse_err::>(&[( + j, + "invalid value: expected key to be a number in quotes at line 1 column 2", + )]); +} + +#[test] +fn test_deny_non_finite_f32_key() { + // We store float bits so that we can derive Ord, and other traits. In a + // real context the code might involve a crate like ordered-float. + + #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone)] + struct F32Bits(u32); + impl Serialize for F32Bits { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_f32(f32::from_bits(self.0)) + } + } + + let map = treemap!(F32Bits(f32::INFINITY.to_bits()) => "x".to_owned()); + assert!(serde_json::to_string(&map).is_err()); + assert!(serde_json::to_value(map).is_err()); + + let map = treemap!(F32Bits(f32::NEG_INFINITY.to_bits()) => "x".to_owned()); + assert!(serde_json::to_string(&map).is_err()); + assert!(serde_json::to_value(map).is_err()); + + let map = treemap!(F32Bits(f32::NAN.to_bits()) => "x".to_owned()); + assert!(serde_json::to_string(&map).is_err()); + assert!(serde_json::to_value(map).is_err()); +} + +#[test] +fn test_deny_non_finite_f64_key() { + // We store float bits so that we can derive Ord, and other traits. In a + // real context the code might involve a crate like ordered-float. + + #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone)] + struct F64Bits(u64); + impl Serialize for F64Bits { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_f64(f64::from_bits(self.0)) + } + } + + let map = treemap!(F64Bits(f64::INFINITY.to_bits()) => "x".to_owned()); + assert!(serde_json::to_string(&map).is_err()); + assert!(serde_json::to_value(map).is_err()); + + let map = treemap!(F64Bits(f64::NEG_INFINITY.to_bits()) => "x".to_owned()); + assert!(serde_json::to_string(&map).is_err()); + assert!(serde_json::to_value(map).is_err()); + + let map = treemap!(F64Bits(f64::NAN.to_bits()) => "x".to_owned()); + assert!(serde_json::to_string(&map).is_err()); + assert!(serde_json::to_value(map).is_err()); +} + +#[test] +fn test_boolean_key() { + let map = treemap!(false => 0, true => 1); + let j = r#"{"false":0,"true":1}"#; + test_encode_ok(&[(&map, j)]); + test_parse_ok(vec![(j, map)]); +} + +#[test] +fn test_borrowed_key() { + let map: BTreeMap<&str, ()> = from_str("{\"borrowed\":null}").unwrap(); + let expected = treemap! { "borrowed" => () }; + assert_eq!(map, expected); + + #[derive(Deserialize, Debug, Ord, PartialOrd, Eq, PartialEq)] + struct NewtypeStr<'a>(&'a str); + + let map: BTreeMap = from_str("{\"borrowed\":null}").unwrap(); + let expected = treemap! { NewtypeStr("borrowed") => () }; + assert_eq!(map, expected); +} + +#[test] +fn test_effectively_string_keys() { + #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Serialize, Deserialize)] + enum Enum { + One, + Two, + } + let map = treemap! { + Enum::One => 1, + Enum::Two => 2, + }; + let expected = r#"{"One":1,"Two":2}"#; + test_encode_ok(&[(&map, expected)]); + test_parse_ok(vec![(expected, map)]); + + #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Serialize, Deserialize)] + struct Wrapper(String); + let map = treemap! { + Wrapper("zero".to_owned()) => 0, + Wrapper("one".to_owned()) => 1, + }; + let expected = r#"{"one":1,"zero":0}"#; + test_encode_ok(&[(&map, expected)]); + test_parse_ok(vec![(expected, map)]); +} + +#[test] +fn test_json_macro() { + // This is tricky because the <...> is not a single TT and the comma inside + // looks like an array element separator. + let _ = json!([ + as Clone>::clone(&Ok(())), + as Clone>::clone(&Err(())) + ]); + + // Same thing but in the map values. + let _ = json!({ + "ok": as Clone>::clone(&Ok(())), + "err": as Clone>::clone(&Err(())) + }); + + // It works in map keys but only if they are parenthesized. + let _ = json!({ + ( as Clone>::clone(&Ok("")).unwrap()): "ok", + ( as Clone>::clone(&Err("")).unwrap_err()): "err" + }); + + #[deny(unused_results)] + let _ = json!({ "architecture": [true, null] }); +} + +#[test] +fn issue_220() { + #[derive(Debug, PartialEq, Eq, Deserialize)] + enum E { + V(u8), + } + + assert!(from_str::(r#" "V"0 "#).is_err()); + + assert_eq!(from_str::(r#"{"V": 0}"#).unwrap(), E::V(0)); +} + +#[test] +fn test_partialeq_number() { + macro_rules! number_partialeq_ok { + ($($n:expr)*) => { + $( + let value = to_value($n).unwrap(); + let s = $n.to_string(); + assert_eq!(value, $n); + assert_eq!($n, value); + assert_ne!(value, s); + )* + }; + } + + number_partialeq_ok!(0 1 100 + i8::MIN i8::MAX i16::MIN i16::MAX i32::MIN i32::MAX i64::MIN i64::MAX + u8::MIN u8::MAX u16::MIN u16::MAX u32::MIN u32::MAX u64::MIN u64::MAX + f32::MIN f32::MAX f32::MIN_EXP f32::MAX_EXP f32::MIN_POSITIVE + f64::MIN f64::MAX f64::MIN_EXP f64::MAX_EXP f64::MIN_POSITIVE + f32::consts::E f32::consts::PI f32::consts::LN_2 f32::consts::LOG2_E + f64::consts::E f64::consts::PI f64::consts::LN_2 f64::consts::LOG2_E + ); +} + +#[test] +fn test_partialeq_string() { + let v = to_value("42").unwrap(); + assert_eq!(v, "42"); + assert_eq!("42", v); + assert_ne!(v, 42); + assert_eq!(v, String::from("42")); + assert_eq!(String::from("42"), v); +} + +#[test] +fn test_partialeq_bool() { + let v = to_value(true).unwrap(); + assert_eq!(v, true); + assert_eq!(true, v); + assert_ne!(v, false); + assert_ne!(v, "true"); + assert_ne!(v, 1); + assert_ne!(v, 0); +} + +struct FailReader(io::ErrorKind); + +impl io::Read for FailReader { + fn read(&mut self, _: &mut [u8]) -> io::Result { + Err(io::Error::new(self.0, "oh no!")) + } +} + +#[test] +fn test_category() { + assert!(from_str::("123").unwrap_err().is_data()); + + assert!(from_str::("]").unwrap_err().is_syntax()); + + assert!(from_str::("").unwrap_err().is_eof()); + assert!(from_str::("\"").unwrap_err().is_eof()); + assert!(from_str::("\"\\").unwrap_err().is_eof()); + assert!(from_str::("\"\\u").unwrap_err().is_eof()); + assert!(from_str::("\"\\u0").unwrap_err().is_eof()); + assert!(from_str::("\"\\u00").unwrap_err().is_eof()); + assert!(from_str::("\"\\u000").unwrap_err().is_eof()); + + assert!(from_str::>("[").unwrap_err().is_eof()); + assert!(from_str::>("[0").unwrap_err().is_eof()); + assert!(from_str::>("[0,").unwrap_err().is_eof()); + + assert!(from_str::>("{") + .unwrap_err() + .is_eof()); + assert!(from_str::>("{\"k\"") + .unwrap_err() + .is_eof()); + assert!(from_str::>("{\"k\":") + .unwrap_err() + .is_eof()); + assert!(from_str::>("{\"k\":0") + .unwrap_err() + .is_eof()); + assert!(from_str::>("{\"k\":0,") + .unwrap_err() + .is_eof()); + + let fail = FailReader(io::ErrorKind::NotConnected); + assert!(from_reader::<_, String>(fail).unwrap_err().is_io()); +} + +#[test] +// Clippy false positive: https://github.com/Manishearth/rust-clippy/issues/292 +#[allow(clippy::needless_lifetimes)] +fn test_into_io_error() { + fn io_error<'de, T: Deserialize<'de> + Debug>(j: &'static str) -> io::Error { + from_str::(j).unwrap_err().into() + } + + assert_eq!( + io_error::("\"\\u").kind(), + io::ErrorKind::UnexpectedEof + ); + assert_eq!(io_error::("0").kind(), io::ErrorKind::InvalidData); + assert_eq!(io_error::("]").kind(), io::ErrorKind::InvalidData); + + let fail = FailReader(io::ErrorKind::NotConnected); + let io_err: io::Error = from_reader::<_, u8>(fail).unwrap_err().into(); + assert_eq!(io_err.kind(), io::ErrorKind::NotConnected); +} + +#[test] +fn test_borrow() { + let s: &str = from_str("\"borrowed\"").unwrap(); + assert_eq!("borrowed", s); + + let s: &str = from_slice(b"\"borrowed\"").unwrap(); + assert_eq!("borrowed", s); +} + +#[test] +fn null_invalid_type() { + let err = serde_json::from_str::("null").unwrap_err(); + assert_eq!( + format!("{}", err), + String::from("invalid type: null, expected a string at line 1 column 4") + ); +} + +#[test] +fn test_integer128() { + let signed = &[i128::MIN, -1, 0, 1, i128::MAX]; + let unsigned = &[0, 1, u128::MAX]; + + for integer128 in signed { + let expected = integer128.to_string(); + assert_eq!(to_string(integer128).unwrap(), expected); + assert_eq!(from_str::(&expected).unwrap(), *integer128); + } + + for integer128 in unsigned { + let expected = integer128.to_string(); + assert_eq!(to_string(integer128).unwrap(), expected); + assert_eq!(from_str::(&expected).unwrap(), *integer128); + } + + test_parse_err::(&[ + ( + "-170141183460469231731687303715884105729", + "number out of range at line 1 column 40", + ), + ( + "170141183460469231731687303715884105728", + "number out of range at line 1 column 39", + ), + ]); + + test_parse_err::(&[ + ("-1", "number out of range at line 1 column 1"), + ( + "340282366920938463463374607431768211456", + "number out of range at line 1 column 39", + ), + ]); +} + +#[test] +fn test_integer128_to_value() { + let signed = &[i128::from(i64::MIN), i128::from(u64::MAX)]; + let unsigned = &[0, u128::from(u64::MAX)]; + + for integer128 in signed { + let expected = integer128.to_string(); + assert_eq!(to_value(integer128).unwrap().to_string(), expected); + } + + for integer128 in unsigned { + let expected = integer128.to_string(); + assert_eq!(to_value(integer128).unwrap().to_string(), expected); + } + + if !cfg!(feature = "arbitrary_precision") { + let err = to_value(u128::from(u64::MAX) + 1).unwrap_err(); + assert_eq!(err.to_string(), "number out of range"); + } +} + +#[cfg(feature = "raw_value")] +#[test] +fn test_borrowed_raw_value() { + #[derive(Serialize, Deserialize)] + struct Wrapper<'a> { + a: i8, + #[serde(borrow)] + b: &'a RawValue, + c: i8, + } + + let wrapper_from_str: Wrapper = + serde_json::from_str(r#"{"a": 1, "b": {"foo": 2}, "c": 3}"#).unwrap(); + assert_eq!(r#"{"foo": 2}"#, wrapper_from_str.b.get()); + + let wrapper_to_string = serde_json::to_string(&wrapper_from_str).unwrap(); + assert_eq!(r#"{"a":1,"b":{"foo": 2},"c":3}"#, wrapper_to_string); + + let wrapper_to_value = serde_json::to_value(&wrapper_from_str).unwrap(); + assert_eq!(json!({"a": 1, "b": {"foo": 2}, "c": 3}), wrapper_to_value); + + let array_from_str: Vec<&RawValue> = + serde_json::from_str(r#"["a", 42, {"foo": "bar"}, null]"#).unwrap(); + assert_eq!(r#""a""#, array_from_str[0].get()); + assert_eq!("42", array_from_str[1].get()); + assert_eq!(r#"{"foo": "bar"}"#, array_from_str[2].get()); + assert_eq!("null", array_from_str[3].get()); + + let array_to_string = serde_json::to_string(&array_from_str).unwrap(); + assert_eq!(r#"["a",42,{"foo": "bar"},null]"#, array_to_string); +} + +#[cfg(feature = "raw_value")] +#[test] +fn test_raw_value_in_map_key() { + #[derive(RefCast)] + #[repr(transparent)] + struct RawMapKey(RawValue); + + #[allow(unknown_lints)] + #[allow(non_local_definitions)] // false positive: https://github.com/rust-lang/rust/issues/121621 + impl<'de> Deserialize<'de> for &'de RawMapKey { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let raw_value = <&RawValue>::deserialize(deserializer)?; + Ok(RawMapKey::ref_cast(raw_value)) + } + } + + impl PartialEq for RawMapKey { + fn eq(&self, other: &Self) -> bool { + self.0.get() == other.0.get() + } + } + + impl Eq for RawMapKey {} + + impl Hash for RawMapKey { + fn hash(&self, hasher: &mut H) { + self.0.get().hash(hasher); + } + } + + let map_from_str: HashMap<&RawMapKey, &RawValue> = + serde_json::from_str(r#" {"\\k":"\\v"} "#).unwrap(); + let (map_k, map_v) = map_from_str.into_iter().next().unwrap(); + assert_eq!("\"\\\\k\"", map_k.0.get()); + assert_eq!("\"\\\\v\"", map_v.get()); +} + +#[cfg(feature = "raw_value")] +#[test] +fn test_boxed_raw_value() { + #[derive(Serialize, Deserialize)] + struct Wrapper { + a: i8, + b: Box, + c: i8, + } + + let wrapper_from_str: Wrapper = + serde_json::from_str(r#"{"a": 1, "b": {"foo": 2}, "c": 3}"#).unwrap(); + assert_eq!(r#"{"foo": 2}"#, wrapper_from_str.b.get()); + + let wrapper_from_reader: Wrapper = + serde_json::from_reader(br#"{"a": 1, "b": {"foo": 2}, "c": 3}"#.as_ref()).unwrap(); + assert_eq!(r#"{"foo": 2}"#, wrapper_from_reader.b.get()); + + let wrapper_from_value: Wrapper = + serde_json::from_value(json!({"a": 1, "b": {"foo": 2}, "c": 3})).unwrap(); + assert_eq!(r#"{"foo":2}"#, wrapper_from_value.b.get()); + + let wrapper_to_string = serde_json::to_string(&wrapper_from_str).unwrap(); + assert_eq!(r#"{"a":1,"b":{"foo": 2},"c":3}"#, wrapper_to_string); + + let wrapper_to_value = serde_json::to_value(&wrapper_from_str).unwrap(); + assert_eq!(json!({"a": 1, "b": {"foo": 2}, "c": 3}), wrapper_to_value); + + let array_from_str: Vec> = + serde_json::from_str(r#"["a", 42, {"foo": "bar"}, null]"#).unwrap(); + assert_eq!(r#""a""#, array_from_str[0].get()); + assert_eq!("42", array_from_str[1].get()); + assert_eq!(r#"{"foo": "bar"}"#, array_from_str[2].get()); + assert_eq!("null", array_from_str[3].get()); + + let array_from_reader: Vec> = + serde_json::from_reader(br#"["a", 42, {"foo": "bar"}, null]"#.as_ref()).unwrap(); + assert_eq!(r#""a""#, array_from_reader[0].get()); + assert_eq!("42", array_from_reader[1].get()); + assert_eq!(r#"{"foo": "bar"}"#, array_from_reader[2].get()); + assert_eq!("null", array_from_reader[3].get()); + + let array_to_string = serde_json::to_string(&array_from_str).unwrap(); + assert_eq!(r#"["a",42,{"foo": "bar"},null]"#, array_to_string); +} + +#[cfg(feature = "raw_value")] +#[test] +fn test_raw_value_from_string_unchecked() { + #[derive(Serialize)] + struct Wrapper { + a: i8, + b: Box, + c: i8, + } + + let json = r#"{"foo":[1,2,3],"bar":"\"escaped\""}"#.to_owned(); + let checked = RawValue::from_string(json.clone()).unwrap(); + let unchecked = unsafe { RawValue::from_string_unchecked(json) }; + assert_eq!(checked.get(), unchecked.get()); + + let wrapper = Wrapper { + a: 1, + b: unchecked, + c: 3, + }; + let wrapper_to_string = serde_json::to_string(&wrapper).unwrap(); + assert_eq!( + r#"{"a":1,"b":{"foo":[1,2,3],"bar":"\"escaped\""},"c":3}"#, + wrapper_to_string, + ); + + // A string with excess capacity is preserved as-is. + let mut spare = String::with_capacity(64); + spare.push_str("[1,2,3]"); + let raw = unsafe { RawValue::from_string_unchecked(spare) }; + assert_eq!("[1,2,3]", raw.get()); +} + +// The debug_assert! inside from_string_unchecked is compiled out of release +// builds, so #[should_panic] can only be exercised under debug (which is the +// default `cargo test` profile). +#[cfg(all(feature = "raw_value", debug_assertions))] +#[test] +#[should_panic = "from_string_unchecked"] +fn test_raw_value_from_string_unchecked_debug_asserts_whitespace() { + let _ = unsafe { RawValue::from_string_unchecked(" 42".to_owned()) }; +} + +#[cfg(all(feature = "raw_value", debug_assertions))] +#[test] +#[should_panic = "from_string_unchecked"] +fn test_raw_value_from_string_unchecked_debug_asserts_well_formed() { + let _ = unsafe { RawValue::from_string_unchecked("[1,".to_owned()) }; +} + +#[cfg(feature = "raw_value")] +#[test] +fn test_raw_invalid_utf8() { + let j = &[b'"', b'\xCE', b'\xF8', b'"']; + let value_err = serde_json::from_slice::(j).unwrap_err(); + let raw_value_err = serde_json::from_slice::>(j).unwrap_err(); + + assert_eq!( + value_err.to_string(), + "invalid unicode code point at line 1 column 4", + ); + assert_eq!( + raw_value_err.to_string(), + "invalid unicode code point at line 1 column 4", + ); +} + +#[cfg(feature = "raw_value")] +#[test] +fn test_serialize_unsized_value_to_raw_value() { + assert_eq!( + serde_json::value::to_raw_value("foobar").unwrap().get(), + r#""foobar""#, + ); +} + +#[test] +fn test_borrow_in_map_key() { + #[derive(Deserialize, Debug)] + struct Outer { + #[allow(dead_code)] + map: BTreeMap, + } + + #[derive(Ord, PartialOrd, Eq, PartialEq, Debug)] + struct MyMapKey(usize); + + impl<'de> Deserialize<'de> for MyMapKey { + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + let s = <&str>::deserialize(deserializer)?; + let n = s.parse().map_err(de::Error::custom)?; + Ok(MyMapKey(n)) + } + } + + let value = json!({ "map": { "1": null } }); + Outer::deserialize(&value).unwrap(); +} + +#[test] +fn test_value_into_deserializer() { + #[derive(Deserialize)] + struct Outer { + inner: Inner, + } + + #[derive(Deserialize)] + struct Inner { + string: String, + } + + let mut map = BTreeMap::new(); + map.insert("inner", json!({ "string": "Hello World" })); + + let outer = Outer::deserialize(serde::de::value::MapDeserializer::new( + map.iter().map(|(k, v)| (*k, v)), + )) + .unwrap(); + assert_eq!(outer.inner.string, "Hello World"); + + let outer = Outer::deserialize(map.into_deserializer()).unwrap(); + assert_eq!(outer.inner.string, "Hello World"); +} + +#[test] +fn hash_positive_and_negative_zero() { + let rand = std::hash::RandomState::new(); + + let k1 = serde_json::from_str::("0.0").unwrap(); + let k2 = serde_json::from_str::("-0.0").unwrap(); + if cfg!(feature = "arbitrary_precision") { + assert_ne!(k1, k2); + assert_ne!(rand.hash_one(k1), rand.hash_one(k2)); + } else { + assert_eq!(k1, k2); + assert_eq!(rand.hash_one(k1), rand.hash_one(k2)); + } +} + +#[test] +fn test_control_character_search() { + // Different space circumstances + for n in 0..16 { + for m in 0..16 { + test_parse_err::(&[( + &format!("\"{}\n{}\"", " ".repeat(n), " ".repeat(m)), + "control character (\\u0000-\\u001F) found while parsing a string at line 2 column 0", + )]); + } + } + + // Multiple occurrences + test_parse_err::(&[( + "\"\t\n\r\"", + "control character (\\u0000-\\u001F) found while parsing a string at line 1 column 2", + )]); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/ui/missing_colon.rs b/third_party/crates/serde_json-1.0.151/tests/ui/missing_colon.rs new file mode 100644 index 0000000..d93b7b9 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/ui/missing_colon.rs @@ -0,0 +1,5 @@ +use serde_json::json; + +fn main() { + json!({ "a" }); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/ui/missing_colon.stderr b/third_party/crates/serde_json-1.0.151/tests/ui/missing_colon.stderr new file mode 100644 index 0000000..d5f6466 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/ui/missing_colon.stderr @@ -0,0 +1,12 @@ +error: unexpected end of macro invocation + --> tests/ui/missing_colon.rs:4:5 + | +4 | json!({ "a" }); + | ^^^^^^^^^^^^^^ missing tokens in macro arguments + | +note: while trying to match `@` + --> src/macros.rs + | + | (@array [$($elems:expr,)*]) => { + | ^ + = note: this error originates in the macro `$crate::json_internal` which comes from the expansion of the macro `json` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/crates/serde_json-1.0.151/tests/ui/missing_comma.rs b/third_party/crates/serde_json-1.0.151/tests/ui/missing_comma.rs new file mode 100644 index 0000000..8818c3e --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/ui/missing_comma.rs @@ -0,0 +1,5 @@ +use serde_json::json; + +fn main() { + json!({ "1": "" "2": "" }); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/ui/missing_comma.stderr b/third_party/crates/serde_json-1.0.151/tests/ui/missing_comma.stderr new file mode 100644 index 0000000..b0f0e4b --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/ui/missing_comma.stderr @@ -0,0 +1,13 @@ +error: no rules expected `"2"` + --> tests/ui/missing_comma.rs:4:21 + | +4 | json!({ "1": "" "2": "" }); + | -^^^ no rules expected this token in macro call + | | + | help: missing comma here + | +note: while trying to match `,` + --> src/macros.rs + | + | ($e:expr , $($tt:tt)*) => {}; + | ^ diff --git a/third_party/crates/serde_json-1.0.151/tests/ui/missing_value.rs b/third_party/crates/serde_json-1.0.151/tests/ui/missing_value.rs new file mode 100644 index 0000000..0ba14e2 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/ui/missing_value.rs @@ -0,0 +1,5 @@ +use serde_json::json; + +fn main() { + json!({ "a" : }); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/ui/missing_value.stderr b/third_party/crates/serde_json-1.0.151/tests/ui/missing_value.stderr new file mode 100644 index 0000000..69f6ca3 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/ui/missing_value.stderr @@ -0,0 +1,12 @@ +error: unexpected end of macro invocation + --> tests/ui/missing_value.rs:4:5 + | +4 | json!({ "a" : }); + | ^^^^^^^^^^^^^^^^ missing tokens in macro arguments + | +note: while trying to match `@` + --> src/macros.rs + | + | (@array [$($elems:expr,)*]) => { + | ^ + = note: this error originates in the macro `$crate::json_internal` which comes from the expansion of the macro `json` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/crates/serde_json-1.0.151/tests/ui/not_found.rs b/third_party/crates/serde_json-1.0.151/tests/ui/not_found.rs new file mode 100644 index 0000000..2df6870 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/ui/not_found.rs @@ -0,0 +1,5 @@ +use serde_json::json; + +fn main() { + json!({ "a" : x }); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/ui/not_found.stderr b/third_party/crates/serde_json-1.0.151/tests/ui/not_found.stderr new file mode 100644 index 0000000..6fec180 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/ui/not_found.stderr @@ -0,0 +1,5 @@ +error[E0425]: cannot find value `x` in this scope + --> tests/ui/not_found.rs:4:19 + | +4 | json!({ "a" : x }); + | ^ not found in this scope diff --git a/third_party/crates/serde_json-1.0.151/tests/ui/parse_expr.rs b/third_party/crates/serde_json-1.0.151/tests/ui/parse_expr.rs new file mode 100644 index 0000000..e7f1805 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/ui/parse_expr.rs @@ -0,0 +1,5 @@ +use serde_json::json; + +fn main() { + json!({ "a" : ~ }); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/ui/parse_expr.stderr b/third_party/crates/serde_json-1.0.151/tests/ui/parse_expr.stderr new file mode 100644 index 0000000..70cd741 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/ui/parse_expr.stderr @@ -0,0 +1,11 @@ +error: no rules expected `~` + --> tests/ui/parse_expr.rs:4:19 + | +4 | json!({ "a" : ~ }); + | ^ no rules expected this token in macro call + | +note: while trying to match meta-variable `$e:expr` + --> src/macros.rs + | + | ($e:expr , $($tt:tt)*) => {}; + | ^^^^^^^ diff --git a/third_party/crates/serde_json-1.0.151/tests/ui/parse_key.rs b/third_party/crates/serde_json-1.0.151/tests/ui/parse_key.rs new file mode 100644 index 0000000..858bd71 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/ui/parse_key.rs @@ -0,0 +1,5 @@ +use serde_json::json; + +fn main() { + json!({ "".s : true }); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/ui/parse_key.stderr b/third_party/crates/serde_json-1.0.151/tests/ui/parse_key.stderr new file mode 100644 index 0000000..15662dc --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/ui/parse_key.stderr @@ -0,0 +1,5 @@ +error[E0609]: no field `s` on type `&'static str` + --> tests/ui/parse_key.rs:4:16 + | +4 | json!({ "".s : true }); + | ^ unknown field diff --git a/third_party/crates/serde_json-1.0.151/tests/ui/unexpected_after_array_element.rs b/third_party/crates/serde_json-1.0.151/tests/ui/unexpected_after_array_element.rs new file mode 100644 index 0000000..226c58c --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/ui/unexpected_after_array_element.rs @@ -0,0 +1,5 @@ +use serde_json::json; + +fn main() { + json!([ true => ]); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/ui/unexpected_after_array_element.stderr b/third_party/crates/serde_json-1.0.151/tests/ui/unexpected_after_array_element.stderr new file mode 100644 index 0000000..b848e4d --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/ui/unexpected_after_array_element.stderr @@ -0,0 +1,7 @@ +error: no rules expected `=>` + --> tests/ui/unexpected_after_array_element.rs:4:18 + | +4 | json!([ true => ]); + | ^^ no rules expected this token in macro call + | + = note: while trying to match end of macro diff --git a/third_party/crates/serde_json-1.0.151/tests/ui/unexpected_after_map_entry.rs b/third_party/crates/serde_json-1.0.151/tests/ui/unexpected_after_map_entry.rs new file mode 100644 index 0000000..0dfb731 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/ui/unexpected_after_map_entry.rs @@ -0,0 +1,5 @@ +use serde_json::json; + +fn main() { + json!({ "k": true => }); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/ui/unexpected_after_map_entry.stderr b/third_party/crates/serde_json-1.0.151/tests/ui/unexpected_after_map_entry.stderr new file mode 100644 index 0000000..9f77c07 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/ui/unexpected_after_map_entry.stderr @@ -0,0 +1,7 @@ +error: no rules expected `=>` + --> tests/ui/unexpected_after_map_entry.rs:4:23 + | +4 | json!({ "k": true => }); + | ^^ no rules expected this token in macro call + | + = note: while trying to match end of macro diff --git a/third_party/crates/serde_json-1.0.151/tests/ui/unexpected_colon.rs b/third_party/crates/serde_json-1.0.151/tests/ui/unexpected_colon.rs new file mode 100644 index 0000000..e767ea6 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/ui/unexpected_colon.rs @@ -0,0 +1,5 @@ +use serde_json::json; + +fn main() { + json!({ : true }); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/ui/unexpected_colon.stderr b/third_party/crates/serde_json-1.0.151/tests/ui/unexpected_colon.stderr new file mode 100644 index 0000000..d47e881 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/ui/unexpected_colon.stderr @@ -0,0 +1,7 @@ +error: no rules expected `:` + --> tests/ui/unexpected_colon.rs:4:13 + | +4 | json!({ : true }); + | ^ no rules expected this token in macro call + | + = note: while trying to match end of macro diff --git a/third_party/crates/serde_json-1.0.151/tests/ui/unexpected_comma.rs b/third_party/crates/serde_json-1.0.151/tests/ui/unexpected_comma.rs new file mode 100644 index 0000000..338874e --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/ui/unexpected_comma.rs @@ -0,0 +1,5 @@ +use serde_json::json; + +fn main() { + json!({ "a" , "b": true }); +} diff --git a/third_party/crates/serde_json-1.0.151/tests/ui/unexpected_comma.stderr b/third_party/crates/serde_json-1.0.151/tests/ui/unexpected_comma.stderr new file mode 100644 index 0000000..e308274 --- /dev/null +++ b/third_party/crates/serde_json-1.0.151/tests/ui/unexpected_comma.stderr @@ -0,0 +1,7 @@ +error: no rules expected `,` + --> tests/ui/unexpected_comma.rs:4:17 + | +4 | json!({ "a" , "b": true }); + | ^ no rules expected this token in macro call + | + = note: while trying to match end of macro diff --git a/third_party/crates/syn-3.0.5/.cargo-checksum.json b/third_party/crates/syn-3.0.5/.cargo-checksum.json new file mode 100644 index 0000000..c0818f6 --- /dev/null +++ b/third_party/crates/syn-3.0.5/.cargo-checksum.json @@ -0,0 +1 @@ +{"$comment":"This file only protects against accidental modifications. It is not a security mechanism and does not protect against malicious changes.","files":{".cargo_vcs_info.json":"d1ccb7a3cb07e9478916c1b8fa72b85f75f35b2823ccd937e64538e6c1ece7d1","Cargo.lock":"e2223ded58505049d0513b0b8929cec1b27fc11cb6418f2764484e9a1242e37d","Cargo.toml":"6447bd9e45a88d404c311a5ff4e16018f468c5739723f7d5caf61887dbff7caf","Cargo.toml.orig":"c5c3d398ef17ea056964ee24a9f54e56782810746efd46d3e4f3563ac19b46a7","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"a00f270c7f468863f28b9984547872efb57c7db1b9beb6e685852dc24de6846e","benches/file.rs":"6f2ae7748d1576cff48e4ef55d4e87e2f5bb7898a36aa99ea6dd6ed0f72a4e3c","benches/rust.rs":"4ad250087795831d7c79b130d47927b5c733052c9659de039c08835b74be72b1","src/attr.rs":"2108cf48c98ed0a7833ec73b841fccc254c733453a7e69127b0255541bbc9572","src/bigint.rs":"21cf6cf0c8e175421a6579321878e140d6cd2c975e5bdac4eadde25907d7e879","src/buffer.rs":"ddb6d50a9e79dc1db86d819d41dbf532e172997c8e0101d73c95052835756c50","src/classify.rs":"980e81540ddf0414bbfa6fc4f543127d39da84337732a6353473afbd547267f0","src/custom_keyword.rs":"322114e36ae43a2f8605506fb4568efdbc2986853e2fee74bd10a4ca0fb60c69","src/custom_punctuation.rs":"67134b7685ce89eddb7bf4ee3c9a48e5eb8ecbb1703cd49a01cbb115239fb814","src/data.rs":"78280858745d59b721098c7d7f8aa99dddd9e519908d75a1c4444c9c455875d6","src/derive.rs":"4927cfd64d2c61bb9ee8462b83d5bbce77e3f85c3a03a5565ecf6f08d55367c3","src/discouraged.rs":"7b5ca0fb3120970d028ddd4efc69363fea278a0b6ed5160d82295c326b3b08ac","src/drops.rs":"c48e679507424c08716b48256a06d59fe55e877de336c40f0df56cfd80e23826","src/error.rs":"5ed698f9dd63f16775e48455919a626a246d2ac38d682c1ba37a0ff561ed0a7b","src/export.rs":"d9039ba7f1455089139cf8a6871159f0ec57949cc730b42fe3c318a8397d3368","src/expr.rs":"5a3dc478d7b76a13f2bd7632ccb8f2f9733c1081fce527a17dabd7a7e99161a2","src/ext.rs":"8bc0d0ffab88c73d2305c9f588e6b5285501de8869308162f91019c83bc5bdf1","src/file.rs":"4513d0f1f4a4d78ba94c0895e97aadc0c2ebcf6f5da36abf762e77e813bc9aea","src/fixup.rs":"7647cde30efdce96b1488ae805788c168d4499b464b7d421abc17ea8ffde66f2","src/gen/clone.rs":"342704f87c06f11b4b6b60689df5f55e7a9a67d656b9286cc23a364f485c135f","src/gen/debug.rs":"29782ea05d86b95e98bb664d6688c413c871dc78f5dc9ee81f584aaa63e85558","src/gen/eq.rs":"15f2b5070ea8fccf07dbff6bf2fdc027c6d913599b5c1a8e8a5bc9e39e601133","src/gen/fold.rs":"4804ee04ce6ed8437a9e5d2a54a3ca91f711098034f95ac7102ca0928783dc3e","src/gen/hash.rs":"ac638e8b56722dd890bd06297a2902b9015cf85e2c50432258b050e43cc1d4cf","src/gen/token.css":"f79afb8272b8c9b6fe63716c6be5c53d8e7c5ca5473bf3ec891b6e1be9887716","src/gen/visit.rs":"32414282294ae0d0fbbe863c51cf26c2fc3fb6843dbf715d96f5ad69f3048c2c","src/gen/visit_mut.rs":"1d76d69baddc4f1354399cab7309a5a2738b3850ad249f793b596fc854c4e8d1","src/generics.rs":"a563693b6c9ec11d61b2ce7f869763a3c967879dd9306743f01203cd9555cda1","src/group.rs":"61e067094aa930b6550dc3717a5aaeef7dabfdcf1a177f83fb636598fa7e4e72","src/ident.rs":"a17e32b0d997649c4c986d1c9eef24be5331cd9ab478604932297b55f785487a","src/item.rs":"11529dc48c5045d3b0f7947d05ea5aadf0f389f4a8e0b25222333042721ab10f","src/lib.rs":"7a274648ad0364fff73af90e8cc9b2cf404604b8364c82648398417d520421d5","src/lifetime.rs":"2f3a240a4a0d9536dd1e3255d5ae0d64efcc46f295cf565a09e8ac33cd3d3487","src/lit.rs":"b474ef6e974844ba972c0fcedf3e075f03e822faf4e55a9b27f648efe7121098","src/lookahead.rs":"ea51bbf9a23d68238f8324a51675f5815fb3e5fc08c6bab93bc2648d3342c38f","src/mac.rs":"fdce8291f71adef3f69975f229156dca2309ca232ed943061afaf96220908ab8","src/macros.rs":"dfc278625948d727ef06e058a94483bbcc551b62b8eb736dc7cd9e0a4777866f","src/meta.rs":"d8703f8cbc5fd6465c367214eac38efca0f8388bdef8ac5e6f863835fbd3b30f","src/op.rs":"a61757370f802e44efa3c4a1057ae2cd26e64e273f7d76c06d5ffb49602319e2","src/parse.rs":"e692d6e895ac79a14680b89a7c29611995126953238176bdb50d2a3c2fb2d9e3","src/parse_macro_input.rs":"e4e22b63d0496d06a4ca17742a22467ed93f08a739081324773828bad63175ee","src/parse_quote.rs":"c0ae210cfe6d6b8f6758cff1f44283acd9df5ed67d88911875079fb28d4d1b67","src/pat.rs":"3258bdaca2be2c692cd9bb09a89f811f53b176939a57ce46c0d89284628fc830","src/path.rs":"088ff7dc2cd278efc32017722887d6849866e54ab7d7ae47710edf785c0cc478","src/precedence.rs":"301f5cc51e1bbb35aeb64f6ed1b21d6f61d83f6c048aec9896976ee0011b948e","src/print.rs":"22910bf0521ab868ebd7c62601c55912d12cfb400c65723e08e5cfa3a2d111c0","src/punctuated.rs":"6b70fd15cc662260c2c0f20cd35a777351b2c5199b299cf5c8d8972723bd0f04","src/restriction.rs":"9506f1dd5710a380a8298dc8b345a0849a011e447e1aca08c4ca29543a65273b","src/scan_expr.rs":"1afda43a7f4e9d426859a90d8a62a58c6654f3be41bb274d4884a56ac08f8eee","src/sealed.rs":"6ece3b3dcb30f6bb98b93d83759ca7712ee8592bef9c0511141039c38765db0e","src/span.rs":"0a48e375e5c9768f6f64174a91ba6a255f4b021e2fb3548d8494e617f142601b","src/spanned.rs":"b53ce23f10935cf202da0f5a430e9feca9f4858bbd6efbe896acf17d3cfce540","src/stmt.rs":"60718ffd8e4b72bae9ea620670276af3bd407f248f2c5e3bd945a2ea8c541661","src/thread.rs":"b91e33c563c2ea584fcd7c5454998303173f4227bdb19504776e61d09b60675c","src/token.rs":"fddf7540f6c87e088ca2e4cd59a4769bc99989907a71e0d7cb42ee6ec067a6ac","src/tt.rs":"d5b9df076504b1506e0b05dafb9006fd0772fdb8d4b8b8dcc315dbca3277331a","src/ty.rs":"63bbf2272575d40ba632b54ca51857f43410bc22c20ff3ecedee3d3f52dd84e5","src/verbatim.rs":"503055ba92ebb97da71a8a7cae1e6606969aadfb965b0d6c7e56693f9ef66b0a","src/whitespace.rs":"9cdcbfe9045b259046329a795bc1105ab5a871471a6d3f7318d275ee53f7a825","tests/common/eq.rs":"6960fd58a534c3371d1671aaf35f9498222a4c3bca2e952e6208e084adf0fe85","tests/common/mod.rs":"b752aa8f1faf8c6abf1286a12fb50b6c257ec1889d81bcdb3dc3257134695a89","tests/common/parse.rs":"b1685e9e0f0569f48d66ddd92d787a12933a1d2f95e7c9ae974a3648763f989b","tests/common/visit.rs":"a260ecd2ce7853cd3644e19aba08e8d358a656fd3fb0f1287cea40c59c9e62c9","tests/debug/gen.rs":"75b59398bb58e8d05c5ee5598b88163564b480c866af3dddb9bcc69e8df8459a","tests/debug/mod.rs":"1259df940bbcaa968a837e402d6853f2efa38d2260e306d42f17f9e8ef74fae5","tests/macros/mod.rs":"d2294a79e341c623ae671dd363e99965d78dda7f340b0cc038267207adfacae2","tests/regression.rs":"e9565ea0efecb4136f099164ffcfa26e1996b0a27fb9c6659e90ad9bdd42e7b6","tests/regression/issue1108.rs":"f32db35244a674e22ff824ca9e5bbec2184e287b59f022db68c418b5878a2edc","tests/regression/issue1235.rs":"a2266b10c3f7c7af5734817ab0a3e8b309b51e7d177b63f26e67e6b744d280b0","tests/repo/mod.rs":"a86074ef6992d93768d9af0e6d8bac21cc9a3378d158a3e1edde0e12a9ebf959","tests/repo/progress.rs":"11219e4ae5e0175d5ddc743907a57b8c4e750e709687c3df53728d6af994a86f","tests/snapshot/mod.rs":"4a101272c5abe6ca9f3501e0cacacee9a0ccf7ca773348a239e5b046d0316a7e","tests/test_attribute.rs":"8a4429b7cfe2360bb73beae54a62ae3255ebbd5181467a8608d6f858c2711728","tests/test_derive_input.rs":"ac6fff053bded4ca30f88343cbf984a319119b58805f56058bd6ad61a1f60972","tests/test_expr.rs":"478d1f99f5cf001f3566ea01ee9a54cf913f47a0d0eb96bc2b3dbc78c8745cba","tests/test_generics.rs":"2bd20cbaab8ff268e6e283ae9564f064f352deab7d3d4beafb7f41baa2b862cf","tests/test_grouping.rs":"fe3de6e8824f0722ab6450c6dfc374f6e0f8fe75c87c4dd56b2cb00a2197ed58","tests/test_ident.rs":"d5850e817720e774cd397a46dbc5298c57933823c18e20805e84503fc9387e8f","tests/test_item.rs":"49f7130127da9077dc39cb1c3b9a70b55f62c39555b48bf9c7f5bb07fc506531","tests/test_lit.rs":"4130efa425d14ed3ad9a1c2a00ef4b29782c9d1cf9e29ff9dddd3b23b2e3ddee","tests/test_meta.rs":"5b0fdee0decbd07476c9673403a662de385901b4bf60600c26ac879893f5bf9c","tests/test_parse_buffer.rs":"1c8cbbf457603bd0a83348079591f843f7ef0533a6275a0c76533e2d07dd321a","tests/test_parse_quote.rs":"2fc6fcd5f6ab063fb26dd64e087a8a0799f0650b7249c1c4f3b08b870b89ed22","tests/test_parse_stream.rs":"b6b533432173123d6d01d8d2cb33714bc50b30b16ffbb6116f93937221ad4594","tests/test_pat.rs":"91458c108f6d8a1660e5633cde6441b0e583f7fa8f36375dcf0a051301eb3d34","tests/test_path.rs":"4957de8bd9e0c158cfa91dc12ec3b16132d243f0d1f3184d827ac6da5ab1739f","tests/test_precedence.rs":"fd6da10bb2414f1a6fc6d18dbbcd773bae9179b405abb06de5874f09848f3887","tests/test_punctuated.rs":"efed2c281b6965d71b065c7606631ba1989af6e7b5f5d1ca1033f8b968dc076c","tests/test_receiver.rs":"c94e39e57b21844b9c89f9da672da33e83046a409f6d8d00422652f92e703d43","tests/test_round_trip.rs":"b784443cfc084e48f1b9fd4d1b2583d19d6e1ec9e5f4137fafc288dd3a44fc49","tests/test_shebang.rs":"785345c798689328060d59a715ed1a54f7a72e9d0305f2f2a1ed84102bcf100b","tests/test_size.rs":"2928bfc73c6a1dc1a7a4fc31bbd1ce8583f97aea4b3adf747dad325bfa748ef0","tests/test_stmt.rs":"17a3f6f7bbd25b428e8761de34b628c99afceacd339350909bbad13614a96cec","tests/test_token_trees.rs":"c30b921a96739c9334ec2bdd06552729891e0251b9d8fbdf0b8f5cc897babee5","tests/test_ty.rs":"5b70d0bc3a02ef6b06f39e4ba5a29df56f1e2237b365f9a0ea1f146b1e2386d2","tests/test_unparenthesize.rs":"a304a65af2cd4ec4b9ab1925727ebfc25b8cb39296f8e6d316d882c381c568da","tests/test_visibility.rs":"811a5df8923426bc24f1bc5e6e346dbbde5ce2ae3143867d81332200ad082494","tests/zzz_stable.rs":"2a862e59cb446235ed99aec0e6ada8e16d3ecc30229b29d825b7c0bbc2602989"},"package":"12df2e0110f65b775f769bb17ef989067a1d931b2eb822bd4346631eeada89f9"} \ No newline at end of file diff --git a/third_party/crates/syn-3.0.5/.cargo_vcs_info.json b/third_party/crates/syn-3.0.5/.cargo_vcs_info.json new file mode 100644 index 0000000..f8dfb21 --- /dev/null +++ b/third_party/crates/syn-3.0.5/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "e0ad92d68b588c964e82bb74c3bd3e1e99f97ceb" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/third_party/crates/syn-3.0.5/BUILD.bazel b/third_party/crates/syn-3.0.5/BUILD.bazel new file mode 100644 index 0000000..8f437ec --- /dev/null +++ b/third_party/crates/syn-3.0.5/BUILD.bazel @@ -0,0 +1,122 @@ +############################################################################### +# @generated +# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To +# regenerate this file, run the following: +# +# bazel run @@//third_party:vendor_crates +############################################################################### + +load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") +load("@rules_rust//rust:defs.bzl", "rust_library") + +package(default_visibility = ["//visibility:public"]) + +cargo_toml_env_vars( + name = "cargo_toml_env_vars", + src = "Cargo.toml", +) + +rust_library( + name = "syn", + srcs = glob( + include = ["**/*.rs"], + allow_empty = False, + ), + compile_data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + crate_features = [ + "clone-impls", + "derive", + "parsing", + "printing", + "proc-macro", + ], + crate_root = "src/lib.rs", + edition = "2021", + rustc_env_files = [ + ":cargo_toml_env_vars", + ], + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=syn", + "manual", + "noclippy", + "norustfmt", + ], + target_compatible_with = select({ + "@rules_rust//rust/platform:aarch64-apple-darwin": [], + "@rules_rust//rust/platform:aarch64-apple-ios": [], + "@rules_rust//rust/platform:aarch64-apple-ios-macabi": [], + "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], + "@rules_rust//rust/platform:aarch64-linux-android": [], + "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], + "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], + "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-none": [], + "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], + "@rules_rust//rust/platform:aarch64-unknown-uefi": [], + "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], + "@rules_rust//rust/platform:armv7-linux-androideabi": [], + "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:i686-apple-darwin": [], + "@rules_rust//rust/platform:i686-linux-android": [], + "@rules_rust//rust/platform:i686-pc-windows-msvc": [], + "@rules_rust//rust/platform:i686-unknown-freebsd": [], + "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], + "@rules_rust//rust/platform:loongarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:mips-unknown-linux-gnu": [], + "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv32imac-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], + "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-netbsd": [], + "@rules_rust//rust/platform:sparc64-unknown-openbsd": [], + "@rules_rust//rust/platform:thumbv6m-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabihf": [], + "@rules_rust//rust/platform:thumbv7m-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabihf": [], + "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], + "@rules_rust//rust/platform:wasm32-unknown-unknown": [], + "@rules_rust//rust/platform:wasm32-wasip1": [], + "@rules_rust//rust/platform:wasm32-wasip1-threads": [], + "@rules_rust//rust/platform:wasm32-wasip2": [], + "@rules_rust//rust/platform:x86_64-apple-darwin": [], + "@rules_rust//rust/platform:x86_64-apple-ios": [], + "@rules_rust//rust/platform:x86_64-apple-ios-macabi": [], + "@rules_rust//rust/platform:x86_64-linux-android": [], + "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], + "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], + "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], + "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-none": [], + "@rules_rust//rust/platform:x86_64-unknown-uefi": [], + "//conditions:default": ["@platforms//:incompatible"], + }), + version = "3.0.5", + deps = [ + "//third_party/crates/proc-macro2-1.0.107:proc_macro2", + "//third_party/crates/quote-1.0.47:quote", + "//third_party/crates/unicode-ident-1.0.24:unicode_ident", + ], +) diff --git a/third_party/crates/syn-3.0.5/Cargo.lock b/third_party/crates/syn-3.0.5/Cargo.lock new file mode 100644 index 0000000..f159469 --- /dev/null +++ b/third_party/crates/syn-3.0.5/Cargo.lock @@ -0,0 +1,1932 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "anyhow" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "automod" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a273e731a7fb8c2268fd2932c9e9a3469f4fd171d85d070d2687190229653bd3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "aws-lc-rs" +version = "1.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b281d307588d634de920874890732659e2e7672f72b5e10e81badc1a8a83621e" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bff6c3b54fad79a2e60b8102caf565819711497c1f5f092f49508e2f5c31b27" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", + "pkg-config", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" + +[[package]] +name = "cc" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "005ec2760ca554fae18df7a11195552ec576cd665632a881bc011d5bb2fd4d80" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" + +[[package]] +name = "chacha20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" +dependencies = [ + "cfg-if", + "cpufeatures", + "rand_core", +] + +[[package]] +name = "cmake" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +dependencies = [ + "cc", +] + +[[package]] +name = "combine" +version = "4.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfc320937d09e6de266b31b9afb480f197d7a861be86be7cb2ea7e5d1bfffc5e" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "console" +version = "0.16.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fe5f465a4f6fee88fad41b85d990f84c835335e85b5d9e6e63e0d06d28cba7c" +dependencies = [ + "encode_unicode", + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8498c871161e1742aaa9d52551b2d6ebdd4c3d45a3be423e3728f33b955be550" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" + +[[package]] +name = "displaydoc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.4", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "either" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" + +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "fastrand" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + +[[package]] +name = "filetime" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759" +dependencies = [ + "cfg-if", + "libc", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e0f1c7c3a72c66fd80abe965175f7523475c0489a87d3ff9d6e8c87d87a9d2d" + +[[package]] +name = "flate2" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb" +dependencies = [ + "crc32fast", + "miniz_oxide", + "zlib-rs", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "futures-channel" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-io" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" + +[[package]] +name = "futures-sink" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi", + "rand_core", + "wasm-bindgen", +] + +[[package]] +name = "h2" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef8e5e5a340588f4452631496976cf8636d4a7ecf600239fdc27615d2530bc16" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "http" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23169fe34a5fbcdd3f3862e78fb9b6fccd5f02a6dc6f732547005d45631ce71c" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b501faa50e7a26c3d3560ca625132f4078a17771f4810baf70475ae48cbe43" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "system-configuration", + "tokio", + "tower-service", + "tracing", + "windows-registry", +] + +[[package]] +name = "icu_collections" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" + +[[package]] +name = "icu_properties" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" + +[[package]] +name = "icu_provider" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07aa2048142242915a31d35844fb311e0e53fcca590c3a0a40dcf1b841fa09eb" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "insta" +version = "1.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f0f8fee8c926415c58d6ae43a08523a26faccb2323f5e6b644fe7dd4ef6b82" +dependencies = [ + "console", + "once_cell", + "similar", + "tempfile", +] + +[[package]] +name = "ipnet" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a756c3fac73139e83f14c2d742155dd2b78d3ee56597b419a0579b7bdd6dd78" + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys", + "log", + "simd_cesu8", + "thiserror", + "walkdir", + "windows-link", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn 2.0.119", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.119", +] + +[[package]] +name = "jobserver" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" +dependencies = [ + "getrandom 0.4.3", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0c1080212aad755ea003d18543e8768dd432c48819efd73a7bf1e39b7a5a3a" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" + +[[package]] +name = "log" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63fbc4a50860e98e7b2aa7804ded1db5cbc3aff9193adaff57a6931bf7c4b4c" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b18443e9c262bfe8fa82f51666e2642c53393f7e5c27b3e1aeab922cff5b9d8" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkg-config" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" + +[[package]] +name = "potential_utf" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" +dependencies = [ + "zerovec", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quinn" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04759210543be93709136e28212294a659ef5001836ff4eab4d663e4529bba83" +dependencies = [ + "aws-lc-rs", + "bytes", + "getrandom 0.4.3", + "lru-slab", + "rand", + "rand_pcg", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.61.2", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rand_pcg" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rayon" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "ref-cast" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e440fb4e4b4147295338efb76001ab9e4efc0e5839df2c47fc5ac2381d365c3" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.4", +] + +[[package]] +name = "reqwest" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "mime", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0283386ce02abc0151e1761d08802dfe86c173b0b494af5cbc086574e453da06" +dependencies = [ + "aws-lc-rs", + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0" +dependencies = [ + "core-foundation 0.10.1", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.103.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags", + "core-foundation 0.10.1", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.4", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "simd-adler32" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" + +[[package]] +name = "simd_cesu8" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "similar" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9be42f50aa861c555654aa3a37f52f4b1074bacf4e48fe0ef7fa584e80f1f0f" + +[[package]] +name = "socket2" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6275cddf4610d1775e6d1fe9469b2e77d0f39fd98fb7450901b821e0c53649f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.5" +dependencies = [ + "anyhow", + "automod", + "flate2", + "insta", + "proc-macro2", + "quote", + "rayon", + "ref-cast", + "reqwest", + "rustversion", + "syn-test-suite", + "tar", + "termcolor", + "unicode-ident", + "walkdir", +] + +[[package]] +name = "syn-test-suite" +version = "0.0.0+test" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0d661992f60e67c8bdd9a7d6360d30d1301f5783abf7d59933844f656762eb5" + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "system-configuration" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" +dependencies = [ + "bitflags", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tar" +version = "0.4.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.3", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.4", +] + +[[package]] +name = "tinystr" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cf0ded5c4e56918d8f8a339e1bb67d038d3bc6d144ac407904015ba2e4cde9b" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c85f2c3ef0b1cd58b36682f4b17aaa995f0e5db534d85692b4903abce21f67" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "libc", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", + "url", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b70935747edd64d89de3efa29d73789b806c15798f8e7dca4d8ac356b50ce70" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b7777d5cc23d0e91404e53ce2d5e8ec7acae3026b16233dba62cd3246457950" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77775f8f3f7217702089053b94958f8f54061a3f663417df76e19cbdcca29bc1" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e11d33f857dc2fb11b8bc75aee111aa9cbeb12cd9f25efd3d4c2a3dd4e235284" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.119", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef64dbcc55df09c7e5a46182d181c2cfa3e925f3da937ea764728b4bbb9dcbf" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c435338968042f4f59a557f690a253676d47ce13ceb55d70100e7facf6620a30" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-root-certs" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b96554aa2acc8ccdb7e1c9a58a7a68dd5d13bccc69cd124cb09406db612a1c9b" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "writeable" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" + +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix", +] + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" + +[[package]] +name = "zerotrie" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.4", +] + +[[package]] +name = "zlib-rs" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34b31d188d9d685a4f9c7b46d6e36631b07058d2cfe190267adce54dc230bf12" diff --git a/third_party/crates/syn-3.0.5/Cargo.toml b/third_party/crates/syn-3.0.5/Cargo.toml new file mode 100644 index 0000000..a18bffe --- /dev/null +++ b/third_party/crates/syn-3.0.5/Cargo.toml @@ -0,0 +1,268 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.71" +name = "syn" +version = "3.0.5" +authors = ["David Tolnay "] +build = false +include = [ + "/benches/**", + "/Cargo.toml", + "/LICENSE-APACHE", + "/LICENSE-MIT", + "/README.md", + "/src/**", + "/tests/**", +] +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Parser for Rust source code" +documentation = "https://docs.rs/syn" +readme = "README.md" +keywords = [ + "macros", + "syn", +] +categories = [ + "development-tools::procedural-macro-helpers", + "parser-implementations", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/dtolnay/syn" + +[package.metadata.docs.rs] +all-features = true +targets = ["x86_64-unknown-linux-gnu"] +rustdoc-args = [ + "--generate-link-to-definition", + "--generate-macro-expansion", + "--extend-css=src/gen/token.css", + "--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", +] + +[package.metadata.playground] +features = [ + "full", + "visit", + "visit-mut", + "fold", + "extra-traits", +] + +[features] +clone-impls = [] +default = [ + "derive", + "parsing", + "printing", + "clone-impls", + "proc-macro", +] +derive = [] +extra-traits = [] +fold = [] +full = [] +parsing = [] +printing = ["dep:quote"] +proc-macro = [ + "proc-macro2/proc-macro", + "quote?/proc-macro", +] +test = ["syn-test-suite/all-features"] +visit = [] +visit-mut = [] + +[lib] +name = "syn" +path = "src/lib.rs" + +[[test]] +name = "regression" +path = "tests/regression.rs" + +[[test]] +name = "test_attribute" +path = "tests/test_attribute.rs" + +[[test]] +name = "test_derive_input" +path = "tests/test_derive_input.rs" + +[[test]] +name = "test_expr" +path = "tests/test_expr.rs" + +[[test]] +name = "test_generics" +path = "tests/test_generics.rs" + +[[test]] +name = "test_grouping" +path = "tests/test_grouping.rs" + +[[test]] +name = "test_ident" +path = "tests/test_ident.rs" + +[[test]] +name = "test_item" +path = "tests/test_item.rs" + +[[test]] +name = "test_lit" +path = "tests/test_lit.rs" + +[[test]] +name = "test_meta" +path = "tests/test_meta.rs" + +[[test]] +name = "test_parse_buffer" +path = "tests/test_parse_buffer.rs" + +[[test]] +name = "test_parse_quote" +path = "tests/test_parse_quote.rs" + +[[test]] +name = "test_parse_stream" +path = "tests/test_parse_stream.rs" + +[[test]] +name = "test_pat" +path = "tests/test_pat.rs" + +[[test]] +name = "test_path" +path = "tests/test_path.rs" + +[[test]] +name = "test_precedence" +path = "tests/test_precedence.rs" + +[[test]] +name = "test_punctuated" +path = "tests/test_punctuated.rs" + +[[test]] +name = "test_receiver" +path = "tests/test_receiver.rs" + +[[test]] +name = "test_round_trip" +path = "tests/test_round_trip.rs" + +[[test]] +name = "test_shebang" +path = "tests/test_shebang.rs" + +[[test]] +name = "test_size" +path = "tests/test_size.rs" + +[[test]] +name = "test_stmt" +path = "tests/test_stmt.rs" + +[[test]] +name = "test_token_trees" +path = "tests/test_token_trees.rs" + +[[test]] +name = "test_ty" +path = "tests/test_ty.rs" + +[[test]] +name = "test_unparenthesize" +path = "tests/test_unparenthesize.rs" + +[[test]] +name = "test_visibility" +path = "tests/test_visibility.rs" + +[[test]] +name = "zzz_stable" +path = "tests/zzz_stable.rs" + +[[bench]] +name = "file" +path = "benches/file.rs" +required-features = [ + "full", + "parsing", +] + +[[bench]] +name = "rust" +path = "benches/rust.rs" +harness = false +required-features = [ + "full", + "parsing", +] + +[dependencies.proc-macro2] +version = "1.0.91" +default-features = false + +[dependencies.quote] +version = "1.0.35" +optional = true +default-features = false + +[dependencies.unicode-ident] +version = "1" + +[dev-dependencies.anyhow] +version = "1" + +[dev-dependencies.automod] +version = "1" + +[dev-dependencies.insta] +version = "1" + +[dev-dependencies.ref-cast] +version = "1" + +[dev-dependencies.rustversion] +version = "1" + +[dev-dependencies.syn-test-suite] +version = "0" + +[dev-dependencies.termcolor] +version = "1" + +[target."cfg(not(miri))".dev-dependencies.flate2] +version = "1" + +[target."cfg(not(miri))".dev-dependencies.rayon] +version = "1" + +[target."cfg(not(miri))".dev-dependencies.reqwest] +version = "0.13" +features = ["blocking"] + +[target."cfg(not(miri))".dev-dependencies.tar] +version = "0.4.16" + +[target."cfg(not(miri))".dev-dependencies.walkdir] +version = "2.3.2" diff --git a/third_party/crates/syn-3.0.5/Cargo.toml.orig b/third_party/crates/syn-3.0.5/Cargo.toml.orig new file mode 100644 index 0000000..7e6765a --- /dev/null +++ b/third_party/crates/syn-3.0.5/Cargo.toml.orig @@ -0,0 +1,95 @@ +[package] +name = "syn" +version = "3.0.5" +authors = ["David Tolnay "] +categories = ["development-tools::procedural-macro-helpers", "parser-implementations"] +description = "Parser for Rust source code" +documentation = "https://docs.rs/syn" +edition = "2021" +include = [ + "/benches/**", + "/Cargo.toml", + "/LICENSE-APACHE", + "/LICENSE-MIT", + "/README.md", + "/src/**", + "/tests/**", +] +keywords = ["macros", "syn"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/dtolnay/syn" +rust-version = "1.71" + +[features] +default = ["derive", "parsing", "printing", "clone-impls", "proc-macro"] +derive = [] +full = [] +parsing = [] +printing = ["dep:quote"] +visit = [] +visit-mut = [] +fold = [] +clone-impls = [] +extra-traits = [] +proc-macro = ["proc-macro2/proc-macro", "quote?/proc-macro"] +test = ["syn-test-suite/all-features"] + +[dependencies] +proc-macro2 = { version = "1.0.91", default-features = false } +quote = { version = "1.0.35", optional = true, default-features = false } +unicode-ident = "1" + +[dev-dependencies] +anyhow = "1" +automod = "1" +insta = "1" +ref-cast = "1" +rustversion = "1" +syn-test-suite = { version = "0", path = "tests/features" } +termcolor = "1" + +[target.'cfg(not(miri))'.dev-dependencies] +flate2 = "1" +rayon = "1" +reqwest = { version = "0.13", features = ["blocking"] } +tar = "0.4.16" +walkdir = "2.3.2" + +[[bench]] +name = "rust" +harness = false +required-features = ["full", "parsing"] + +[[bench]] +name = "file" +required-features = ["full", "parsing"] + +[package.metadata.docs.rs] +all-features = true +targets = ["x86_64-unknown-linux-gnu"] +rustdoc-args = [ + "--generate-link-to-definition", + "--generate-macro-expansion", + "--extend-css=src/gen/token.css", + "--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", +] + +[package.metadata.playground] +features = ["full", "visit", "visit-mut", "fold", "extra-traits"] + +[workspace] +members = [ + "dev", + "examples/dump-syntax", + "examples/heapsize/example", + "examples/heapsize/heapsize", + "examples/heapsize/heapsize_derive", + "examples/lazy-static/example", + "examples/lazy-static/lazy-static", + "examples/trace-var/example", + "examples/trace-var/trace-var", + "tests/features", +] diff --git a/third_party/crates/syn-3.0.5/LICENSE-APACHE b/third_party/crates/syn-3.0.5/LICENSE-APACHE new file mode 100644 index 0000000..1b5ec8b --- /dev/null +++ b/third_party/crates/syn-3.0.5/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/third_party/crates/syn-3.0.5/LICENSE-MIT b/third_party/crates/syn-3.0.5/LICENSE-MIT new file mode 100644 index 0000000..31aa793 --- /dev/null +++ b/third_party/crates/syn-3.0.5/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/crates/syn-3.0.5/README.md b/third_party/crates/syn-3.0.5/README.md new file mode 100644 index 0000000..9618ce8 --- /dev/null +++ b/third_party/crates/syn-3.0.5/README.md @@ -0,0 +1,297 @@ +Parser for Rust source code +=========================== + +[github](https://github.com/dtolnay/syn) +[crates.io](https://crates.io/crates/syn) +[docs.rs](https://docs.rs/syn) +[build status](https://github.com/dtolnay/syn/actions?query=branch%3Amaster) + +Syn is a parsing library for parsing a stream of Rust tokens into a syntax tree +of Rust source code. + +Currently this library is geared toward use in Rust procedural macros, but +contains some APIs that may be useful more generally. + +- **Data structures** — Syn provides a syntax tree that can represent most + stable Rust source code and some unstable syntax. The syntax tree is rooted at + [`syn::File`] which represents a full source file, but there are other entry + points that may be useful to procedural macros including [`syn::Item`], + [`syn::Expr`] and [`syn::Type`]. + +- **Derives** — Of particular interest to derive macros is [`syn::DeriveInput`] + which is any of the three legal input items to a derive macro. An example + below shows using this type in a library that can derive implementations of a + user-defined trait. + +- **Parsing** — Parsing in Syn is built around [parser functions] with the + signature `fn(ParseStream) -> Result`. Every syntax tree node defined by + Syn is individually parsable and may be used as a building block for custom + syntaxes, or you may dream up your own brand new syntax without involving any + of our syntax tree types. + +- **Location information** — Every token parsed by Syn is associated with a + `Span` that tracks line and column information back to the source of that + token. These spans allow a procedural macro to display detailed error messages + pointing to all the right places in the user's code. There is an example of + this below. + +- **Feature flags** — Functionality is aggressively feature gated so your + procedural macros enable only what they need, and do not pay in compile time + for all the rest. + +[`syn::File`]: https://docs.rs/syn/3/syn/struct.File.html +[`syn::Item`]: https://docs.rs/syn/3/syn/enum.Item.html +[`syn::Expr`]: https://docs.rs/syn/3/syn/enum.Expr.html +[`syn::Type`]: https://docs.rs/syn/3/syn/enum.Type.html +[`syn::DeriveInput`]: https://docs.rs/syn/3/syn/struct.DeriveInput.html +[parser functions]: https://docs.rs/syn/3/syn/parse/index.html + +[*Release notes*](https://github.com/dtolnay/syn/releases) + +
+ +## Resources + +The best way to learn about procedural macros is by writing some. Consider +working through [this procedural macro workshop][workshop] to get familiar with +the different types of procedural macros. The workshop contains relevant links +into the Syn documentation as you work through each project. + +[workshop]: https://github.com/dtolnay/proc-macro-workshop + +
+ +## Example of a derive macro + +The canonical derive macro using Syn looks like this. We write an ordinary Rust +function tagged with a `proc_macro_derive` attribute and the name of the trait +we are deriving. Any time that derive appears in the user's code, the Rust +compiler passes their data structure as tokens into our macro. We get to execute +arbitrary Rust code to figure out what to do with those tokens, then hand some +tokens back to the compiler to compile into the user's crate. + +[`TokenStream`]: https://doc.rust-lang.org/proc_macro/struct.TokenStream.html + +```toml +# Cargo.toml +[package] +... + +[lib] +proc-macro = true + +[dependencies] +syn = "3" +quote = "1" +``` + +```rust +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, DeriveInput}; + +#[proc_macro_derive(MyMacro)] +pub fn my_macro(input: TokenStream) -> TokenStream { + // Parse the input tokens into a syntax tree + let input = parse_macro_input!(input as DeriveInput); + + // Build the output, possibly using quasi-quotation + let expanded = quote! { + // ... + }; + + // Hand the output tokens back to the compiler + TokenStream::from(expanded) +} +``` + +The [`heapsize`] example directory shows a complete working implementation of a +derive macro. The example derives a `HeapSize` trait which computes an estimate +of the amount of heap memory owned by a value. + +[`heapsize`]: examples/heapsize + +```rust +pub trait HeapSize { + /// Total number of bytes of heap memory owned by `self`. + fn heap_size_of_children(&self) -> usize; +} +``` + +The derive macro allows users to write `#[derive(HeapSize)]` on data structures +in their program. + +```rust +#[derive(HeapSize)] +struct Demo<'a, T: ?Sized> { + a: Box, + b: u8, + c: &'a str, + d: String, +} +``` + +
+ +## Spans and error reporting + +The token-based procedural macro API provides great control over where the +compiler's error messages are displayed in user code. Consider the error the +user sees if one of their field types does not implement `HeapSize`. + +```rust +#[derive(HeapSize)] +struct Broken { + ok: String, + bad: std::thread::Thread, +} +``` + +By tracking span information all the way through the expansion of a procedural +macro as shown in the `heapsize` example, token-based macros in Syn are able to +trigger errors that directly pinpoint the source of the problem. + +```console +error[E0277]: the trait bound `Thread: HeapSize` is not satisfied + --> src/main.rs:9:5 + | +3 | #[derive(HeapSize)] + | -------- required by a bound introduced by this call +... +9 | bad: std::thread::Thread, + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HeapSize` is not implemented for `Thread` + | + = help: the following other types implement trait `HeapSize`: + &'a T + Box + Demo<'a, T> + String + [T] + u8 +``` + +
+ +## Parsing a custom syntax + +The [`lazy-static`] example directory shows the implementation of a +`functionlike!(...)` procedural macro in which the input tokens are parsed using +Syn's parsing API. + +[`lazy-static`]: examples/lazy-static + +The example reimplements the popular `lazy_static` crate from crates.io as a +procedural macro. + +```rust +lazy_static! { + static ref USERNAME: Regex = Regex::new("^[a-z0-9_-]{3,16}$").unwrap(); +} +``` + +The implementation shows how to trigger custom warnings and error messages on +the macro input. + +```console +warning: come on, pick a more creative name + --> src/main.rs:10:16 + | +10 | static ref FOO: String = "lazy_static".to_owned(); + | ^^^ +``` + +
+ +## Testing + +When testing macros, we often care not just that the macro can be used +successfully but also that when the macro is provided with invalid input it +produces maximally helpful error messages. Consider using the [`trybuild`] crate +to write tests for errors that are emitted by your macro or errors detected by +the Rust compiler in the expanded code following misuse of the macro. Such tests +help avoid regressions from later refactors that mistakenly make an error no +longer trigger or be less helpful than it used to be. + +[`trybuild`]: https://github.com/dtolnay/trybuild + +
+ +## Debugging + +When developing a procedural macro it can be helpful to look at what the +generated code looks like. Use `cargo rustc -- -Zunstable-options +-Zunpretty=expanded` or the [`cargo expand`] subcommand. + +[`cargo expand`]: https://github.com/dtolnay/cargo-expand + +To show the expanded code for some crate that uses your procedural macro, run +`cargo expand` from that crate. To show the expanded code for one of your own +test cases, run `cargo expand --test the_test_case` where the last argument is +the name of the test file without the `.rs` extension. + +This write-up by Brandon W Maister discusses debugging in more detail: +[Debugging Rust's new Custom Derive system][debugging]. + +[debugging]: https://quodlibetor.github.io/posts/debugging-rusts-new-custom-derive-system/ + +
+ +## Optional features + +Syn puts a lot of functionality behind optional features in order to optimize +compile time for the most common use cases. The following features are +available. + +- **`derive`** *(enabled by default)* — Data structures for representing the + possible input to a derive macro, including structs and enums and types. +- **`full`** — Data structures for representing the syntax tree of all valid + Rust source code, including items and expressions. +- **`parsing`** *(enabled by default)* — Ability to parse input tokens into a + syntax tree node of a chosen type. +- **`printing`** *(enabled by default)* — Ability to print a syntax tree node as + tokens of Rust source code. +- **`visit`** — Trait for traversing a syntax tree. +- **`visit-mut`** — Trait for traversing and mutating in place a syntax tree. +- **`fold`** — Trait for transforming an owned syntax tree. +- **`clone-impls`** *(enabled by default)* — Clone impls for all syntax tree + types. +- **`extra-traits`** — Debug, Eq, PartialEq, Hash impls for all syntax tree + types. +- **`proc-macro`** *(enabled by default)* — Runtime dependency on the dynamic + library libproc_macro from rustc toolchain. + +
+ +## Proc macro shim + +Syn operates on the token representation provided by the [proc-macro2] crate +from crates.io rather than using the compiler's built in proc-macro crate +directly. This enables code using Syn to execute outside of the context of a +procedural macro, such as in unit tests or build.rs, and we avoid needing +incompatible ecosystems for proc macros vs non-macro use cases. + +In general all of your code should be written against proc-macro2 rather than +proc-macro. The one exception is in the signatures of procedural macro entry +points, which are required by the language to use `proc_macro::TokenStream`. + +The proc-macro2 crate will automatically detect and use the compiler's data +structures when a procedural macro is active. + +[proc-macro2]: https://docs.rs/proc-macro2/1.0/proc_macro2/ + +
+ +#### License + + +Licensed under either of
Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + diff --git a/third_party/crates/syn-3.0.5/benches/file.rs b/third_party/crates/syn-3.0.5/benches/file.rs new file mode 100644 index 0000000..6167488 --- /dev/null +++ b/third_party/crates/syn-3.0.5/benches/file.rs @@ -0,0 +1,59 @@ +// $ cargo bench --features full,test --bench file + +#![feature(rustc_private, test)] +#![recursion_limit = "1024"] +#![allow( + clippy::elidable_lifetime_names, + clippy::items_after_statements, + clippy::manual_let_else, + clippy::match_like_matches_macro, + clippy::missing_panics_doc, + clippy::must_use_candidate, + clippy::needless_lifetimes, + clippy::uninlined_format_args +)] + +extern crate test; + +#[macro_use] +#[path = "../tests/macros/mod.rs"] +mod macros; + +#[allow(dead_code)] +#[path = "../tests/repo/mod.rs"] +mod repo; + +use proc_macro2::{Span, TokenStream}; +use std::fs; +use std::str::FromStr; +use syn::parse::{ParseStream, Parser}; +use test::Bencher; + +const FILE: &str = "tests/rust/library/core/src/str/mod.rs"; + +fn get_tokens() -> TokenStream { + repo::clone_rust(); + let content = fs::read_to_string(FILE).unwrap(); + TokenStream::from_str(&content).unwrap() +} + +#[bench] +fn baseline(b: &mut Bencher) { + let tokens = get_tokens(); + b.iter(|| drop(tokens.clone())); +} + +#[bench] +fn create_token_buffer(b: &mut Bencher) { + let tokens = get_tokens(); + fn immediate_fail(_input: ParseStream) -> syn::Result<()> { + Err(syn::Error::new(Span::call_site(), "")) + } + b.iter(|| immediate_fail.parse2(tokens.clone())); +} + +#[bench] +fn parse_file(b: &mut Bencher) { + let tokens = get_tokens(); + b.iter(|| syn::parse2::(tokens.clone())); +} diff --git a/third_party/crates/syn-3.0.5/benches/rust.rs b/third_party/crates/syn-3.0.5/benches/rust.rs new file mode 100644 index 0000000..c0e82c6 --- /dev/null +++ b/third_party/crates/syn-3.0.5/benches/rust.rs @@ -0,0 +1,189 @@ +// $ cargo bench --features full,test --bench rust +// +// Syn only, useful for profiling: +// $ RUSTFLAGS='--cfg syn_only' cargo build --release --features full,test --bench rust + +#![cfg_attr(not(syn_only), feature(rustc_private))] +#![recursion_limit = "1024"] +#![allow( + clippy::arc_with_non_send_sync, + clippy::cast_lossless, + clippy::elidable_lifetime_names, + clippy::let_underscore_untyped, + clippy::manual_let_else, + clippy::match_like_matches_macro, + clippy::needless_lifetimes, + clippy::uninlined_format_args, + clippy::unnecessary_wraps +)] + +#[macro_use] +#[path = "../tests/macros/mod.rs"] +mod macros; + +#[allow(dead_code)] +#[path = "../tests/repo/mod.rs"] +mod repo; + +use std::fs; +use std::path::Path; +use std::time::{Duration, Instant}; + +#[cfg(not(syn_only))] +mod tokenstream_parse { + use proc_macro2::TokenStream; + use std::path::Path; + use std::str::FromStr; + + pub fn bench(_path: &Path, content: &str) -> Result<(), ()> { + TokenStream::from_str(content).map(drop).map_err(drop) + } +} + +mod syn_parse { + use std::path::Path; + + pub fn bench(_path: &Path, content: &str) -> Result<(), ()> { + syn::parse_file(content).map(drop).map_err(drop) + } +} + +#[cfg(not(syn_only))] +mod librustc_parse { + extern crate rustc_data_structures; + extern crate rustc_driver; + extern crate rustc_error_messages; + extern crate rustc_errors; + extern crate rustc_parse; + extern crate rustc_session; + extern crate rustc_span; + + use crate::repo; + use rustc_errors::emitter::Emitter; + use rustc_errors::{DiagCtxt, DiagInner}; + use rustc_parse::lexer::StripTokens; + use rustc_session::parse::ParseSess; + use rustc_span::source_map::{FilePathMapping, SourceMap}; + use rustc_span::FileName; + use std::path::Path; + use std::sync::Arc; + + pub fn bench(path: &Path, content: &str) -> Result<(), ()> { + struct SilentEmitter; + + impl Emitter for SilentEmitter { + fn emit_diagnostic(&mut self, _diag: DiagInner) {} + fn source_map(&self) -> Option<&SourceMap> { + None + } + } + + let edition = repo::edition(path).parse().unwrap(); + rustc_span::create_session_if_not_set_then(edition, |_| { + let source_map = Arc::new(SourceMap::new(FilePathMapping::empty())); + let emitter = Box::new(SilentEmitter); + let handler = DiagCtxt::new(emitter); + let sess = ParseSess::with_dcx(handler, source_map); + let name = FileName::Custom("bench".to_owned()); + let mut parser = rustc_parse::new_parser_from_source_str( + &sess, + name, + content.to_owned(), + StripTokens::ShebangAndFrontmatter, + ) + .unwrap(); + if let Err(diagnostic) = parser.parse_crate_mod() { + diagnostic.cancel(); + return Err(()); + } + Ok(()) + }) + } +} + +#[cfg(not(syn_only))] +mod read_from_disk { + use std::path::Path; + + pub fn bench(_path: &Path, content: &str) -> Result<(), ()> { + let _ = content; + Ok(()) + } +} + +fn exec(mut codepath: impl FnMut(&Path, &str) -> Result<(), ()>) -> Duration { + let begin = Instant::now(); + let mut success = 0; + let mut total = 0; + + ["tests/rust/compiler", "tests/rust/library"] + .iter() + .flat_map(|dir| { + walkdir::WalkDir::new(dir) + .into_iter() + .filter_entry(repo::base_dir_filter) + }) + .for_each(|entry| { + let entry = entry.unwrap(); + let path = entry.path(); + if path.is_dir() { + return; + } + let content = fs::read_to_string(path).unwrap(); + let ok = codepath(path, &content).is_ok(); + success += ok as usize; + total += 1; + if !ok { + eprintln!("FAIL {}", path.display()); + } + }); + + assert_eq!(success, total); + begin.elapsed() +} + +fn main() { + repo::clone_rust(); + + macro_rules! testcases { + ($($(#[$cfg:meta])* $name:ident,)*) => { + [ + $( + $(#[$cfg])* + (stringify!($name), $name::bench as fn(&Path, &str) -> Result<(), ()>), + )* + ] + }; + } + + #[cfg(not(syn_only))] + { + let mut lines = 0; + let mut files = 0; + exec(|_path, content| { + lines += content.lines().count(); + files += 1; + Ok(()) + }); + eprintln!("\n{} lines in {} files", lines, files); + } + + for (name, f) in testcases!( + #[cfg(not(syn_only))] + read_from_disk, + #[cfg(not(syn_only))] + tokenstream_parse, + syn_parse, + #[cfg(not(syn_only))] + librustc_parse, + ) { + eprint!("{:20}", format!("{}:", name)); + let elapsed = exec(f); + eprintln!( + "elapsed={}.{:03}s", + elapsed.as_secs(), + elapsed.subsec_millis(), + ); + } + eprintln!(); +} diff --git a/third_party/crates/syn-3.0.5/src/attr.rs b/third_party/crates/syn-3.0.5/src/attr.rs new file mode 100644 index 0000000..5e2d7a7 --- /dev/null +++ b/third_party/crates/syn-3.0.5/src/attr.rs @@ -0,0 +1,841 @@ +#[cfg(feature = "parsing")] +use crate::error::Error; +#[cfg(feature = "parsing")] +use crate::error::Result; +use crate::expr::Expr; +use crate::mac::MacroDelimiter; +#[cfg(feature = "parsing")] +use crate::meta::{self, ParseNestedMeta}; +#[cfg(feature = "parsing")] +use crate::parse::{Parse, ParseStream, Parser}; +use crate::path::Path; +use crate::token; +#[cfg(feature = "parsing")] +use alloc::format; +#[cfg(feature = "parsing")] +use alloc::vec::Vec; +#[cfg(feature = "printing")] +use core::iter; +#[cfg(feature = "printing")] +use core::slice; +use proc_macro2::TokenStream; + +ast_struct! { + /// An attribute, like `#[repr(transparent)]`. + /// + ///
+ /// + /// # Syntax + /// + /// Rust has six types of attributes. + /// + /// - Outer attributes like `#[repr(transparent)]`. These appear outside or + /// in front of the item they describe. + /// + /// - Inner attributes like `#![feature(proc_macro)]`. These appear inside + /// of the item they describe, usually a module. + /// + /// - Outer one-line doc comments like `/// Example`. + /// + /// - Inner one-line doc comments like `//! Please file an issue`. + /// + /// - Outer documentation blocks `/** Example */`. + /// + /// - Inner documentation blocks `/*! Please file an issue */`. + /// + /// The `style` field of type `AttrStyle` distinguishes whether an attribute + /// is outer or inner. + /// + /// Every attribute has a `path` that indicates the intended interpretation + /// of the rest of the attribute's contents. The path and the optional + /// additional contents are represented together in the `meta` field of the + /// attribute in three possible varieties: + /// + /// - Meta::Path — attributes whose information content conveys just a + /// path, for example the `#[test]` attribute. + /// + /// - Meta::List — attributes that carry arbitrary tokens after the + /// path, surrounded by a delimiter (parenthesis, bracket, or brace). For + /// example `#[derive(Copy)]` or `#[precondition(x < 5)]`. + /// + /// - Meta::NameValue — attributes with an `=` sign after the path, + /// followed by a Rust expression. For example `#[path = + /// "sys/windows.rs"]`. + /// + /// All doc comments are represented in the NameValue style with a path of + /// "doc", as this is how they are processed by the compiler and by + /// `macro_rules!` macros. + /// + /// ```text + /// #[derive(Copy, Clone)] + /// ~~~~~~Path + /// ^^^^^^^^^^^^^^^^^^^Meta::List + /// + /// #[path = "sys/windows.rs"] + /// ~~~~Path + /// ^^^^^^^^^^^^^^^^^^^^^^^Meta::NameValue + /// + /// #[test] + /// ^^^^Meta::Path + /// ``` + /// + ///
+ /// + /// # Parsing from tokens to Attribute + /// + /// This type does not implement the [`Parse`] trait and thus cannot be + /// parsed directly by [`ParseStream::parse`]. Instead use + /// [`ParseStream::call`] with one of the two parser functions + /// [`Attribute::parse_outer`] or [`Attribute::parse_inner`] depending on + /// which you intend to parse. + /// + /// [`Parse`]: crate::parse::Parse + /// [`ParseStream::parse`]: crate::parse::ParseBuffer::parse + /// [`ParseStream::call`]: crate::parse::ParseBuffer::call + /// + /// ``` + /// use syn::{Attribute, Ident, Result, Token}; + /// use syn::parse::{Parse, ParseStream}; + /// + /// // Parses a unit struct with attributes. + /// // + /// // #[path = "s.tmpl"] + /// // struct S; + /// struct UnitStruct { + /// attrs: Vec, + /// struct_token: Token![struct], + /// name: Ident, + /// semi_token: Token![;], + /// } + /// + /// impl Parse for UnitStruct { + /// fn parse(input: ParseStream) -> Result { + /// Ok(UnitStruct { + /// attrs: input.call(Attribute::parse_outer)?, + /// struct_token: input.parse()?, + /// name: input.parse()?, + /// semi_token: input.parse()?, + /// }) + /// } + /// } + /// ``` + /// + ///


+ /// + /// # Parsing from Attribute to structured arguments + /// + /// The grammar of attributes in Rust is very flexible, which makes the + /// syntax tree not that useful on its own. In particular, arguments of the + /// `Meta::List` variety of attribute are held in an arbitrary `tokens: + /// TokenStream`. Macros are expected to check the `path` of the attribute, + /// decide whether they recognize it, and then parse the remaining tokens + /// according to whatever grammar they wish to require for that kind of + /// attribute. Use [`parse_args()`] to parse those tokens into the expected + /// data structure. + /// + /// [`parse_args()`]: Attribute::parse_args + /// + ///


+ /// + /// # Doc comments + /// + /// The compiler transforms doc comments, such as `/// comment` and `/*! + /// comment */`, into attributes before macros are expanded. Each comment is + /// expanded into an attribute of the form `#[doc = r"comment"]`. + /// + /// As an example, the following `mod` items are expanded identically: + /// + /// ``` + /// # use syn::{ItemMod, parse_quote}; + /// let doc: ItemMod = parse_quote! { + /// /// Single line doc comments + /// /// We write so many! + /// /** + /// * Multi-line comments... + /// * May span many lines + /// */ + /// mod example { + /// //! Of course, they can be inner too + /// /*! And fit in a single line */ + /// } + /// }; + /// let attr: ItemMod = parse_quote! { + /// #[doc = r" Single line doc comments"] + /// #[doc = r" We write so many!"] + /// #[doc = r" + /// * Multi-line comments... + /// * May span many lines + /// "] + /// mod example { + /// #![doc = r" Of course, they can be inner too"] + /// #![doc = r" And fit in a single line "] + /// } + /// }; + /// assert_eq!(doc, attr); + /// ``` + #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] + pub struct Attribute { + pub pound_token: Token![#], + pub style: AttrStyle, + pub bracket_token: token::Bracket, + pub meta: Meta, + } +} + +impl Attribute { + /// Returns the path that identifies the interpretation of this attribute. + /// + /// For example this would return the `test` in `#[test]`, the `derive` in + /// `#[derive(Copy)]`, and the `path` in `#[path = "sys/windows.rs"]`. + pub fn path(&self) -> &Path { + self.meta.path() + } + + /// Parse the arguments to the attribute as a syntax tree. + /// + /// This is similar to pulling out the `TokenStream` from `Meta::List` and + /// doing `syn::parse2::(meta_list.tokens)`, except that using + /// `parse_args` the error message has a more useful span when `tokens` is + /// empty. + /// + /// The surrounding delimiters are *not* included in the input to the + /// parser. + /// + /// ```text + /// #[my_attr(value < 5)] + /// ^^^^^^^^^ what gets parsed + /// ``` + /// + /// # Example + /// + /// ``` + /// use syn::{parse_quote, Attribute, Expr}; + /// + /// let attr: Attribute = parse_quote! { + /// #[precondition(value < 5)] + /// }; + /// + /// if attr.path().is_ident("precondition") { + /// let precondition: Expr = attr.parse_args()?; + /// // ... + /// } + /// # anyhow::Ok(()) + /// ``` + #[cfg(feature = "parsing")] + #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] + pub fn parse_args(&self) -> Result { + self.parse_args_with(T::parse) + } + + /// Parse the arguments to the attribute using the given parser. + /// + /// # Example + /// + /// ``` + /// use syn::{parse_quote, Attribute}; + /// + /// let attr: Attribute = parse_quote! { + /// #[inception { #[brrrrrrraaaaawwwwrwrrrmrmrmmrmrmmmmm] }] + /// }; + /// + /// let bwom = attr.parse_args_with(Attribute::parse_outer)?; + /// + /// // Attribute does not have a Parse impl, so we couldn't directly do: + /// // let bwom: Attribute = attr.parse_args()?; + /// # anyhow::Ok(()) + /// ``` + #[cfg(feature = "parsing")] + #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] + pub fn parse_args_with(&self, parser: F) -> Result { + match &self.meta { + Meta::Path(path) => Err(crate::error::new2( + path.segments.first().unwrap().ident.span(), + path.segments.last().unwrap().ident.span(), + format!( + "expected attribute arguments in parentheses: {}[{}(...)]", + parsing::DisplayAttrStyle(&self.style), + parsing::DisplayPath(path), + ), + )), + Meta::NameValue(meta) => Err(Error::new( + meta.eq_token.span, + format_args!( + "expected parentheses: {}[{}(...)]", + parsing::DisplayAttrStyle(&self.style), + parsing::DisplayPath(&meta.path), + ), + )), + Meta::List(meta) => meta.parse_args_with(parser), + } + } + + /// Parse the arguments to the attribute, expecting it to follow the + /// conventional structure used by most of Rust's built-in attributes. + /// + /// The [*Meta Item Attribute Syntax*][syntax] section in the Rust reference + /// explains the convention in more detail. Not all attributes follow this + /// convention, so [`parse_args()`][Self::parse_args] is available if you + /// need to parse arbitrarily goofy attribute syntax. + /// + /// [syntax]: https://doc.rust-lang.org/reference/attributes.html#meta-item-attribute-syntax + /// + /// # Example + /// + /// We'll parse a struct, and then parse some of Rust's `#[repr]` attribute + /// syntax. + /// + /// ``` + /// use syn::{parenthesized, parse_quote, token, ItemStruct, LitInt}; + /// + /// let input: ItemStruct = parse_quote! { + /// #[repr(C, align(4))] + /// pub struct MyStruct(u16, u32); + /// }; + /// + /// let mut repr_c = false; + /// let mut repr_transparent = false; + /// let mut repr_align = None::; + /// let mut repr_packed = None::; + /// for attr in &input.attrs { + /// if attr.path().is_ident("repr") { + /// attr.parse_nested_meta(|meta| { + /// // #[repr(C)] + /// if meta.path.is_ident("C") { + /// repr_c = true; + /// return Ok(()); + /// } + /// + /// // #[repr(transparent)] + /// if meta.path.is_ident("transparent") { + /// repr_transparent = true; + /// return Ok(()); + /// } + /// + /// // #[repr(align(N))] + /// if meta.path.is_ident("align") { + /// let content; + /// parenthesized!(content in meta.input); + /// let lit: LitInt = content.parse()?; + /// let n: usize = lit.base10_parse()?; + /// repr_align = Some(n); + /// return Ok(()); + /// } + /// + /// // #[repr(packed)] or #[repr(packed(N))], omitted N means 1 + /// if meta.path.is_ident("packed") { + /// if meta.input.peek(token::Paren) { + /// let content; + /// parenthesized!(content in meta.input); + /// let lit: LitInt = content.parse()?; + /// let n: usize = lit.base10_parse()?; + /// repr_packed = Some(n); + /// } else { + /// repr_packed = Some(1); + /// } + /// return Ok(()); + /// } + /// + /// Err(meta.error("unrecognized repr")) + /// })?; + /// } + /// } + /// # anyhow::Ok(()) + /// ``` + /// + /// # Alternatives + /// + /// In some cases, for attributes which have nested layers of structured + /// content, the following less flexible approach might be more convenient: + /// + /// ``` + /// # use syn::{parse_quote, ItemStruct}; + /// # + /// # let input: ItemStruct = parse_quote! { + /// # #[repr(C, align(4))] + /// # pub struct MyStruct(u16, u32); + /// # }; + /// # + /// use syn::punctuated::Punctuated; + /// use syn::{parenthesized, token, Error, LitInt, Meta, Token}; + /// + /// let mut repr_c = false; + /// let mut repr_transparent = false; + /// let mut repr_align = None::; + /// let mut repr_packed = None::; + /// for attr in &input.attrs { + /// if attr.path().is_ident("repr") { + /// let nested = attr.parse_args_with(Punctuated::::parse_terminated)?; + /// for meta in nested { + /// match meta { + /// // #[repr(C)] + /// Meta::Path(path) if path.is_ident("C") => { + /// repr_c = true; + /// } + /// + /// // #[repr(align(N))] + /// Meta::List(meta) if meta.path.is_ident("align") => { + /// let lit: LitInt = meta.parse_args()?; + /// let n: usize = lit.base10_parse()?; + /// repr_align = Some(n); + /// } + /// + /// /* ... */ + /// + /// _ => { + /// return Err(Error::new_spanned(meta, "unrecognized repr")); + /// } + /// } + /// } + /// } + /// } + /// # Ok(()) + /// ``` + #[cfg(feature = "parsing")] + #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] + pub fn parse_nested_meta( + &self, + logic: impl FnMut(ParseNestedMeta) -> Result<()>, + ) -> Result<()> { + self.parse_args_with(meta::parser(logic)) + } + + /// Parses zero or more outer attributes from the stream. + /// + /// # Example + /// + /// See + /// [*Parsing from tokens to Attribute*](#parsing-from-tokens-to-attribute). + #[cfg(feature = "parsing")] + #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] + pub fn parse_outer(input: ParseStream) -> Result> { + let mut attrs = Vec::new(); + while input.peek(Token![#]) { + attrs.push(input.call(parsing::single_parse_outer)?); + } + Ok(attrs) + } + + /// Parses zero or more inner attributes from the stream. + /// + /// # Example + /// + /// See + /// [*Parsing from tokens to Attribute*](#parsing-from-tokens-to-attribute). + #[cfg(feature = "parsing")] + #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] + pub fn parse_inner(input: ParseStream) -> Result> { + let mut attrs = Vec::new(); + parsing::parse_inner(input, &mut attrs)?; + Ok(attrs) + } +} + +ast_enum! { + /// Distinguishes between attributes that decorate an item and attributes + /// that are contained within an item. + /// + /// # Outer attributes + /// + /// - `#[repr(transparent)]` + /// - `/// # Example` + /// - `/** Please file an issue */` + /// + /// # Inner attributes + /// + /// - `#![feature(proc_macro)]` + /// - `//! # Example` + /// - `/*! Please file an issue */` + #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] + pub enum AttrStyle { + Outer, + Inner(Token![!]), + } +} + +ast_enum! { + /// Content of a compile-time structured attribute. + /// + /// ## Path + /// + /// A meta path is like the `test` in `#[test]`. + /// + /// ## List + /// + /// A meta list is like the `derive(Copy)` in `#[derive(Copy)]`. + /// + /// ## NameValue + /// + /// A name-value meta is like the `path = "..."` in `#[path = + /// "sys/windows.rs"]`. + /// + /// # Syntax tree enum + /// + /// This type is a [syntax tree enum]. + /// + /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums + #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] + pub enum Meta { + Path(Path), + + /// A structured list within an attribute, like `derive(Copy, Clone)`. + List(MetaList), + + /// A name-value pair within an attribute, like `feature = "nightly"`. + NameValue(MetaNameValue), + } +} + +ast_struct! { + /// A structured list within an attribute, like `derive(Copy, Clone)`. + #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] + pub struct MetaList { + pub path: Path, + pub delimiter: MacroDelimiter, + pub tokens: TokenStream, + } +} + +ast_struct! { + /// A name-value pair within an attribute, like `feature = "nightly"`. + #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] + pub struct MetaNameValue { + pub path: Path, + pub eq_token: Token![=], + pub value: Expr, + } +} + +impl Meta { + /// Returns the path that begins this structured meta item. + /// + /// For example this would return the `test` in `#[test]`, the `derive` in + /// `#[derive(Copy)]`, and the `path` in `#[path = "sys/windows.rs"]`. + pub fn path(&self) -> &Path { + match self { + Meta::Path(path) => path, + Meta::List(meta) => &meta.path, + Meta::NameValue(meta) => &meta.path, + } + } + + /// Error if this is a `Meta::List` or `Meta::NameValue`. + #[cfg(feature = "parsing")] + #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] + pub fn require_path_only(&self) -> Result<&Path> { + let error_span = match self { + Meta::Path(path) => return Ok(path), + Meta::List(meta) => meta.delimiter.span().open(), + Meta::NameValue(meta) => meta.eq_token.span, + }; + Err(Error::new(error_span, "unexpected token in attribute")) + } + + /// Error if this is a `Meta::Path` or `Meta::NameValue`. + #[cfg(feature = "parsing")] + #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] + pub fn require_list(&self) -> Result<&MetaList> { + match self { + Meta::List(meta) => Ok(meta), + Meta::Path(path) => Err(crate::error::new2( + path.segments.first().unwrap().ident.span(), + path.segments.last().unwrap().ident.span(), + format!( + "expected attribute arguments in parentheses: `{}(...)`", + parsing::DisplayPath(path), + ), + )), + Meta::NameValue(meta) => Err(Error::new(meta.eq_token.span, "expected `(`")), + } + } + + /// Error if this is a `Meta::Path` or `Meta::List`. + #[cfg(feature = "parsing")] + #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] + pub fn require_name_value(&self) -> Result<&MetaNameValue> { + match self { + Meta::NameValue(meta) => Ok(meta), + Meta::Path(path) => Err(crate::error::new2( + path.segments.first().unwrap().ident.span(), + path.segments.last().unwrap().ident.span(), + format!( + "expected a value for this attribute: `{} = ...`", + parsing::DisplayPath(path), + ), + )), + Meta::List(meta) => Err(Error::new(meta.delimiter.span().open(), "expected `=`")), + } + } +} + +impl MetaList { + /// See [`Attribute::parse_args`]. + #[cfg(feature = "parsing")] + #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] + pub fn parse_args(&self) -> Result { + self.parse_args_with(T::parse) + } + + /// See [`Attribute::parse_args_with`]. + #[cfg(feature = "parsing")] + #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] + pub fn parse_args_with(&self, parser: F) -> Result { + let scope = self.delimiter.span().close(); + crate::parse::parse_scoped(parser, scope, self.tokens.clone()) + } + + /// See [`Attribute::parse_nested_meta`]. + #[cfg(feature = "parsing")] + #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] + pub fn parse_nested_meta( + &self, + logic: impl FnMut(ParseNestedMeta) -> Result<()>, + ) -> Result<()> { + self.parse_args_with(meta::parser(logic)) + } +} + +#[cfg(feature = "printing")] +pub(crate) trait FilterAttrs<'a> { + type Ret: Iterator; + + fn outer(self) -> Self::Ret; + #[cfg(feature = "full")] + fn inner(self) -> Self::Ret; +} + +#[cfg(feature = "printing")] +impl<'a> FilterAttrs<'a> for &'a [Attribute] { + type Ret = iter::Filter, fn(&&Attribute) -> bool>; + + fn outer(self) -> Self::Ret { + fn is_outer(attr: &&Attribute) -> bool { + match attr.style { + AttrStyle::Outer => true, + AttrStyle::Inner(_) => false, + } + } + self.iter().filter(is_outer) + } + + #[cfg(feature = "full")] + fn inner(self) -> Self::Ret { + fn is_inner(attr: &&Attribute) -> bool { + match attr.style { + AttrStyle::Inner(_) => true, + AttrStyle::Outer => false, + } + } + self.iter().filter(is_inner) + } +} + +impl From for Meta { + fn from(meta: Path) -> Meta { + Meta::Path(meta) + } +} + +impl From for Meta { + fn from(meta: MetaList) -> Meta { + Meta::List(meta) + } +} + +impl From for Meta { + fn from(meta: MetaNameValue) -> Meta { + Meta::NameValue(meta) + } +} + +#[cfg(feature = "parsing")] +pub(crate) mod parsing { + use crate::attr::{AttrStyle, Attribute, Meta, MetaList, MetaNameValue}; + use crate::error::Result; + use crate::expr::{Expr, ExprLit}; + use crate::lit::Lit; + use crate::parse::discouraged::Speculative as _; + use crate::parse::{Parse, ParseStream}; + use crate::path::Path; + use crate::{mac, token}; + use alloc::vec::Vec; + use core::fmt::{self, Display}; + use proc_macro2::Ident; + + pub(crate) fn parse_inner(input: ParseStream, attrs: &mut Vec) -> Result<()> { + while input.peek(Token![#]) && input.peek2(Token![!]) { + attrs.push(input.call(single_parse_inner)?); + } + Ok(()) + } + + pub(crate) fn single_parse_inner(input: ParseStream) -> Result { + let content; + Ok(Attribute { + pound_token: input.parse()?, + style: AttrStyle::Inner(input.parse()?), + bracket_token: bracketed!(content in input), + meta: content.parse()?, + }) + } + + pub(crate) fn single_parse_outer(input: ParseStream) -> Result { + let content; + Ok(Attribute { + pound_token: input.parse()?, + style: AttrStyle::Outer, + bracket_token: bracketed!(content in input), + meta: content.parse()?, + }) + } + + #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] + impl Parse for Meta { + fn parse(input: ParseStream) -> Result { + let path = parse_outermost_meta_path(input)?; + parse_meta_after_path(path, input) + } + } + + #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] + impl Parse for MetaList { + fn parse(input: ParseStream) -> Result { + let path = parse_outermost_meta_path(input)?; + parse_meta_list_after_path(path, input) + } + } + + #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] + impl Parse for MetaNameValue { + fn parse(input: ParseStream) -> Result { + let path = parse_outermost_meta_path(input)?; + parse_meta_name_value_after_path(path, input) + } + } + + // Unlike meta::parse_meta_path which accepts arbitrary keywords in the path, + // only the `unsafe` keyword is accepted as an attribute's outermost path. + fn parse_outermost_meta_path(input: ParseStream) -> Result { + if input.peek(Token![unsafe]) { + let unsafe_token: Token![unsafe] = input.parse()?; + Ok(Path::from(Ident::new("unsafe", unsafe_token.span))) + } else { + Path::parse_mod_style(input) + } + } + + pub(crate) fn parse_meta_after_path(path: Path, input: ParseStream) -> Result { + if input.peek(token::Paren) || input.peek(token::Bracket) || input.peek(token::Brace) { + parse_meta_list_after_path(path, input).map(Meta::List) + } else if input.peek(Token![=]) && !input.peek(Token![==]) && !input.peek(Token![=>]) { + parse_meta_name_value_after_path(path, input).map(Meta::NameValue) + } else { + Ok(Meta::Path(path)) + } + } + + fn parse_meta_list_after_path(path: Path, input: ParseStream) -> Result { + let (delimiter, tokens) = mac::parse_delimiter(input)?; + Ok(MetaList { + path, + delimiter, + tokens, + }) + } + + fn parse_meta_name_value_after_path(path: Path, input: ParseStream) -> Result { + let eq_token: Token![=] = input.parse()?; + let ahead = input.fork(); + let lit: Option = ahead.parse()?; + let value = if let (Some(lit), true) = (lit, ahead.is_empty()) { + input.advance_to(&ahead); + Expr::Lit(ExprLit { + attrs: Vec::new(), + lit, + }) + } else if input.peek(Token![#]) && input.peek2(token::Bracket) { + return Err(input.error("unexpected attribute inside of attribute")); + } else { + input.parse()? + }; + Ok(MetaNameValue { + path, + eq_token, + value, + }) + } + + pub(super) struct DisplayAttrStyle<'a>(pub &'a AttrStyle); + + impl<'a> Display for DisplayAttrStyle<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(match self.0 { + AttrStyle::Outer => "#", + AttrStyle::Inner(_) => "#!", + }) + } + } + + pub(super) struct DisplayPath<'a>(pub &'a Path); + + impl<'a> Display for DisplayPath<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + for (i, segment) in self.0.segments.iter().enumerate() { + if i > 0 || self.0.leading_colon.is_some() { + formatter.write_str("::")?; + } + write!(formatter, "{}", segment.ident)?; + } + Ok(()) + } + } +} + +#[cfg(feature = "printing")] +mod printing { + use crate::attr::{AttrStyle, Attribute, Meta, MetaList, MetaNameValue}; + use crate::path; + use crate::path::printing::PathStyle; + use proc_macro2::TokenStream; + use quote::ToTokens; + + #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] + impl ToTokens for Attribute { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.pound_token.to_tokens(tokens); + if let AttrStyle::Inner(b) = &self.style { + b.to_tokens(tokens); + } + self.bracket_token.surround(tokens, |tokens| { + self.meta.to_tokens(tokens); + }); + } + } + + #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] + impl ToTokens for Meta { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + Meta::Path(path) => path::printing::print_path(tokens, path, PathStyle::Mod), + Meta::List(meta_list) => meta_list.to_tokens(tokens), + Meta::NameValue(meta_name_value) => meta_name_value.to_tokens(tokens), + } + } + } + + #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] + impl ToTokens for MetaList { + fn to_tokens(&self, tokens: &mut TokenStream) { + path::printing::print_path(tokens, &self.path, PathStyle::Mod); + self.delimiter.surround(tokens, self.tokens.clone()); + } + } + + #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] + impl ToTokens for MetaNameValue { + fn to_tokens(&self, tokens: &mut TokenStream) { + path::printing::print_path(tokens, &self.path, PathStyle::Mod); + self.eq_token.to_tokens(tokens); + self.value.to_tokens(tokens); + } + } +} diff --git a/third_party/crates/syn-3.0.5/src/bigint.rs b/third_party/crates/syn-3.0.5/src/bigint.rs new file mode 100644 index 0000000..d32298b --- /dev/null +++ b/third_party/crates/syn-3.0.5/src/bigint.rs @@ -0,0 +1,68 @@ +use alloc::string::String; +use alloc::vec::Vec; +use core::ops::{AddAssign, MulAssign}; + +// For implementing base10_digits() accessor on LitInt. +pub(crate) struct BigInt { + digits: Vec, +} + +impl BigInt { + pub(crate) fn new() -> Self { + BigInt { digits: Vec::new() } + } + + pub(crate) fn to_string(&self) -> String { + let mut repr = String::with_capacity(self.digits.len()); + + let mut has_nonzero = false; + for digit in self.digits.iter().rev() { + has_nonzero |= *digit != 0; + if has_nonzero { + repr.push((*digit + b'0') as char); + } + } + + if repr.is_empty() { + repr.push('0'); + } + + repr + } + + fn reserve_two_digits(&mut self) { + let len = self.digits.len(); + let desired = + len + !self.digits.ends_with(&[0, 0]) as usize + !self.digits.ends_with(&[0]) as usize; + self.digits.resize(desired, 0); + } +} + +impl AddAssign for BigInt { + // Assumes increment <16. + fn add_assign(&mut self, mut increment: u8) { + self.reserve_two_digits(); + + let mut i = 0; + while increment > 0 { + let sum = self.digits[i] + increment; + self.digits[i] = sum % 10; + increment = sum / 10; + i += 1; + } + } +} + +impl MulAssign for BigInt { + // Assumes base <=16. + fn mul_assign(&mut self, base: u8) { + self.reserve_two_digits(); + + let mut carry = 0; + for digit in &mut self.digits { + let prod = *digit * base + carry; + *digit = prod % 10; + carry = prod / 10; + } + } +} diff --git a/third_party/crates/syn-3.0.5/src/buffer.rs b/third_party/crates/syn-3.0.5/src/buffer.rs new file mode 100644 index 0000000..f2e205b --- /dev/null +++ b/third_party/crates/syn-3.0.5/src/buffer.rs @@ -0,0 +1,462 @@ +//! A stably addressed token buffer supporting efficient traversal based on a +//! cheaply copyable cursor. + +// This module is heavily commented as it contains most of the unsafe code in +// Syn, and caution should be used when editing it. The public-facing interface +// is 100% safe but the implementation is fragile internally. + +use crate::ext::TokenStreamExt as _; +use crate::Lifetime; +use alloc::boxed::Box; +use alloc::vec::Vec; +use core::cmp::Ordering; +use core::marker::PhantomData; +use core::ptr; +use proc_macro2::extra::DelimSpan; +use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; + +/// Internal type which is used instead of `TokenTree` to represent a token tree +/// within a `TokenBuffer`. +enum Entry { + // Mimicking types from proc-macro. + // Group entries contain the offset to the matching End entry. + Group(Group, usize), + Ident(Ident), + Punct(Punct), + Literal(Literal), + // End entries contain the offset (negative) to the start of the buffer, and + // offset (negative) to the matching Group entry. + End(isize, isize), +} + +/// A buffer that can be efficiently traversed multiple times, unlike +/// `TokenStream` which requires a deep copy in order to traverse more than +/// once. +pub struct TokenBuffer { + // NOTE: Do not implement clone on this - while the current design could be + // cloned, other designs which could be desirable may not be cloneable. + entries: Box<[Entry]>, +} + +impl TokenBuffer { + fn recursive_new(entries: &mut Vec, stream: TokenStream) { + for tt in stream { + match tt { + TokenTree::Ident(ident) => entries.push(Entry::Ident(ident)), + TokenTree::Punct(punct) => entries.push(Entry::Punct(punct)), + TokenTree::Literal(literal) => entries.push(Entry::Literal(literal)), + TokenTree::Group(group) => { + let group_start_index = entries.len(); + entries.push(Entry::End(0, 0)); // we replace this below + Self::recursive_new(entries, group.stream()); + let group_end_index = entries.len(); + let group_offset = group_end_index - group_start_index; + entries.push(Entry::End( + -(group_end_index as isize), + -(group_offset as isize), + )); + entries[group_start_index] = Entry::Group(group, group_offset); + } + } + } + } + + /// Creates a `TokenBuffer` containing all the tokens from the input + /// `proc_macro::TokenStream`. + #[cfg(feature = "proc-macro")] + #[cfg_attr(docsrs, doc(cfg(feature = "proc-macro")))] + pub fn new(stream: proc_macro::TokenStream) -> Self { + Self::new2(stream.into()) + } + + /// Creates a `TokenBuffer` containing all the tokens from the input + /// `proc_macro2::TokenStream`. + pub fn new2(stream: TokenStream) -> Self { + let mut entries = Vec::new(); + Self::recursive_new(&mut entries, stream); + entries.push(Entry::End(-(entries.len() as isize), 0)); + Self { + entries: entries.into_boxed_slice(), + } + } + + /// Creates a cursor referencing the first token in the buffer and able to + /// traverse until the end of the buffer. + pub fn begin(&self) -> Cursor { + let ptr = self.entries.as_ptr(); + unsafe { Cursor::create(ptr, ptr.add(self.entries.len() - 1)) } + } +} + +/// A cheaply copyable cursor into a `TokenBuffer`. +/// +/// This cursor holds a shared reference into the immutable data which is used +/// internally to represent a `TokenStream`, and can be efficiently manipulated +/// and copied around. +/// +/// An empty `Cursor` can be created directly, or one may create a `TokenBuffer` +/// object and get a cursor to its first token with `begin()`. +pub struct Cursor<'a> { + // The current entry which the `Cursor` is pointing at. + ptr: *const Entry, + // This is the only `Entry::End` object which this cursor is allowed to + // point at. All other `End` objects are skipped over in `Cursor::create`. + scope: *const Entry, + // Cursor is covariant in 'a. This field ensures that our pointers are still + // valid. + marker: PhantomData<&'a Entry>, +} + +impl<'a> Cursor<'a> { + /// Creates a cursor referencing a static empty TokenStream. + pub fn empty() -> Self { + // It's safe in this situation for us to put an `Entry` object in global + // storage, despite it not actually being safe to send across threads + // (`Ident` is a reference into a thread-local table). This is because + // this entry never includes a `Ident` object. + // + // This wrapper struct allows us to break the rules and put a `Sync` + // object in global storage. + struct UnsafeSyncEntry(Entry); + unsafe impl Sync for UnsafeSyncEntry {} + static EMPTY_ENTRY: UnsafeSyncEntry = UnsafeSyncEntry(Entry::End(0, 0)); + + Cursor { + ptr: &EMPTY_ENTRY.0, + scope: &EMPTY_ENTRY.0, + marker: PhantomData, + } + } + + /// This create method intelligently exits non-explicitly-entered + /// `None`-delimited scopes when the cursor reaches the end of them, + /// allowing for them to be treated transparently. + unsafe fn create(mut ptr: *const Entry, scope: *const Entry) -> Self { + // NOTE: If we're looking at a `End`, we want to advance the cursor + // past it, unless `ptr == scope`, which means that we're at the edge of + // our cursor's scope. We should only have `ptr != scope` at the exit + // from None-delimited groups entered with `ignore_none`. + while let Entry::End(..) = unsafe { &*ptr } { + if ptr::eq(ptr, scope) { + break; + } + ptr = unsafe { ptr.add(1) }; + } + + Cursor { + ptr, + scope, + marker: PhantomData, + } + } + + /// Get the current entry. + fn entry(self) -> &'a Entry { + unsafe { &*self.ptr } + } + + /// Bump the cursor to point at the next token after the current one. This + /// is undefined behavior if the cursor is currently looking at an + /// `Entry::End`. + /// + /// If the cursor is looking at an `Entry::Group`, the bumped cursor will + /// point at the first token in the group (with the same scope end). + unsafe fn bump_ignore_group(self) -> Cursor<'a> { + unsafe { Cursor::create(self.ptr.add(1), self.scope) } + } + + /// While the cursor is looking at a `None`-delimited group, move it to look + /// at the first token inside instead. If the group is empty, this will move + /// the cursor past the `None`-delimited group. + /// + /// WARNING: This mutates its argument. + fn ignore_none(&mut self) { + while let Entry::Group(group, _) = self.entry() { + if group.delimiter() == Delimiter::None { + unsafe { *self = self.bump_ignore_group() }; + } else { + break; + } + } + } + + /// Checks whether the cursor is currently pointing at the end of its valid + /// scope. + pub fn eof(self) -> bool { + // We're at eof if we're at the end of our scope. + ptr::eq(self.ptr, self.scope) + } + + /// If the cursor is pointing at a `Ident`, returns it along with a cursor + /// pointing at the next `TokenTree`. + pub fn ident(mut self) -> Option<(Ident, Cursor<'a>)> { + self.ignore_none(); + match self.entry() { + Entry::Ident(ident) => Some((ident.clone(), unsafe { self.bump_ignore_group() })), + _ => None, + } + } + + pub(crate) fn peek_keyword(mut self, token: &str) -> bool { + self.ignore_none(); + match self.entry() { + Entry::Ident(ident) => ident == token, + _ => false, + } + } + + /// If the cursor is pointing at a `Punct`, returns it along with a cursor + /// pointing at the next `TokenTree`. + pub fn punct(mut self) -> Option<(Punct, Cursor<'a>)> { + self.ignore_none(); + match self.entry() { + Entry::Punct(punct) if punct.as_char() != '\'' => { + Some((punct.clone(), unsafe { self.bump_ignore_group() })) + } + _ => None, + } + } + + pub(crate) fn peek_punct(mut self, token: &str) -> bool { + for (i, ch) in token.chars().enumerate() { + self.ignore_none(); + match self.entry() { + Entry::Punct(punct) if punct.as_char() == ch => { + if i == token.len() - 1 { + return true; + } else if punct.spacing() != Spacing::Joint { + break; + } + self = unsafe { self.bump_ignore_group() }; + } + _ => break, + } + } + false + } + + /// If the cursor is pointing at a `Literal`, return it along with a cursor + /// pointing at the next `TokenTree`. + pub fn literal(mut self) -> Option<(Literal, Cursor<'a>)> { + self.ignore_none(); + match self.entry() { + Entry::Literal(literal) => Some((literal.clone(), unsafe { self.bump_ignore_group() })), + _ => None, + } + } + + /// If the cursor is pointing at a `Lifetime`, returns it along with a + /// cursor pointing at the next `TokenTree`. + pub fn lifetime(mut self) -> Option<(Lifetime, Cursor<'a>)> { + self.ignore_none(); + match self.entry() { + Entry::Punct(punct) if punct.as_char() == '\'' && punct.spacing() == Spacing::Joint => { + let next = unsafe { self.bump_ignore_group() }; + let (ident, rest) = next.ident()?; + let lifetime = Lifetime { + apostrophe: punct.span(), + ident, + }; + Some((lifetime, rest)) + } + _ => None, + } + } + + /// If the cursor is pointing at a `Group` with the given delimiter, returns + /// a cursor into that group and one pointing to the next `TokenTree`. + pub fn group(mut self, delim: Delimiter) -> Option<(Cursor<'a>, DelimSpan, Cursor<'a>)> { + // If we're not trying to enter a none-delimited group, we want to + // ignore them. We have to make sure to _not_ ignore them when we want + // to enter them, of course. For obvious reasons. + if delim != Delimiter::None { + self.ignore_none(); + } + + if let Entry::Group(group, end_offset) = self.entry() { + if group.delimiter() == delim { + let span = group.delim_span(); + let end_of_group = unsafe { self.ptr.add(*end_offset) }; + let inside_of_group = unsafe { Cursor::create(self.ptr.add(1), end_of_group) }; + let after_group = unsafe { Cursor::create(end_of_group, self.scope) }; + return Some((inside_of_group, span, after_group)); + } + } + + None + } + + /// If the cursor is pointing at a `Group`, returns a cursor into the group + /// and one pointing to the next `TokenTree`. + pub fn any_group(self) -> Option<(Cursor<'a>, Delimiter, DelimSpan, Cursor<'a>)> { + if let Entry::Group(group, end_offset) = self.entry() { + let delimiter = group.delimiter(); + let span = group.delim_span(); + let end_of_group = unsafe { self.ptr.add(*end_offset) }; + let inside_of_group = unsafe { Cursor::create(self.ptr.add(1), end_of_group) }; + let after_group = unsafe { Cursor::create(end_of_group, self.scope) }; + return Some((inside_of_group, delimiter, span, after_group)); + } + + None + } + + pub(crate) fn any_group_token(self) -> Option<(Group, Cursor<'a>)> { + if let Entry::Group(group, end_offset) = self.entry() { + let end_of_group = unsafe { self.ptr.add(*end_offset) }; + let after_group = unsafe { Cursor::create(end_of_group, self.scope) }; + return Some((group.clone(), after_group)); + } + + None + } + + /// Copies all remaining tokens visible from this cursor into a + /// `TokenStream`. + pub fn token_stream(self) -> TokenStream { + let mut tokens = TokenStream::new(); + let mut cursor = self; + while let Some((tt, rest)) = cursor.token_tree() { + tokens.append(tt); + cursor = rest; + } + tokens + } + + /// If the cursor is pointing at a `TokenTree`, returns it along with a + /// cursor pointing at the next `TokenTree`. + /// + /// Returns `None` if the cursor has reached the end of its stream. + /// + /// This method does not treat `None`-delimited groups as transparent, and + /// will return a `Group(None, ..)` if the cursor is looking at one. + pub fn token_tree(self) -> Option<(TokenTree, Cursor<'a>)> { + let (tree, len) = match self.entry() { + Entry::Group(group, end_offset) => (group.clone().into(), *end_offset), + Entry::Literal(literal) => (literal.clone().into(), 1), + Entry::Ident(ident) => (ident.clone().into(), 1), + Entry::Punct(punct) => (punct.clone().into(), 1), + Entry::End(..) => return None, + }; + + let rest = unsafe { Cursor::create(self.ptr.add(len), self.scope) }; + Some((tree, rest)) + } + + /// Returns the `Span` of the current token, or `Span::call_site()` if this + /// cursor points to eof. + pub fn span(mut self) -> Span { + match self.entry() { + Entry::Group(group, _) => group.span(), + Entry::Literal(literal) => literal.span(), + Entry::Ident(ident) => ident.span(), + Entry::Punct(punct) => punct.span(), + Entry::End(_, offset) => { + self.ptr = unsafe { self.ptr.offset(*offset) }; + if let Entry::Group(group, _) = self.entry() { + group.span_close() + } else { + Span::call_site() + } + } + } + } + + /// Returns the `Span` of the token immediately prior to the position of + /// this cursor, or of the current token if there is no previous one. + pub fn prev_span(mut self) -> Span { + if start_of_buffer(self) < self.ptr { + self.ptr = unsafe { self.ptr.sub(1) }; + } + self.span() + } + + /// Skip over the next token that is not a None-delimited group, without + /// cloning it. Returns `None` if this cursor points to eof. + /// + /// This method treats `'lifetimes` as a single token. + pub(crate) fn skip(mut self) -> Option> { + self.ignore_none(); + + let len = match self.entry() { + Entry::End(..) => return None, + + // Treat lifetimes as a single tt for the purposes of 'skip'. + Entry::Punct(punct) if punct.as_char() == '\'' && punct.spacing() == Spacing::Joint => { + match unsafe { &*self.ptr.add(1) } { + Entry::Ident(_) => 2, + _ => 1, + } + } + + Entry::Group(_, end_offset) => *end_offset, + _ => 1, + }; + + Some(unsafe { Cursor::create(self.ptr.add(len), self.scope) }) + } + + pub(crate) fn scope_delimiter(self) -> Delimiter { + match unsafe { &*self.scope } { + Entry::End(_, offset) => match unsafe { &*self.scope.offset(*offset) } { + Entry::Group(group, _) => group.delimiter(), + _ => Delimiter::None, + }, + _ => unreachable!(), + } + } +} + +impl<'a> Copy for Cursor<'a> {} + +impl<'a> Clone for Cursor<'a> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a> Eq for Cursor<'a> {} + +impl<'a> PartialEq for Cursor<'a> { + fn eq(&self, other: &Self) -> bool { + ptr::eq(self.ptr, other.ptr) + } +} + +impl<'a> PartialOrd for Cursor<'a> { + fn partial_cmp(&self, other: &Self) -> Option { + if same_buffer(*self, *other) { + Some(cmp_assuming_same_buffer(*self, *other)) + } else { + None + } + } +} + +pub(crate) fn same_scope(a: Cursor, b: Cursor) -> bool { + ptr::eq(a.scope, b.scope) +} + +pub(crate) fn same_buffer(a: Cursor, b: Cursor) -> bool { + ptr::eq(start_of_buffer(a), start_of_buffer(b)) +} + +fn start_of_buffer(cursor: Cursor) -> *const Entry { + unsafe { + match &*cursor.scope { + Entry::End(offset, _) => cursor.scope.offset(*offset), + _ => unreachable!(), + } + } +} + +pub(crate) fn cmp_assuming_same_buffer(a: Cursor, b: Cursor) -> Ordering { + a.ptr.cmp(&b.ptr) +} + +pub(crate) fn open_span_of_group(cursor: Cursor) -> Span { + match cursor.entry() { + Entry::Group(group, _) => group.span_open(), + _ => cursor.span(), + } +} diff --git a/third_party/crates/syn-3.0.5/src/classify.rs b/third_party/crates/syn-3.0.5/src/classify.rs new file mode 100644 index 0000000..10c23e2 --- /dev/null +++ b/third_party/crates/syn-3.0.5/src/classify.rs @@ -0,0 +1,311 @@ +#[cfg(feature = "full")] +use crate::expr::Expr; +#[cfg(any(feature = "printing", feature = "full"))] +use crate::generics::TypeParamBound; +#[cfg(any(feature = "printing", feature = "full"))] +use crate::path::{Path, PathArguments}; +#[cfg(any(feature = "printing", feature = "full"))] +use crate::punctuated::Punctuated; +#[cfg(any(feature = "printing", feature = "full"))] +use crate::ty::{ReturnType, Type}; +#[cfg(any(feature = "printing", feature = "full"))] +use core::ops::ControlFlow; +#[cfg(feature = "full")] +use proc_macro2::{Delimiter, TokenStream, TokenTree}; + +#[cfg(feature = "full")] +pub(crate) fn requires_semi_to_be_stmt(expr: &Expr) -> bool { + match expr { + Expr::Macro(expr) => !expr.mac.delimiter.is_brace(), + _ => requires_comma_to_be_match_arm(expr), + } +} + +#[cfg(feature = "full")] +pub(crate) fn requires_comma_to_be_match_arm(expr: &Expr) -> bool { + match expr { + Expr::If(_) + | Expr::Match(_) + | Expr::Block(_) | Expr::Unsafe(_) // both under ExprKind::Block in rustc + | Expr::While(_) + | Expr::Loop(_) + | Expr::ForLoop(_) + | Expr::TryBlock(_) + | Expr::Const(_) => false, + + Expr::Array(_) + | Expr::Assign(_) + | Expr::Async(_) + | Expr::Await(_) + | Expr::Binary(_) + | Expr::Break(_) + | Expr::Call(_) + | Expr::Cast(_) + | Expr::Closure(_) + | Expr::Continue(_) + | Expr::Field(_) + | Expr::Group(_) + | Expr::Index(_) + | Expr::Infer(_) + | Expr::Let(_) + | Expr::Lit(_) + | Expr::Macro(_) + | Expr::MethodCall(_) + | Expr::Paren(_) + | Expr::Path(_) + | Expr::Range(_) + | Expr::RawAddr(_) + | Expr::Reference(_) + | Expr::Repeat(_) + | Expr::Return(_) + | Expr::Struct(_) + | Expr::Try(_) + | Expr::Tuple(_) + | Expr::Unary(_) + | Expr::Yield(_) + | Expr::Verbatim(_) => true, + } +} + +#[cfg(feature = "printing")] +pub(crate) fn trailing_unparameterized_path(mut ty: &Type) -> bool { + loop { + match ty { + Type::FnPtr(t) => match &t.output { + ReturnType::Default => return false, + ReturnType::Type(_, ret) => ty = ret, + }, + Type::ImplTrait(t) => match last_type_in_bounds(&t.bounds) { + ControlFlow::Break(trailing_path) => return trailing_path, + ControlFlow::Continue(t) => ty = t, + }, + Type::Path(t) => match last_type_in_path(&t.path) { + ControlFlow::Break(trailing_path) => return trailing_path, + ControlFlow::Continue(t) => ty = t, + }, + Type::Ptr(t) => ty = &t.elem, + Type::Reference(t) => ty = &t.elem, + Type::TraitObject(t) => match last_type_in_bounds(&t.bounds) { + ControlFlow::Break(trailing_path) => return trailing_path, + ControlFlow::Continue(t) => ty = t, + }, + + Type::Array(_) + | Type::Group(_) + | Type::Infer(_) + | Type::Macro(_) + | Type::Never(_) + | Type::Paren(_) + | Type::Slice(_) + | Type::Tuple(_) + | Type::Verbatim(_) => return false, + } + } + + fn last_type_in_path(path: &Path) -> ControlFlow { + match &path.segments.last().unwrap().arguments { + PathArguments::None => ControlFlow::Break(true), + PathArguments::AngleBracketed(_) => ControlFlow::Break(false), + PathArguments::Parenthesized(arg) => match &arg.output { + ReturnType::Default => ControlFlow::Break(false), + ReturnType::Type(_, ret) => ControlFlow::Continue(ret), + }, + } + } + + fn last_type_in_bounds( + bounds: &Punctuated, + ) -> ControlFlow { + match bounds.last().unwrap() { + TypeParamBound::Trait(t) => last_type_in_path(&t.path), + TypeParamBound::Lifetime(_) + | TypeParamBound::PreciseCapture(_) + | TypeParamBound::Verbatim(_) => ControlFlow::Break(false), + } + } +} + +/// Whether the expression's first token is the label of a loop/block. +#[cfg(all(feature = "printing", feature = "full"))] +pub(crate) fn expr_leading_label(mut expr: &Expr) -> bool { + loop { + match expr { + Expr::Block(e) => return e.label.is_some(), + Expr::ForLoop(e) => return e.label.is_some(), + Expr::Loop(e) => return e.label.is_some(), + Expr::While(e) => return e.label.is_some(), + + Expr::Assign(e) => expr = &e.left, + Expr::Await(e) => expr = &e.base, + Expr::Binary(e) => expr = &e.left, + Expr::Call(e) => expr = &e.func, + Expr::Cast(e) => expr = &e.expr, + Expr::Field(e) => expr = &e.base, + Expr::Index(e) => expr = &e.expr, + Expr::MethodCall(e) => expr = &e.receiver, + Expr::Range(e) => match &e.start { + Some(start) => expr = start, + None => return false, + }, + Expr::Try(e) => expr = &e.expr, + + Expr::Array(_) + | Expr::Async(_) + | Expr::Break(_) + | Expr::Closure(_) + | Expr::Const(_) + | Expr::Continue(_) + | Expr::Group(_) + | Expr::If(_) + | Expr::Infer(_) + | Expr::Let(_) + | Expr::Lit(_) + | Expr::Macro(_) + | Expr::Match(_) + | Expr::Paren(_) + | Expr::Path(_) + | Expr::RawAddr(_) + | Expr::Reference(_) + | Expr::Repeat(_) + | Expr::Return(_) + | Expr::Struct(_) + | Expr::TryBlock(_) + | Expr::Tuple(_) + | Expr::Unary(_) + | Expr::Unsafe(_) + | Expr::Verbatim(_) + | Expr::Yield(_) => return false, + } + } +} + +/// Whether the expression's last token is `}`. +#[cfg(feature = "full")] +pub(crate) fn expr_trailing_brace(mut expr: &Expr) -> bool { + loop { + match expr { + Expr::Async(_) + | Expr::Block(_) + | Expr::Const(_) + | Expr::ForLoop(_) + | Expr::If(_) + | Expr::Loop(_) + | Expr::Match(_) + | Expr::Struct(_) + | Expr::TryBlock(_) + | Expr::Unsafe(_) + | Expr::While(_) => return true, + + Expr::Assign(e) => expr = &e.right, + Expr::Binary(e) => expr = &e.right, + Expr::Break(e) => match &e.expr { + Some(e) => expr = e, + None => return false, + }, + Expr::Cast(e) => return type_trailing_brace(&e.ty), + Expr::Closure(e) => expr = &e.body, + Expr::Let(e) => expr = &e.expr, + Expr::Macro(e) => return e.mac.delimiter.is_brace(), + Expr::Range(e) => match &e.end { + Some(end) => expr = end, + None => return false, + }, + Expr::RawAddr(e) => expr = &e.expr, + Expr::Reference(e) => expr = &e.expr, + Expr::Return(e) => match &e.expr { + Some(e) => expr = e, + None => return false, + }, + Expr::Unary(e) => expr = &e.expr, + Expr::Verbatim(e) => return tokens_trailing_brace(e), + Expr::Yield(e) => match &e.expr { + Some(e) => expr = e, + None => return false, + }, + + Expr::Array(_) + | Expr::Await(_) + | Expr::Call(_) + | Expr::Continue(_) + | Expr::Field(_) + | Expr::Group(_) + | Expr::Index(_) + | Expr::Infer(_) + | Expr::Lit(_) + | Expr::MethodCall(_) + | Expr::Paren(_) + | Expr::Path(_) + | Expr::Repeat(_) + | Expr::Try(_) + | Expr::Tuple(_) => return false, + } + } + + fn type_trailing_brace(mut ty: &Type) -> bool { + loop { + match ty { + Type::FnPtr(t) => match &t.output { + ReturnType::Default => return false, + ReturnType::Type(_, ret) => ty = ret, + }, + Type::ImplTrait(t) => match last_type_in_bounds(&t.bounds) { + ControlFlow::Break(trailing_brace) => return trailing_brace, + ControlFlow::Continue(t) => ty = t, + }, + Type::Macro(t) => return t.mac.delimiter.is_brace(), + Type::Path(t) => match last_type_in_path(&t.path) { + Some(t) => ty = t, + None => return false, + }, + Type::Ptr(t) => ty = &t.elem, + Type::Reference(t) => ty = &t.elem, + Type::TraitObject(t) => match last_type_in_bounds(&t.bounds) { + ControlFlow::Break(trailing_brace) => return trailing_brace, + ControlFlow::Continue(t) => ty = t, + }, + Type::Verbatim(t) => return tokens_trailing_brace(t), + + Type::Array(_) + | Type::Group(_) + | Type::Infer(_) + | Type::Never(_) + | Type::Paren(_) + | Type::Slice(_) + | Type::Tuple(_) => return false, + } + } + } + + fn last_type_in_path(path: &Path) -> Option<&Type> { + match &path.segments.last().unwrap().arguments { + PathArguments::None | PathArguments::AngleBracketed(_) => None, + PathArguments::Parenthesized(arg) => match &arg.output { + ReturnType::Default => None, + ReturnType::Type(_, ret) => Some(ret), + }, + } + } + + fn last_type_in_bounds( + bounds: &Punctuated, + ) -> ControlFlow { + match bounds.last().unwrap() { + TypeParamBound::Trait(t) => match last_type_in_path(&t.path) { + Some(t) => ControlFlow::Continue(t), + None => ControlFlow::Break(false), + }, + TypeParamBound::Lifetime(_) | TypeParamBound::PreciseCapture(_) => { + ControlFlow::Break(false) + } + TypeParamBound::Verbatim(t) => ControlFlow::Break(tokens_trailing_brace(t)), + } + } + + fn tokens_trailing_brace(tokens: &TokenStream) -> bool { + if let Some(TokenTree::Group(last)) = tokens.clone().into_iter().last() { + last.delimiter() == Delimiter::Brace + } else { + false + } + } +} diff --git a/third_party/crates/syn-3.0.5/src/custom_keyword.rs b/third_party/crates/syn-3.0.5/src/custom_keyword.rs new file mode 100644 index 0000000..cc4f632 --- /dev/null +++ b/third_party/crates/syn-3.0.5/src/custom_keyword.rs @@ -0,0 +1,260 @@ +/// Define a type that supports parsing and printing a given identifier as if it +/// were a keyword. +/// +/// # Usage +/// +/// As a convention, it is recommended that this macro be invoked within a +/// module called `kw` or `keyword` and that the resulting parser be invoked +/// with a `kw::` or `keyword::` prefix. +/// +/// ``` +/// mod kw { +/// syn::custom_keyword!(whatever); +/// } +/// ``` +/// +/// The generated syntax tree node supports the following operations just like +/// any built-in keyword token. +/// +/// - [Peeking] — `input.peek(kw::whatever)` +/// +/// - [Parsing] — `input.parse::()?` +/// +/// - [Printing] — `quote!( ... #whatever_token ... )` +/// +/// - Construction from a [`Span`] — `let whatever_token = kw::whatever(sp)` +/// +/// - Field access to its span — `let sp = whatever_token.span` +/// +/// [Peeking]: crate::parse::ParseBuffer::peek +/// [Parsing]: crate::parse::ParseBuffer::parse +/// [Printing]: quote::ToTokens +/// [`Span`]: proc_macro2::Span +/// +/// # Example +/// +/// This example parses input that looks like `bool = true` or `str = "value"`. +/// The key must be either the identifier `bool` or the identifier `str`. If +/// `bool`, the value may be either `true` or `false`. If `str`, the value may +/// be any string literal. +/// +/// The symbols `bool` and `str` are not reserved keywords in Rust so these are +/// not considered keywords in the `syn::token` module. Like any other +/// identifier that is not a keyword, these can be declared as custom keywords +/// by crates that need to use them as such. +/// +/// ``` +/// use syn::{LitBool, LitStr, Result, Token}; +/// use syn::parse::{Parse, ParseStream}; +/// +/// mod kw { +/// syn::custom_keyword!(bool); +/// syn::custom_keyword!(str); +/// } +/// +/// enum Argument { +/// Bool { +/// bool_token: kw::bool, +/// eq_token: Token![=], +/// value: LitBool, +/// }, +/// Str { +/// str_token: kw::str, +/// eq_token: Token![=], +/// value: LitStr, +/// }, +/// } +/// +/// impl Parse for Argument { +/// fn parse(input: ParseStream) -> Result { +/// let lookahead = input.lookahead1(); +/// if lookahead.peek(kw::bool) { +/// Ok(Argument::Bool { +/// bool_token: input.parse::()?, +/// eq_token: input.parse()?, +/// value: input.parse()?, +/// }) +/// } else if lookahead.peek(kw::str) { +/// Ok(Argument::Str { +/// str_token: input.parse::()?, +/// eq_token: input.parse()?, +/// value: input.parse()?, +/// }) +/// } else { +/// Err(lookahead.error()) +/// } +/// } +/// } +/// ``` +#[macro_export] +macro_rules! custom_keyword { + ($ident:ident) => { + #[allow(non_camel_case_types)] + pub struct $ident { + #[allow(dead_code)] + pub span: $crate::__private::Span, + } + + #[doc(hidden)] + #[allow(dead_code, non_snake_case)] + pub fn $ident<__S: $crate::__private::IntoSpans<$crate::__private::Span>>( + span: __S, + ) -> $ident { + $ident { + span: $crate::__private::IntoSpans::into_spans(span), + } + } + + const _: () = { + impl $crate::__private::Default for $ident { + fn default() -> Self { + $ident { + span: $crate::__private::Span::call_site(), + } + } + } + + $crate::impl_parse_for_custom_keyword!($ident); + $crate::impl_to_tokens_for_custom_keyword!($ident); + $crate::impl_clone_for_custom_keyword!($ident); + $crate::impl_extra_traits_for_custom_keyword!($ident); + }; + }; +} + +// Not public API. +#[cfg(feature = "parsing")] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_parse_for_custom_keyword { + ($ident:ident) => { + // For peek. + impl $crate::__private::CustomToken for $ident { + fn peek(cursor: $crate::buffer::Cursor) -> $crate::__private::bool { + if let $crate::__private::Some((ident, _rest)) = cursor.ident() { + ident == $crate::__private::stringify!($ident) + } else { + false + } + } + + fn display() -> &'static $crate::__private::str { + $crate::__private::concat!("`", $crate::__private::stringify!($ident), "`") + } + } + + impl $crate::parse::Parse for $ident { + fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> { + input.step(|cursor| { + if let $crate::__private::Some((ident, rest)) = cursor.ident() { + if ident == $crate::__private::stringify!($ident) { + return $crate::__private::Ok(($ident { span: ident.span() }, rest)); + } + } + $crate::__private::Err(cursor.error($crate::__private::concat!( + "expected `", + $crate::__private::stringify!($ident), + "`", + ))) + }) + } + } + }; +} + +// Not public API. +#[cfg(not(feature = "parsing"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_parse_for_custom_keyword { + ($ident:ident) => {}; +} + +// Not public API. +#[cfg(feature = "printing")] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_to_tokens_for_custom_keyword { + ($ident:ident) => { + impl $crate::__private::ToTokens for $ident { + fn to_tokens(&self, tokens: &mut $crate::__private::TokenStream2) { + let ident = $crate::Ident::new($crate::__private::stringify!($ident), self.span); + $crate::__private::TokenStreamExt::append(tokens, ident); + } + } + }; +} + +// Not public API. +#[cfg(not(feature = "printing"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_to_tokens_for_custom_keyword { + ($ident:ident) => {}; +} + +// Not public API. +#[cfg(feature = "clone-impls")] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_clone_for_custom_keyword { + ($ident:ident) => { + impl $crate::__private::Copy for $ident {} + + #[allow(clippy::expl_impl_clone_on_copy)] + impl $crate::__private::Clone for $ident { + fn clone(&self) -> Self { + *self + } + } + }; +} + +// Not public API. +#[cfg(not(feature = "clone-impls"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_clone_for_custom_keyword { + ($ident:ident) => {}; +} + +// Not public API. +#[cfg(feature = "extra-traits")] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_extra_traits_for_custom_keyword { + ($ident:ident) => { + impl $crate::__private::Debug for $ident { + fn fmt(&self, f: &mut $crate::__private::Formatter) -> $crate::__private::FmtResult { + $crate::__private::Formatter::write_str( + f, + $crate::__private::concat!( + "Keyword [", + $crate::__private::stringify!($ident), + "]", + ), + ) + } + } + + impl $crate::__private::Eq for $ident {} + + impl $crate::__private::PartialEq for $ident { + fn eq(&self, _other: &Self) -> $crate::__private::bool { + true + } + } + + impl $crate::__private::Hash for $ident { + fn hash<__H: $crate::__private::Hasher>(&self, _state: &mut __H) {} + } + }; +} + +// Not public API. +#[cfg(not(feature = "extra-traits"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_extra_traits_for_custom_keyword { + ($ident:ident) => {}; +} diff --git a/third_party/crates/syn-3.0.5/src/custom_punctuation.rs b/third_party/crates/syn-3.0.5/src/custom_punctuation.rs new file mode 100644 index 0000000..58955c7 --- /dev/null +++ b/third_party/crates/syn-3.0.5/src/custom_punctuation.rs @@ -0,0 +1,305 @@ +/// Define a type that supports parsing and printing a multi-character symbol +/// as if it were a punctuation token. +/// +/// # Usage +/// +/// ``` +/// syn::custom_punctuation!(LeftRightArrow, <=>); +/// ``` +/// +/// The generated syntax tree node supports the following operations just like +/// any built-in punctuation token. +/// +/// - [Peeking] — `input.peek(LeftRightArrow)` +/// +/// - [Parsing] — `input.parse::()?` +/// +/// - [Printing] — `quote!( ... #lrarrow ... )` +/// +/// - Construction from a [`Span`] — `let lrarrow = LeftRightArrow(sp)` +/// +/// - Construction from multiple [`Span`] — `let lrarrow = LeftRightArrow([sp, sp, sp])` +/// +/// - Field access to its spans — `let spans = lrarrow.spans` +/// +/// [Peeking]: crate::parse::ParseBuffer::peek +/// [Parsing]: crate::parse::ParseBuffer::parse +/// [Printing]: quote::ToTokens +/// [`Span`]: proc_macro2::Span +/// +/// # Example +/// +/// ``` +/// use core::iter; +/// use proc_macro2::{TokenStream, TokenTree}; +/// use syn::parse::{Parse, ParseStream, Peek, Result}; +/// use syn::punctuated::Punctuated; +/// use syn::Expr; +/// +/// syn::custom_punctuation!(PathSeparator, ); +/// +/// // expr expr expr ... +/// struct PathSegments { +/// segments: Punctuated, +/// } +/// +/// impl Parse for PathSegments { +/// fn parse(input: ParseStream) -> Result { +/// let mut segments = Punctuated::new(); +/// +/// let first = parse_until(input, PathSeparator)?; +/// segments.push_value(syn::parse2(first)?); +/// +/// while input.peek(PathSeparator) { +/// segments.push_punct(input.parse()?); +/// +/// let next = parse_until(input, PathSeparator)?; +/// segments.push_value(syn::parse2(next)?); +/// } +/// +/// Ok(PathSegments { segments }) +/// } +/// } +/// +/// fn parse_until(input: ParseStream, end: E) -> Result { +/// let mut tokens = TokenStream::new(); +/// while !input.is_empty() && !input.peek(end) { +/// let next: TokenTree = input.parse()?; +/// tokens.extend(iter::once(next)); +/// } +/// Ok(tokens) +/// } +/// +/// fn main() { +/// let input = r#" a::b c::d::e "#; +/// let _: PathSegments = syn::parse_str(input).unwrap(); +/// } +/// ``` +#[macro_export] +macro_rules! custom_punctuation { + ($ident:ident, $($tt:tt)+) => { + pub struct $ident { + #[allow(dead_code)] + pub spans: $crate::custom_punctuation_repr!($($tt)+), + } + + #[doc(hidden)] + #[allow(dead_code, non_snake_case)] + pub fn $ident<__S: $crate::__private::IntoSpans<$crate::custom_punctuation_repr!($($tt)+)>>( + spans: __S, + ) -> $ident { + let _validate_len = 0 $(+ $crate::custom_punctuation_len!(strict, $tt))*; + $ident { + spans: $crate::__private::IntoSpans::into_spans(spans) + } + } + + const _: () = { + impl $crate::__private::Default for $ident { + fn default() -> Self { + $ident($crate::__private::Span::call_site()) + } + } + + $crate::impl_parse_for_custom_punctuation!($ident, $($tt)+); + $crate::impl_to_tokens_for_custom_punctuation!($ident, $($tt)+); + $crate::impl_clone_for_custom_punctuation!($ident, $($tt)+); + $crate::impl_extra_traits_for_custom_punctuation!($ident, $($tt)+); + }; + }; +} + +// Not public API. +#[cfg(feature = "parsing")] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_parse_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => { + impl $crate::__private::CustomToken for $ident { + fn peek(cursor: $crate::buffer::Cursor) -> $crate::__private::bool { + $crate::__private::peek_punct(cursor, $crate::stringify_punct!($($tt)+)) + } + + fn display() -> &'static $crate::__private::str { + $crate::__private::concat!("`", $crate::stringify_punct!($($tt)+), "`") + } + } + + impl $crate::parse::Parse for $ident { + fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> { + let spans: $crate::custom_punctuation_repr!($($tt)+) = + $crate::__private::parse_punct(input, $crate::stringify_punct!($($tt)+))?; + Ok($ident(spans)) + } + } + }; +} + +// Not public API. +#[cfg(not(feature = "parsing"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_parse_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => {}; +} + +// Not public API. +#[cfg(feature = "printing")] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_to_tokens_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => { + impl $crate::__private::ToTokens for $ident { + fn to_tokens(&self, tokens: &mut $crate::__private::TokenStream2) { + $crate::__private::print_punct($crate::stringify_punct!($($tt)+), &self.spans, tokens) + } + } + }; +} + +// Not public API. +#[cfg(not(feature = "printing"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_to_tokens_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => {}; +} + +// Not public API. +#[cfg(feature = "clone-impls")] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_clone_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => { + impl $crate::__private::Copy for $ident {} + + #[allow(clippy::expl_impl_clone_on_copy)] + impl $crate::__private::Clone for $ident { + fn clone(&self) -> Self { + *self + } + } + }; +} + +// Not public API. +#[cfg(not(feature = "clone-impls"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_clone_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => {}; +} + +// Not public API. +#[cfg(feature = "extra-traits")] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_extra_traits_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => { + impl $crate::__private::Debug for $ident { + fn fmt(&self, f: &mut $crate::__private::Formatter) -> $crate::__private::FmtResult { + $crate::__private::Formatter::write_str(f, $crate::__private::stringify!($ident)) + } + } + + impl $crate::__private::Eq for $ident {} + + impl $crate::__private::PartialEq for $ident { + fn eq(&self, _other: &Self) -> $crate::__private::bool { + true + } + } + + impl $crate::__private::Hash for $ident { + fn hash<__H: $crate::__private::Hasher>(&self, _state: &mut __H) {} + } + }; +} + +// Not public API. +#[cfg(not(feature = "extra-traits"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_extra_traits_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => {}; +} + +// Not public API. +#[doc(hidden)] +#[macro_export] +macro_rules! custom_punctuation_repr { + ($($tt:tt)+) => { + [$crate::__private::Span; 0 $(+ $crate::custom_punctuation_len!(lenient, $tt))+] + }; +} + +// Not public API. +#[doc(hidden)] +#[macro_export] +#[rustfmt::skip] +macro_rules! custom_punctuation_len { + ($mode:ident, &) => { 1 }; + ($mode:ident, &&) => { 2 }; + ($mode:ident, &=) => { 2 }; + ($mode:ident, @) => { 1 }; + ($mode:ident, ^) => { 1 }; + ($mode:ident, ^=) => { 2 }; + ($mode:ident, :) => { 1 }; + ($mode:ident, ,) => { 1 }; + ($mode:ident, $) => { 1 }; + ($mode:ident, .) => { 1 }; + ($mode:ident, ..) => { 2 }; + ($mode:ident, ...) => { 3 }; + ($mode:ident, ..=) => { 3 }; + ($mode:ident, =) => { 1 }; + ($mode:ident, ==) => { 2 }; + ($mode:ident, =>) => { 2 }; + ($mode:ident, >=) => { 2 }; + ($mode:ident, >) => { 1 }; + ($mode:ident, <-) => { 2 }; + ($mode:ident, <=) => { 2 }; + ($mode:ident, <) => { 1 }; + ($mode:ident, -) => { 1 }; + ($mode:ident, -=) => { 2 }; + ($mode:ident, !=) => { 2 }; + ($mode:ident, !) => { 1 }; + ($mode:ident, |) => { 1 }; + ($mode:ident, |=) => { 2 }; + ($mode:ident, ||) => { 2 }; + ($mode:ident, ::) => { 2 }; + ($mode:ident, %) => { 1 }; + ($mode:ident, %=) => { 2 }; + ($mode:ident, +) => { 1 }; + ($mode:ident, +=) => { 2 }; + ($mode:ident, #) => { 1 }; + ($mode:ident, ?) => { 1 }; + ($mode:ident, ->) => { 2 }; + ($mode:ident, ;) => { 1 }; + ($mode:ident, <<) => { 2 }; + ($mode:ident, <<=) => { 3 }; + ($mode:ident, >>) => { 2 }; + ($mode:ident, >>=) => { 3 }; + ($mode:ident, /) => { 1 }; + ($mode:ident, /=) => { 2 }; + ($mode:ident, *) => { 1 }; + ($mode:ident, *=) => { 2 }; + ($mode:ident, ~) => { 1 }; + (lenient, $tt:tt) => { 0 }; + (strict, $tt:tt) => {{ $crate::custom_punctuation_unexpected!($tt); 0 }}; +} + +// Not public API. +#[doc(hidden)] +#[macro_export] +macro_rules! custom_punctuation_unexpected { + () => {}; +} + +// Not public API. +#[doc(hidden)] +#[macro_export] +macro_rules! stringify_punct { + ($($tt:tt)+) => { + $crate::__private::concat!($($crate::__private::stringify!($tt)),+) + }; +} diff --git a/third_party/crates/syn-3.0.5/src/data.rs b/third_party/crates/syn-3.0.5/src/data.rs new file mode 100644 index 0000000..e2e936a --- /dev/null +++ b/third_party/crates/syn-3.0.5/src/data.rs @@ -0,0 +1,489 @@ +use crate::attr::Attribute; +#[cfg(feature = "parsing")] +use crate::error::Result; +use crate::expr::{Expr, Index, Member}; +use crate::ident::Ident; +use crate::punctuated::{self, Punctuated}; +use crate::restriction::Visibility; +use crate::token; +use crate::ty::Type; +use alloc::vec::Vec; + +ast_struct! { + /// An enum variant. + #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] + pub struct Variant { + pub attrs: Vec, + + /// Name of the variant. + pub ident: Ident, + + /// Content stored in the variant. + pub fields: Fields, + + /// Explicit discriminant: `Variant = 1` + pub discriminant: Option<(Token![=], Expr)>, + } +} + +ast_enum_of_structs! { + /// Data stored within an enum variant or struct. + /// + /// # Syntax tree enum + /// + /// This type is a [syntax tree enum]. + /// + /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums + #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] + pub enum Fields { + /// Named fields of a struct or struct variant such as `Point { x: f64, + /// y: f64 }`. + Named(FieldsNamed), + + /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`. + Unnamed(FieldsUnnamed), + + /// Unit struct or unit variant such as `None`. + Unit, + } +} + +ast_struct! { + /// Named fields of a struct or struct variant such as `Point { x: f64, + /// y: f64 }`. + #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] + pub struct FieldsNamed { + pub brace_token: token::Brace, + pub named: Punctuated, + } +} + +ast_struct! { + /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`. + #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] + pub struct FieldsUnnamed { + pub paren_token: token::Paren, + pub unnamed: Punctuated, + } +} + +impl Fields { + /// Get an iterator over the borrowed [`Field`] items in this object. This + /// iterator can be used to iterate over a named or unnamed struct or + /// variant's fields uniformly. + pub fn iter(&self) -> punctuated::Iter { + match self { + Fields::Unit => crate::punctuated::empty_punctuated_iter(), + Fields::Named(f) => f.named.iter(), + Fields::Unnamed(f) => f.unnamed.iter(), + } + } + + /// Get an iterator over the mutably borrowed [`Field`] items in this + /// object. This iterator can be used to iterate over a named or unnamed + /// struct or variant's fields uniformly. + pub fn iter_mut(&mut self) -> punctuated::IterMut { + match self { + Fields::Unit => crate::punctuated::empty_punctuated_iter_mut(), + Fields::Named(f) => f.named.iter_mut(), + Fields::Unnamed(f) => f.unnamed.iter_mut(), + } + } + + /// Returns the number of fields. + pub fn len(&self) -> usize { + match self { + Fields::Unit => 0, + Fields::Named(f) => f.named.len(), + Fields::Unnamed(f) => f.unnamed.len(), + } + } + + /// Returns `true` if there are zero fields. + pub fn is_empty(&self) -> bool { + match self { + Fields::Unit => true, + Fields::Named(f) => f.named.is_empty(), + Fields::Unnamed(f) => f.unnamed.is_empty(), + } + } + + return_impl_trait! { + /// Get an iterator over the fields of a struct or variant as [`Member`]s. + /// This iterator can be used to iterate over a named or unnamed struct or + /// variant's fields uniformly. + /// + /// # Example + /// + /// The following is a simplistic [`Clone`] derive for structs. (A more + /// complete implementation would additionally want to infer trait bounds on + /// the generic type parameters.) + /// + /// ``` + /// # use quote::quote; + /// # + /// fn derive_clone(input: &syn::ItemStruct) -> proc_macro2::TokenStream { + /// let ident = &input.ident; + /// let members = input.fields.members(); + /// let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + /// quote! { + /// impl #impl_generics Clone for #ident #ty_generics #where_clause { + /// fn clone(&self) -> Self { + /// Self { + /// #(#members: self.#members.clone()),* + /// } + /// } + /// } + /// } + /// } + /// ``` + /// + /// For structs with named fields, it produces an expression like `Self { a: + /// self.a.clone() }`. For structs with unnamed fields, `Self { 0: + /// self.0.clone() }`. And for unit structs, `Self {}`. + pub fn members(&self) -> impl Iterator + Clone + '_ [Members] { + Members { + fields: self.iter(), + index: 0, + } + } + } +} + +impl IntoIterator for Fields { + type Item = Field; + type IntoIter = punctuated::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + match self { + Fields::Unit => Punctuated::::new().into_iter(), + Fields::Named(f) => f.named.into_iter(), + Fields::Unnamed(f) => f.unnamed.into_iter(), + } + } +} + +impl<'a> IntoIterator for &'a Fields { + type Item = &'a Field; + type IntoIter = punctuated::Iter<'a, Field>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a> IntoIterator for &'a mut Fields { + type Item = &'a mut Field; + type IntoIter = punctuated::IterMut<'a, Field>; + + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +ast_struct! { + /// A field of a struct or enum variant. + #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] + pub struct Field { + pub attrs: Vec, + + pub vis: Visibility, + + /// (Non-exhaustive) Additional optional information about a field. + pub modifiers: FieldModifiers, + + /// Name of the field, if any. + /// + /// Fields of tuple structs have no names. + pub ident: Option, + + pub colon_token: Option, + + pub ty: Type, + + pub default: Option<(Token![=], Expr)>, + } +} + +ast_struct! { + /// Additional optional information about a field. + /// + /// This data structure may grow to accommodate future Rust language + /// changes, including the following in-progress RFCs: + /// + /// - [RFC 3323] "Restrictions", such as `mut(crate)` + /// - [RFC 3458] "Unsafe fields" + /// + /// [RFC 3323]: https://rust-lang.github.io/rfcs/3323-restrictions.html + /// [RFC 3458]: https://github.com/rust-lang/rfcs/pull/3458 + #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] + #[non_exhaustive] + pub struct FieldModifiers {} +} + +impl Default for FieldModifiers { + fn default() -> Self { + FieldModifiers {} + } +} + +impl FieldModifiers { + #[cfg(feature = "parsing")] + #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] + pub fn require_empty(&self) -> Result<()> { + Ok(()) + } +} + +pub struct Members<'a> { + fields: punctuated::Iter<'a, Field>, + index: u32, +} + +impl<'a> Iterator for Members<'a> { + type Item = Member; + + fn next(&mut self) -> Option { + let field = self.fields.next()?; + let member = match &field.ident { + Some(ident) => Member::Named(ident.clone()), + None => { + #[cfg(all(feature = "parsing", feature = "printing"))] + let span = crate::spanned::Spanned::span(&field.ty); + #[cfg(not(all(feature = "parsing", feature = "printing")))] + let span = proc_macro2::Span::call_site(); + Member::Unnamed(Index { + index: self.index, + span, + }) + } + }; + self.index += 1; + Some(member) + } +} + +impl<'a> Clone for Members<'a> { + fn clone(&self) -> Self { + Members { + fields: self.fields.clone(), + index: self.index, + } + } +} + +#[cfg(feature = "parsing")] +pub(crate) mod parsing { + use crate::attr::Attribute; + use crate::data::{Field, FieldModifiers, Fields, FieldsNamed, FieldsUnnamed, Variant}; + use crate::error::{Error, Result}; + use crate::expr::Expr; + use crate::ext::IdentExt as _; + use crate::ident::Ident; + #[cfg(not(feature = "full"))] + use crate::parse::discouraged::Speculative as _; + use crate::parse::{Parse, ParseStream}; + use crate::restriction::Visibility; + #[cfg(not(feature = "full"))] + use crate::scan_expr::scan_expr; + use crate::token; + use crate::ty::Type; + use crate::verbatim; + + #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] + impl Parse for Variant { + fn parse(input: ParseStream) -> Result { + let attrs = input.call(Attribute::parse_outer)?; + let _visibility: Visibility = input.parse()?; + let ident: Ident = input.parse()?; + let fields = if input.peek(token::Brace) { + Fields::Named(input.parse()?) + } else if input.peek(token::Paren) { + Fields::Unnamed(input.parse()?) + } else { + Fields::Unit + }; + let discriminant = if input.peek(Token![=]) { + let eq_token: Token![=] = input.parse()?; + #[cfg(feature = "full")] + let discriminant: Expr = input.parse()?; + #[cfg(not(feature = "full"))] + let discriminant = { + let begin = input.cursor(); + let ahead = input.fork(); + let mut discriminant: Result = ahead.parse(); + if discriminant.is_ok() { + input.advance_to(&ahead); + } else if scan_expr(input).is_ok() { + discriminant = Ok(Expr::Verbatim(verbatim::between(begin, input.cursor()))); + } + discriminant? + }; + Some((eq_token, discriminant)) + } else { + None + }; + Ok(Variant { + attrs, + ident, + fields, + discriminant, + }) + } + } + + #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] + impl Parse for FieldsNamed { + fn parse(input: ParseStream) -> Result { + let content; + Ok(FieldsNamed { + brace_token: braced!(content in input), + named: content.parse_terminated(Field::parse_named, Token![,])?, + }) + } + } + + #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] + impl Parse for FieldsUnnamed { + fn parse(input: ParseStream) -> Result { + let content; + Ok(FieldsUnnamed { + paren_token: parenthesized!(content in input), + unnamed: content.parse_terminated(Field::parse_unnamed, Token![,])?, + }) + } + } + + impl Field { + /// Parses a named (braced struct) field. + #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] + pub fn parse_named(input: ParseStream) -> Result { + let attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + + let unnamed_field = cfg!(feature = "full") && input.peek(Token![_]); + let ident = if unnamed_field { + input.call(Ident::parse_any) + } else { + input.parse() + }?; + + let colon_token: Token![:] = input.parse()?; + + let ty: Type = if unnamed_field + && (input.peek(Token![struct]) + || input.peek(Token![union]) && input.peek2(token::Brace)) + { + let begin = input.cursor(); + input.call(Ident::parse_any)?; + input.parse::()?; + Type::Verbatim(verbatim::between(begin, input.cursor())) + } else { + input.parse()? + }; + + let default = if input.peek(Token![=]) { + let eq_token: Token![=] = input.parse()?; + let expr: Expr = input.parse()?; + Some((eq_token, expr)) + } else { + None + }; + + Ok(Field { + attrs, + vis, + modifiers: FieldModifiers {}, + ident: Some(ident), + colon_token: Some(colon_token), + ty, + default, + }) + } + + /// Parses an unnamed (tuple struct) field. + #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] + pub fn parse_unnamed(input: ParseStream) -> Result { + let attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + let ty: Type = input.parse()?; + + if input.peek(Token![=]) { + input.parse::()?; + let expr_start = input.cursor(); + input.parse::()?; + let expr_end = input.cursor(); + return Err(Error::new_range( + expr_start..expr_end, + "field default value is only supported in structs with named fields", + )); + } + + Ok(Field { + attrs, + vis, + modifiers: FieldModifiers {}, + ident: None, + colon_token: None, + ty, + default: None, + }) + } + } +} + +#[cfg(feature = "printing")] +mod printing { + use crate::data::{Field, FieldsNamed, FieldsUnnamed, Variant}; + use crate::print::TokensOrDefault; + use proc_macro2::TokenStream; + use quote::{ToTokens, TokenStreamExt as _}; + + #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] + impl ToTokens for Variant { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(&self.attrs); + self.ident.to_tokens(tokens); + self.fields.to_tokens(tokens); + if let Some((eq_token, disc)) = &self.discriminant { + eq_token.to_tokens(tokens); + disc.to_tokens(tokens); + } + } + } + + #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] + impl ToTokens for FieldsNamed { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.brace_token.surround(tokens, |tokens| { + self.named.to_tokens(tokens); + }); + } + } + + #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] + impl ToTokens for FieldsUnnamed { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.paren_token.surround(tokens, |tokens| { + self.unnamed.to_tokens(tokens); + }); + } + } + + #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] + impl ToTokens for Field { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(&self.attrs); + self.vis.to_tokens(tokens); + if let Some(ident) = &self.ident { + ident.to_tokens(tokens); + TokensOrDefault(&self.colon_token).to_tokens(tokens); + } + self.ty.to_tokens(tokens); + if let Some((eq_token, default)) = &self.default { + eq_token.to_tokens(tokens); + default.to_tokens(tokens); + } + } + } +} diff --git a/third_party/crates/syn-3.0.5/src/derive.rs b/third_party/crates/syn-3.0.5/src/derive.rs new file mode 100644 index 0000000..573b88f --- /dev/null +++ b/third_party/crates/syn-3.0.5/src/derive.rs @@ -0,0 +1,260 @@ +use crate::attr::Attribute; +use crate::data::{Fields, FieldsNamed, Variant}; +use crate::generics::Generics; +use crate::ident::Ident; +use crate::punctuated::Punctuated; +use crate::restriction::Visibility; +use crate::token; +use alloc::vec::Vec; + +ast_struct! { + /// Data structure sent to a `proc_macro_derive` macro. + #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] + pub struct DeriveInput { + pub attrs: Vec, + pub vis: Visibility, + pub ident: Ident, + pub generics: Generics, + pub data: Data, + } +} + +ast_enum! { + /// The storage of a struct, enum or union data structure. + /// + /// # Syntax tree enum + /// + /// This type is a [syntax tree enum]. + /// + /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums + #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] + pub enum Data { + Struct(DataStruct), + Enum(DataEnum), + Union(DataUnion), + } +} + +ast_struct! { + /// A struct input to a `proc_macro_derive` macro. + #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] + pub struct DataStruct { + pub struct_token: Token![struct], + pub fields: Fields, + pub semi_token: Option, + } +} + +ast_struct! { + /// An enum input to a `proc_macro_derive` macro. + #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] + pub struct DataEnum { + pub enum_token: Token![enum], + pub brace_token: token::Brace, + pub variants: Punctuated, + } +} + +ast_struct! { + /// An untagged union input to a `proc_macro_derive` macro. + #[cfg_attr(docsrs, doc(cfg(feature = "derive")))] + pub struct DataUnion { + pub union_token: Token![union], + pub fields: FieldsNamed, + } +} + +#[cfg(feature = "parsing")] +pub(crate) mod parsing { + use crate::attr::Attribute; + use crate::data::{Fields, FieldsNamed, Variant}; + use crate::derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput}; + use crate::error::Result; + use crate::generics::{Generics, WhereClause}; + use crate::ident::Ident; + use crate::parse::{Parse, ParseStream}; + use crate::punctuated::Punctuated; + use crate::restriction::Visibility; + use crate::token; + + #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] + impl Parse for DeriveInput { + fn parse(input: ParseStream) -> Result { + let attrs = input.call(Attribute::parse_outer)?; + let vis = input.parse::()?; + + let lookahead = input.lookahead1(); + if lookahead.peek(Token![struct]) { + let struct_token = input.parse::()?; + let ident = input.parse::()?; + let generics = input.parse::()?; + let (where_clause, fields, semi) = data_struct(input)?; + Ok(DeriveInput { + attrs, + vis, + ident, + generics: Generics { + where_clause, + ..generics + }, + data: Data::Struct(DataStruct { + struct_token, + fields, + semi_token: semi, + }), + }) + } else if lookahead.peek(Token![enum]) { + let enum_token = input.parse::()?; + let ident = input.parse::()?; + let generics = input.parse::()?; + let (where_clause, brace, variants) = data_enum(input)?; + Ok(DeriveInput { + attrs, + vis, + ident, + generics: Generics { + where_clause, + ..generics + }, + data: Data::Enum(DataEnum { + enum_token, + brace_token: brace, + variants, + }), + }) + } else if lookahead.peek(Token![union]) { + let union_token = input.parse::()?; + let ident = input.parse::()?; + let generics = input.parse::()?; + let (where_clause, fields) = data_union(input)?; + Ok(DeriveInput { + attrs, + vis, + ident, + generics: Generics { + where_clause, + ..generics + }, + data: Data::Union(DataUnion { + union_token, + fields, + }), + }) + } else { + Err(lookahead.error()) + } + } + } + + pub(crate) fn data_struct( + input: ParseStream, + ) -> Result<(Option, Fields, Option)> { + let mut lookahead = input.lookahead1(); + let mut where_clause = None; + if lookahead.peek(Token![where]) { + where_clause = Some(input.parse()?); + lookahead = input.lookahead1(); + } + + if where_clause.is_none() && lookahead.peek(token::Paren) { + let fields = input.parse()?; + + lookahead = input.lookahead1(); + if lookahead.peek(Token![where]) { + where_clause = Some(input.parse()?); + lookahead = input.lookahead1(); + } + + if lookahead.peek(Token![;]) { + let semi = input.parse()?; + Ok((where_clause, Fields::Unnamed(fields), Some(semi))) + } else { + Err(lookahead.error()) + } + } else if lookahead.peek(token::Brace) { + let fields = input.parse()?; + Ok((where_clause, Fields::Named(fields), None)) + } else if lookahead.peek(Token![;]) { + let semi = input.parse()?; + Ok((where_clause, Fields::Unit, Some(semi))) + } else { + Err(lookahead.error()) + } + } + + pub(crate) fn data_enum( + input: ParseStream, + ) -> Result<( + Option, + token::Brace, + Punctuated, + )> { + let where_clause = input.parse()?; + + let content; + let brace = braced!(content in input); + let variants = content.parse_terminated(Variant::parse, Token![,])?; + + Ok((where_clause, brace, variants)) + } + + pub(crate) fn data_union(input: ParseStream) -> Result<(Option, FieldsNamed)> { + let where_clause = input.parse()?; + let fields = input.parse()?; + Ok((where_clause, fields)) + } +} + +#[cfg(feature = "printing")] +mod printing { + use crate::attr::FilterAttrs; + use crate::data::Fields; + use crate::derive::{Data, DeriveInput}; + use crate::print::TokensOrDefault; + use proc_macro2::TokenStream; + use quote::ToTokens; + + #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] + impl ToTokens for DeriveInput { + fn to_tokens(&self, tokens: &mut TokenStream) { + for attr in self.attrs.outer() { + attr.to_tokens(tokens); + } + self.vis.to_tokens(tokens); + match &self.data { + Data::Struct(d) => d.struct_token.to_tokens(tokens), + Data::Enum(d) => d.enum_token.to_tokens(tokens), + Data::Union(d) => d.union_token.to_tokens(tokens), + } + self.ident.to_tokens(tokens); + self.generics.to_tokens(tokens); + match &self.data { + Data::Struct(data) => match &data.fields { + Fields::Named(fields) => { + self.generics.where_clause.to_tokens(tokens); + fields.to_tokens(tokens); + } + Fields::Unnamed(fields) => { + fields.to_tokens(tokens); + self.generics.where_clause.to_tokens(tokens); + TokensOrDefault(&data.semi_token).to_tokens(tokens); + } + Fields::Unit => { + self.generics.where_clause.to_tokens(tokens); + TokensOrDefault(&data.semi_token).to_tokens(tokens); + } + }, + Data::Enum(data) => { + self.generics.where_clause.to_tokens(tokens); + data.brace_token.surround(tokens, |tokens| { + data.variants.to_tokens(tokens); + }); + } + Data::Union(data) => { + self.generics.where_clause.to_tokens(tokens); + data.fields.to_tokens(tokens); + } + } + } + } +} diff --git a/third_party/crates/syn-3.0.5/src/discouraged.rs b/third_party/crates/syn-3.0.5/src/discouraged.rs new file mode 100644 index 0000000..6058480 --- /dev/null +++ b/third_party/crates/syn-3.0.5/src/discouraged.rs @@ -0,0 +1,233 @@ +//! Extensions to the parsing API with niche applicability. + +use crate::buffer::Cursor; +use crate::error::Result; +use crate::parse::{inner_unexpected, ParseBuffer, Unexpected}; +use alloc::rc::Rc; +use core::cell::Cell; +use core::mem; +use proc_macro2::extra::DelimSpan; +use proc_macro2::Delimiter; + +/// Extensions to the `ParseStream` API to support speculative parsing. +pub trait Speculative: private::Sealed { + /// Advance this parse stream to the position of a forked parse stream. + /// + /// This is the opposite operation to [`ParseStream::fork`]. You can fork a + /// parse stream, perform some speculative parsing, then join the original + /// stream to the fork to "commit" the parsing from the fork to the main + /// stream. + /// + /// If you can avoid doing this, you should, as it limits the ability to + /// generate useful errors. That said, it is often the only way to parse + /// syntax of the form `A* B*` for arbitrary syntax `A` and `B`. The problem + /// is that when the fork fails to parse an `A`, it's impossible to tell + /// whether that was because of a syntax error and the user meant to provide + /// an `A`, or that the `A`s are finished and it's time to start parsing + /// `B`s. Use with care. + /// + /// Also note that if `A` is a subset of `B`, `A* B*` can be parsed by + /// parsing `B*` and removing the leading members of `A` from the + /// repetition, bypassing the need to involve the downsides associated with + /// speculative parsing. + /// + /// [`ParseStream::fork`]: ParseBuffer::fork + /// + /// # Example + /// + /// There has been chatter about the possibility of making the colons in the + /// turbofish syntax like `path::to::` no longer required by accepting + /// `path::to` in expression position. Specifically, according to [RFC + /// 2544], [`PathSegment`] parsing should always try to consume a following + /// `<` token as the start of generic arguments, and reset to the `<` if + /// that fails (e.g. the token is acting as a less-than operator). + /// + /// This is the exact kind of parsing behavior which requires the "fork, + /// try, commit" behavior that [`ParseStream::fork`] discourages. With + /// `advance_to`, we can avoid having to parse the speculatively parsed + /// content a second time. + /// + /// This change in behavior can be implemented in syn by replacing just the + /// `Parse` implementation for `PathSegment`: + /// + /// ``` + /// # use syn::ext::IdentExt; + /// use syn::parse::discouraged::Speculative; + /// # use syn::parse::{Parse, ParseStream}; + /// # use syn::{Ident, PathArguments, Result, Token}; + /// + /// pub struct PathSegment { + /// pub ident: Ident, + /// pub arguments: PathArguments, + /// } + /// # + /// # impl From for PathSegment + /// # where + /// # T: Into, + /// # { + /// # fn from(ident: T) -> Self { + /// # PathSegment { + /// # ident: ident.into(), + /// # arguments: PathArguments::None, + /// # } + /// # } + /// # } + /// + /// impl Parse for PathSegment { + /// fn parse(input: ParseStream) -> Result { + /// if input.peek(Token![super]) + /// || input.peek(Token![self]) + /// || input.peek(Token![Self]) + /// || input.peek(Token![crate]) + /// { + /// let ident = input.call(Ident::parse_any)?; + /// return Ok(PathSegment::from(ident)); + /// } + /// + /// let ident = input.parse()?; + /// if input.peek(Token![::]) && input.peek3(Token![<]) { + /// return Ok(PathSegment { + /// ident, + /// arguments: PathArguments::AngleBracketed(input.parse()?), + /// }); + /// } + /// if input.peek(Token![<]) && !input.peek(Token![<=]) { + /// let fork = input.fork(); + /// if let Ok(arguments) = fork.parse() { + /// input.advance_to(&fork); + /// return Ok(PathSegment { + /// ident, + /// arguments: PathArguments::AngleBracketed(arguments), + /// }); + /// } + /// } + /// Ok(PathSegment::from(ident)) + /// } + /// } + /// + /// # syn::parse_str::("a").unwrap(); + /// ``` + /// + /// # Drawbacks + /// + /// The main drawback of this style of speculative parsing is in error + /// presentation. Even if the lookahead is the "correct" parse, the error + /// that is shown is that of the "fallback" parse. To use the same example + /// as the turbofish above, take the following unfinished "turbofish": + /// + /// ```text + /// let _ = f<&'a fn(), for<'a> serde::>(); + /// ``` + /// + /// If this is parsed as generic arguments, we can provide the error message + /// + /// ```text + /// error: expected identifier + /// --> src.rs:L:C + /// | + /// L | let _ = f<&'a fn(), for<'a> serde::>(); + /// | ^ + /// ``` + /// + /// but if parsed using the above speculative parsing, it falls back to + /// assuming that the `<` is a less-than when it fails to parse the generic + /// arguments, and tries to interpret the `&'a` as the start of a labelled + /// loop, resulting in the much less helpful error + /// + /// ```text + /// error: expected `:` + /// --> src.rs:L:C + /// | + /// L | let _ = f<&'a fn(), for<'a> serde::>(); + /// | ^^ + /// ``` + /// + /// This can be mitigated with various heuristics (two examples: show both + /// forks' parse errors, or show the one that consumed more tokens), but + /// when you can control the grammar, sticking to something that can be + /// parsed LL(3) and without the LL(*) speculative parsing this makes + /// possible, displaying reasonable errors becomes much more simple. + /// + /// [RFC 2544]: https://github.com/rust-lang/rfcs/pull/2544 + /// [`PathSegment`]: crate::PathSegment + /// + /// # Performance + /// + /// This method performs a cheap fixed amount of work that does not depend + /// on how far apart the two streams are positioned. + /// + /// # Panics + /// + /// The forked stream in the argument of `advance_to` must have been + /// obtained by forking `self`. Attempting to advance to any other stream + /// will cause a panic. + fn advance_to(&self, fork: &Self); +} + +impl<'a> Speculative for ParseBuffer<'a> { + fn advance_to(&self, fork: &Self) { + if !crate::buffer::same_scope(self.cursor(), fork.cursor()) { + panic!("fork was not derived from the advancing parse stream"); + } + + let (self_unexp, self_sp) = inner_unexpected(self); + let (fork_unexp, fork_sp) = inner_unexpected(fork); + if !Rc::ptr_eq(&self_unexp, &fork_unexp) { + match (fork_sp, self_sp) { + // Unexpected set on the fork, but not on `self`, copy it over. + (Some((span, delimiter)), None) => { + self_unexp.set(Unexpected::Some(span, delimiter)); + } + // Unexpected unset. Use chain to propagate errors from fork. + (None, None) => { + fork_unexp.set(Unexpected::Chain(self_unexp)); + + // Ensure toplevel 'unexpected' tokens from the fork don't + // propagate up the chain by replacing the root `unexpected` + // pointer, only 'unexpected' tokens from existing group + // parsers should propagate. + fork.unexpected + .set(Some(Rc::new(Cell::new(Unexpected::None)))); + } + // Unexpected has been set on `self`. No changes needed. + (_, Some(_)) => {} + } + } + + // See comment on `cell` in the struct definition. + self.cell + .set(unsafe { mem::transmute::>(fork.cursor()) }); + } +} + +/// Extensions to the `ParseStream` API to support manipulating invisible +/// delimiters the same as if they were visible. +pub trait AnyDelimiter: private::Sealed { + /// Returns the delimiter, the span of the delimiter token, and the nested + /// contents for further parsing. + fn parse_any_delimiter(&self) -> Result<(Delimiter, DelimSpan, ParseBuffer)>; +} + +impl<'a> AnyDelimiter for ParseBuffer<'a> { + fn parse_any_delimiter(&self) -> Result<(Delimiter, DelimSpan, ParseBuffer)> { + self.step(|cursor| { + if let Some((content, delimiter, span, rest)) = cursor.any_group() { + let scope = span.close(); + let nested = crate::parse::advance_step_cursor(cursor, content); + let unexpected = crate::parse::get_unexpected(self); + let content = crate::parse::new_parse_buffer(scope, nested, unexpected); + Ok(((delimiter, span, content), rest)) + } else { + Err(cursor.error("expected any delimiter")) + } + }) + } +} + +mod private { + use crate::parse::ParseBuffer; + + pub trait Sealed {} + + impl<'a> Sealed for ParseBuffer<'a> {} +} diff --git a/third_party/crates/syn-3.0.5/src/drops.rs b/third_party/crates/syn-3.0.5/src/drops.rs new file mode 100644 index 0000000..20ab75e --- /dev/null +++ b/third_party/crates/syn-3.0.5/src/drops.rs @@ -0,0 +1,58 @@ +use core::iter; +use core::mem::ManuallyDrop; +use core::ops::{Deref, DerefMut}; +use core::option; +use core::slice; + +#[repr(transparent)] +pub(crate) struct NoDrop(ManuallyDrop); + +impl NoDrop { + pub(crate) fn new(value: T) -> Self + where + T: TrivialDrop, + { + NoDrop(ManuallyDrop::new(value)) + } +} + +impl Deref for NoDrop { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for NoDrop { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +pub(crate) trait TrivialDrop {} + +impl TrivialDrop for iter::Empty {} +impl TrivialDrop for slice::Iter<'_, T> {} +impl TrivialDrop for slice::IterMut<'_, T> {} +impl TrivialDrop for option::IntoIter<&T> {} +impl TrivialDrop for option::IntoIter<&mut T> {} + +#[test] +fn test_needs_drop() { + use core::mem::needs_drop; + + struct NeedsDrop; + + impl Drop for NeedsDrop { + fn drop(&mut self) {} + } + + assert!(needs_drop::()); + + // Test each of the types with a handwritten TrivialDrop impl above. + assert!(!needs_drop::>()); + assert!(!needs_drop::>()); + assert!(!needs_drop::>()); + assert!(!needs_drop::>()); + assert!(!needs_drop::>()); +} diff --git a/third_party/crates/syn-3.0.5/src/error.rs b/third_party/crates/syn-3.0.5/src/error.rs new file mode 100644 index 0000000..16fb7d9 --- /dev/null +++ b/third_party/crates/syn-3.0.5/src/error.rs @@ -0,0 +1,552 @@ +#[cfg(feature = "parsing")] +use crate::buffer::Cursor; +use crate::ext::{PunctExt as _, TokenStreamExt as _}; +use crate::thread::ThreadBound; +#[cfg(feature = "parsing")] +use alloc::format; +use alloc::string::{String, ToString}; +use alloc::vec; +use alloc::vec::Vec; +use core::fmt::{self, Debug, Display}; +#[cfg(feature = "parsing")] +use core::ops::Range; +use core::slice; +use proc_macro2::{ + Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree, +}; +#[cfg(feature = "printing")] +use quote::ToTokens; + +/// The result of a Syn parser. +pub type Result = core::result::Result; + +/// Error returned when a Syn parser cannot parse the input tokens. +/// +/// # Error reporting in proc macros +/// +/// The correct way to report errors back to the compiler from a procedural +/// macro is by emitting an appropriately spanned invocation of +/// [`compile_error!`] in the generated code. This produces a better diagnostic +/// message than simply panicking the macro. +/// +/// [`compile_error!`]: core::compile_error! +/// +/// When parsing macro input, the [`parse_macro_input!`] macro handles the +/// conversion to `compile_error!` automatically. +/// +/// [`parse_macro_input!`]: crate::parse_macro_input! +/// +/// ``` +/// # extern crate proc_macro; +/// # +/// use proc_macro::TokenStream; +/// use syn::parse::{Parse, ParseStream, Result}; +/// use syn::{parse_macro_input, ItemFn}; +/// +/// # const IGNORE: &str = stringify! { +/// #[proc_macro_attribute] +/// # }; +/// pub fn my_attr(args: TokenStream, input: TokenStream) -> TokenStream { +/// let args = parse_macro_input!(args as MyAttrArgs); +/// let input = parse_macro_input!(input as ItemFn); +/// +/// /* ... */ +/// # TokenStream::new() +/// } +/// +/// struct MyAttrArgs { +/// # _k: [(); { stringify! { +/// ... +/// # }; 0 }] +/// } +/// +/// impl Parse for MyAttrArgs { +/// fn parse(input: ParseStream) -> Result { +/// # stringify! { +/// ... +/// # }; +/// # unimplemented!() +/// } +/// } +/// ``` +/// +/// For errors that arise later than the initial parsing stage, the +/// [`.to_compile_error()`] or [`.into_compile_error()`] methods can be used to +/// perform an explicit conversion to `compile_error!`. +/// +/// [`.to_compile_error()`]: Error::to_compile_error +/// [`.into_compile_error()`]: Error::into_compile_error +/// +/// ``` +/// # extern crate proc_macro; +/// # +/// # use proc_macro::TokenStream; +/// # use syn::{parse_macro_input, DeriveInput}; +/// # +/// # const IGNORE: &str = stringify! { +/// #[proc_macro_derive(MyDerive)] +/// # }; +/// pub fn my_derive(input: TokenStream) -> TokenStream { +/// let input = parse_macro_input!(input as DeriveInput); +/// +/// // fn(DeriveInput) -> syn::Result +/// expand::my_derive(input) +/// .unwrap_or_else(syn::Error::into_compile_error) +/// .into() +/// } +/// # +/// # mod expand { +/// # use proc_macro2::TokenStream; +/// # use syn::{DeriveInput, Result}; +/// # +/// # pub fn my_derive(input: DeriveInput) -> Result { +/// # unimplemented!() +/// # } +/// # } +/// ``` +pub struct Error { + messages: Vec, +} + +struct ErrorMessage { + // Span is implemented as an index into a thread-local interner to keep the + // size small. It is not safe to access from a different thread. We want + // errors to be Send and Sync to play nicely with ecosystem crates for error + // handling, so pin the span we're given to its original thread and assume + // it is Span::call_site if accessed from any other thread. + span: ThreadBound, + message: String, +} + +// Cannot use core::ops::Range because that does not implement Copy, +// whereas ThreadBound requires a Copy impl as a way to ensure no Drop impls +// are involved. +struct SpanRange { + start: Span, + end: Span, +} + +#[cfg(test)] +struct _Test +where + Error: Send + Sync; + +impl Error { + /// Usually the [`ParseStream::error`] method will be used instead, which + /// automatically uses the correct span from the current position of the + /// parse stream. + /// + /// Use `Error::new` when the error needs to be triggered on some span other + /// than where the parse stream is currently positioned. + /// + /// [`ParseStream::error`]: crate::parse::ParseBuffer::error + /// + /// # Example + /// + /// ``` + /// use syn::{Error, Ident, LitStr, Result, Token}; + /// use syn::parse::ParseStream; + /// + /// // Parses input that looks like `name = "string"` where the key must be + /// // the identifier `name` and the value may be any string literal. + /// // Returns the string literal. + /// fn parse_name(input: ParseStream) -> Result { + /// let name_token: Ident = input.parse()?; + /// if name_token != "name" { + /// // Trigger an error not on the current position of the stream, + /// // but on the position of the unexpected identifier. + /// return Err(Error::new(name_token.span(), "expected `name`")); + /// } + /// input.parse::()?; + /// let s: LitStr = input.parse()?; + /// Ok(s) + /// } + /// ``` + pub fn new(span: Span, message: impl Display) -> Self { + return new(span, message.to_string()); + + fn new(span: Span, message: String) -> Error { + Error { + messages: vec![ErrorMessage { + span: ThreadBound::new(SpanRange { + start: span, + end: span, + }), + message, + }], + } + } + } + + /// Creates an error with the specified message spanning the given syntax + /// tree node. + /// + /// Unlike the `Error::new` constructor, this constructor takes an argument + /// `tokens` which is a syntax tree node. This allows the resulting `Error` + /// to attempt to span all tokens inside of `tokens`. While you would + /// typically be able to use the `Spanned` trait with the above `Error::new` + /// constructor, implementation limitations today mean that + /// `Error::new_spanned` may provide a higher-quality error message on + /// stable Rust. + /// + /// When in doubt it's recommended to stick to `Error::new` (or + /// `ParseStream::error`)! + #[cfg(feature = "printing")] + #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] + pub fn new_spanned(tokens: impl ToTokens, message: impl Display) -> Self { + return new_spanned(tokens.into_token_stream(), message.to_string()); + + fn new_spanned(tokens: TokenStream, message: String) -> Error { + let mut iter = tokens.into_iter(); + let start = iter.next().map_or_else(Span::call_site, |t| t.span()); + let end = iter.last().map_or(start, |t| t.span()); + Error { + messages: vec![ErrorMessage { + span: ThreadBound::new(SpanRange { start, end }), + message, + }], + } + } + } + + /// Creates an error spanning the given cursor range. + /// + /// # Example + /// + /// This parses a sequence of '+'-separated lifetimes and types like + /// `Vec + dyn Display + 'static`, at least one of which must be a type. + /// + /// ``` + /// use syn::{Lifetime, Token, Type}; + /// use syn::parse::{Error, ParseStream, Result}; + /// + /// enum Thing { + /// Lifetime(Lifetime), + /// Type(Type), + /// } + /// + /// fn parse_things(input: ParseStream) -> Result> { + /// let things_begin = input.cursor(); + /// let things_end; + /// let mut things = Vec::new(); + /// let mut has_type = false; + /// loop { + /// if input.peek(Lifetime) { + /// let lifetime: Lifetime = input.parse()?; + /// things.push(Thing::Lifetime(lifetime)); + /// } else { + /// let ty = input.call(Type::without_plus)?; + /// things.push(Thing::Type(ty)); + /// has_type = true; + /// } + /// let plus_token: Option = input.parse()?; + /// if plus_token.is_none() { + /// things_end = input.cursor(); + /// break; + /// } + /// } + /// + /// if has_type { + /// Ok(things) + /// } else { + /// let msg = "things must not be all lifetimes, at least one type is required"; + /// Err(Error::new_range(things_begin..things_end, msg)) + /// } + /// } + /// ``` + /// + /// ```text + /// error: things must not be all lifetimes, at least one type is required + /// --> example.rs:4:23 + /// | + /// 4 | example!(THINGS = 'a + 'b, ...); + /// | ^^^^^^^ + /// ``` + #[cfg(feature = "parsing")] + #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] + pub fn new_range<'a>(span: impl Into>>, message: impl Display) -> Self { + return new_range(span.into(), message.to_string()); + + fn new_range(span: Range, message: String) -> Error { + assert!(crate::buffer::same_buffer(span.start, span.end)); + assert!(span.start <= span.end); + Error { + messages: vec![ErrorMessage { + span: ThreadBound::new(SpanRange { + start: span.start.span(), + end: if span.start == span.end { + span.end.span() + } else { + span.end.prev_span() + }, + }), + message, + }], + } + } + } + + /// The source location of the error. + /// + /// Spans are not thread-safe so this function returns `Span::call_site()` + /// if called from a different thread than the one on which the `Error` was + /// originally created. + pub fn span(&self) -> Span { + let SpanRange { start, end } = match self.messages[0].span.get() { + Some(span) => *span, + None => return Span::call_site(), + }; + start.join(end).unwrap_or(start) + } + + /// Render the error as an invocation of [`compile_error!`]. + /// + /// The [`parse_macro_input!`] macro provides a convenient way to invoke + /// this method correctly in a procedural macro. + /// + /// [`compile_error!`]: core::compile_error! + /// [`parse_macro_input!`]: crate::parse_macro_input! + pub fn to_compile_error(&self) -> TokenStream { + let mut tokens = TokenStream::new(); + for msg in &self.messages { + ErrorMessage::to_compile_error(msg, &mut tokens); + } + tokens + } + + /// Render the error as an invocation of [`compile_error!`]. + /// + /// [`compile_error!`]: core::compile_error! + /// + /// # Example + /// + /// ``` + /// # extern crate proc_macro; + /// # + /// use proc_macro::TokenStream; + /// use syn::{parse_macro_input, DeriveInput, Error}; + /// + /// # const _: &str = stringify! { + /// #[proc_macro_derive(MyTrait)] + /// # }; + /// pub fn derive_my_trait(input: TokenStream) -> TokenStream { + /// let input = parse_macro_input!(input as DeriveInput); + /// my_trait::expand(input) + /// .unwrap_or_else(Error::into_compile_error) + /// .into() + /// } + /// + /// mod my_trait { + /// use proc_macro2::TokenStream; + /// use syn::{DeriveInput, Result}; + /// + /// pub(crate) fn expand(input: DeriveInput) -> Result { + /// /* ... */ + /// # unimplemented!() + /// } + /// } + /// ``` + pub fn into_compile_error(self) -> TokenStream { + self.to_compile_error() + } + + /// Add another error message to self such that when `to_compile_error()` is + /// called, both errors will be emitted together. + pub fn combine(&mut self, another: Error) { + self.messages.extend(another.messages); + } +} + +impl ErrorMessage { + fn to_compile_error(&self, tokens: &mut TokenStream) { + let (start, end) = match self.span.get() { + Some(range) => (range.start, range.end), + None => (Span::call_site(), Span::call_site()), + }; + + // ::core::compile_error!($message) + tokens.append(TokenTree::Punct(Punct::new_spanned( + ':', + Spacing::Joint, + start, + ))); + tokens.append(TokenTree::Punct(Punct::new_spanned( + ':', + Spacing::Alone, + start, + ))); + tokens.append(TokenTree::Ident(Ident::new("core", start))); + tokens.append(TokenTree::Punct(Punct::new_spanned( + ':', + Spacing::Joint, + start, + ))); + tokens.append(TokenTree::Punct(Punct::new_spanned( + ':', + Spacing::Alone, + start, + ))); + tokens.append(TokenTree::Ident(Ident::new("compile_error", start))); + tokens.append(TokenTree::Punct(Punct::new_spanned( + '!', + Spacing::Alone, + start, + ))); + tokens.append(TokenTree::Group({ + let mut group = Group::new( + Delimiter::Brace, + TokenStream::from({ + let mut string = Literal::string(&self.message); + string.set_span(end); + TokenTree::Literal(string) + }), + ); + group.set_span(end); + group + })); + } +} + +#[cfg(feature = "parsing")] +pub(crate) fn new_at(scope: Span, cursor: Cursor, message: T) -> Error { + if cursor.eof() { + Error::new(scope, format!("unexpected end of input, {}", message)) + } else { + let span = crate::buffer::open_span_of_group(cursor); + Error::new(span, message) + } +} + +#[cfg(all(feature = "parsing", any(feature = "full", feature = "derive")))] +pub(crate) fn new2(start: Span, end: Span, message: T) -> Error { + return new2(start, end, message.to_string()); + + fn new2(start: Span, end: Span, message: String) -> Error { + Error { + messages: vec![ErrorMessage { + span: ThreadBound::new(SpanRange { start, end }), + message, + }], + } + } +} + +impl Debug for Error { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + if self.messages.len() == 1 { + formatter + .debug_tuple("Error") + .field(&self.messages[0]) + .finish() + } else { + formatter + .debug_tuple("Error") + .field(&self.messages) + .finish() + } + } +} + +impl Debug for ErrorMessage { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.message, formatter) + } +} + +impl Display for Error { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(&self.messages[0].message) + } +} + +impl Clone for Error { + fn clone(&self) -> Self { + Error { + messages: self.messages.clone(), + } + } +} + +impl Clone for ErrorMessage { + fn clone(&self) -> Self { + ErrorMessage { + span: self.span, + message: self.message.clone(), + } + } +} + +impl Clone for SpanRange { + fn clone(&self) -> Self { + *self + } +} + +impl Copy for SpanRange {} + +// TODO: impl core::error::Error (requires Rust 1.81+) +impl std::error::Error for Error {} + +impl From for Error { + fn from(err: LexError) -> Self { + Error::new(err.span(), err) + } +} + +impl IntoIterator for Error { + type Item = Error; + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + IntoIter { + messages: self.messages.into_iter(), + } + } +} + +pub struct IntoIter { + messages: vec::IntoIter, +} + +impl Iterator for IntoIter { + type Item = Error; + + fn next(&mut self) -> Option { + Some(Error { + messages: vec![self.messages.next()?], + }) + } +} + +impl<'a> IntoIterator for &'a Error { + type Item = Error; + type IntoIter = Iter<'a>; + + fn into_iter(self) -> Self::IntoIter { + Iter { + messages: self.messages.iter(), + } + } +} + +pub struct Iter<'a> { + messages: slice::Iter<'a, ErrorMessage>, +} + +impl<'a> Iterator for Iter<'a> { + type Item = Error; + + fn next(&mut self) -> Option { + Some(Error { + messages: vec![self.messages.next()?.clone()], + }) + } +} + +impl Extend for Error { + fn extend>(&mut self, iter: T) { + for err in iter { + self.combine(err); + } + } +} diff --git a/third_party/crates/syn-3.0.5/src/export.rs b/third_party/crates/syn-3.0.5/src/export.rs new file mode 100644 index 0000000..eca67f6 --- /dev/null +++ b/third_party/crates/syn-3.0.5/src/export.rs @@ -0,0 +1,73 @@ +#[doc(hidden)] +pub use core::clone::Clone; +#[doc(hidden)] +pub use core::cmp::{Eq, PartialEq}; +#[doc(hidden)] +pub use core::concat; +#[doc(hidden)] +pub use core::default::Default; +#[doc(hidden)] +pub use core::fmt::Debug; +#[doc(hidden)] +pub use core::hash::{Hash, Hasher}; +#[doc(hidden)] +pub use core::marker::Copy; +#[doc(hidden)] +pub use core::option::Option::{None, Some}; +#[doc(hidden)] +pub use core::result::Result::{Err, Ok}; +#[doc(hidden)] +pub use core::stringify; + +#[doc(hidden)] +pub type Formatter<'a> = core::fmt::Formatter<'a>; +#[doc(hidden)] +pub type FmtResult = core::fmt::Result; + +#[doc(hidden)] +pub type bool = core::primitive::bool; +#[doc(hidden)] +pub type str = core::primitive::str; + +#[cfg(feature = "printing")] +#[doc(hidden)] +pub use quote; + +#[doc(hidden)] +pub type Span = proc_macro2::Span; +#[doc(hidden)] +pub type TokenStream2 = proc_macro2::TokenStream; + +#[cfg(feature = "parsing")] +#[doc(hidden)] +pub use crate::group::{parse_braces, parse_brackets, parse_parens}; + +#[doc(hidden)] +pub use crate::span::IntoSpans; + +#[cfg(all(feature = "parsing", feature = "printing"))] +#[doc(hidden)] +pub use crate::parse_quote::parse as parse_quote; + +#[cfg(feature = "parsing")] +#[doc(hidden)] +pub use crate::token::parsing::{peek_punct, punct as parse_punct}; + +#[cfg(feature = "printing")] +#[doc(hidden)] +pub use crate::token::printing::punct as print_punct; + +#[cfg(feature = "parsing")] +#[doc(hidden)] +pub use crate::token::private::CustomToken; + +#[cfg(feature = "proc-macro")] +#[doc(hidden)] +pub type TokenStream = proc_macro::TokenStream; + +#[cfg(feature = "printing")] +#[doc(hidden)] +pub use quote::{ToTokens, TokenStreamExt}; + +#[doc(hidden)] +pub struct private(pub(crate) ()); diff --git a/third_party/crates/syn-3.0.5/src/expr.rs b/third_party/crates/syn-3.0.5/src/expr.rs new file mode 100644 index 0000000..c9437d5 --- /dev/null +++ b/third_party/crates/syn-3.0.5/src/expr.rs @@ -0,0 +1,4237 @@ +use crate::attr::Attribute; +#[cfg(all(feature = "parsing", feature = "full"))] +use crate::error::Result; +#[cfg(feature = "parsing")] +use crate::ext::IdentExt as _; +#[cfg(feature = "full")] +use crate::generics::BoundLifetimes; +use crate::ident::Ident; +#[cfg(any(feature = "parsing", feature = "full"))] +use crate::lifetime::Lifetime; +use crate::lit::Lit; +use crate::mac::Macro; +use crate::op::{BinOp, UnOp}; +#[cfg(feature = "parsing")] +use crate::parse::ParseStream; +#[cfg(feature = "full")] +use crate::pat::Pat; +use crate::path::{AngleBracketedGenericArguments, Path, QSelf}; +use crate::punctuated::Punctuated; +#[cfg(feature = "full")] +use crate::stmt::Block; +use crate::token; +use crate::ty::Type; +#[cfg(feature = "full")] +use crate::ty::{PointerMutability, ReturnType}; +use alloc::boxed::Box; +use alloc::vec::Vec; +#[cfg(feature = "printing")] +use core::fmt::{self, Display}; +use core::hash::{Hash, Hasher}; +#[cfg(all(feature = "parsing", feature = "full"))] +use core::mem; +use proc_macro2::{Span, TokenStream}; +#[cfg(feature = "printing")] +use quote::IdentFragment; + +ast_enum_of_structs! { + /// A Rust expression. + /// + /// *This type is available only if Syn is built with the `"derive"` or `"full"` + /// feature, but most of the variants are not available unless "full" is enabled.* + /// + /// # Syntax tree enums + /// + /// This type is a syntax tree enum. In Syn this and other syntax tree enums + /// are designed to be traversed using the following rebinding idiom. + /// + /// ``` + /// # use syn::Expr; + /// # + /// # fn example(expr: Expr) { + /// # const IGNORE: &str = stringify! { + /// let expr: Expr = /* ... */; + /// # }; + /// match expr { + /// Expr::MethodCall(expr) => { + /// /* ... */ + /// } + /// Expr::Cast(expr) => { + /// /* ... */ + /// } + /// Expr::If(expr) => { + /// /* ... */ + /// } + /// + /// /* ... */ + /// # _ => {} + /// # } + /// # } + /// ``` + /// + /// We begin with a variable `expr` of type `Expr` that has no fields + /// (because it is an enum), and by matching on it and rebinding a variable + /// with the same name `expr` we effectively imbue our variable with all of + /// the data fields provided by the variant that it turned out to be. So for + /// example above if we ended up in the `MethodCall` case then we get to use + /// `expr.receiver`, `expr.args` etc; if we ended up in the `If` case we get + /// to use `expr.cond`, `expr.then_branch`, `expr.else_branch`. + /// + /// This approach avoids repeating the variant names twice on every line. + /// + /// ``` + /// # use syn::{Expr, ExprMethodCall}; + /// # + /// # fn example(expr: Expr) { + /// // Repetitive; recommend not doing this. + /// match expr { + /// Expr::MethodCall(ExprMethodCall { method, args, .. }) => { + /// # } + /// # _ => {} + /// # } + /// # } + /// ``` + /// + /// In general, the name to which a syntax tree enum variant is bound should + /// be a suitable name for the complete syntax tree enum type. + /// + /// ``` + /// # use syn::{Expr, ExprField}; + /// # + /// # fn example(discriminant: ExprField) { + /// // Binding is called `base` which is the name I would use if I were + /// // assigning `*discriminant.base` without an `if let`. + /// if let Expr::Tuple(base) = *discriminant.base { + /// # } + /// # } + /// ``` + /// + /// A sign that you may not be choosing the right variable names is if you + /// see names getting repeated in your code, like accessing + /// `receiver.receiver` or `pat.pat` or `cond.cond`. + /// + /// # Exhaustive matching + /// + /// For testing exhaustiveness in downstream code, use the following idiom: + /// + /// ``` + /// # use syn::Expr; + /// # + /// # fn example(expr: Expr) { + /// match expr { + /// #![cfg_attr(test, deny(non_exhaustive_omitted_patterns))] + /// + /// Expr::Array(expr) => { /*...*/ } + /// Expr::Assign(expr) => { /*...*/ } + #[cfg_attr(not(doctest), doc = " ...")] + /// Expr::Yield(expr) => { /*...*/ } + /// + /// _ => { /* some sane fallback */ } + /// } + /// # } + /// ``` + /// + /// This way we fail your tests but don't break your library when adding a + /// variant. You will be notified by a test failure when a variant is added, + /// so that you can add code to handle it, but your library will continue to + /// compile and work for downstream users in the interim. + #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] + #[non_exhaustive] + pub enum Expr { + /// A slice literal expression: `[a, b, c, d]`. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + Array(ExprArray), + + /// An assignment expression: `a = compute()`. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + Assign(ExprAssign), + + /// An async block: `async { ... }`. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + Async(ExprAsync), + + /// An await expression: `fut.await`. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + Await(ExprAwait), + + /// A binary operation: `a + b`, `a += b`. + Binary(ExprBinary), + + /// A braced block: `{ ... }`. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + Block(ExprBlock), + + /// A `break`, with an optional label to break and an optional + /// expression. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + Break(ExprBreak), + + /// A function call expression: `invoke(a, b)`. + Call(ExprCall), + + /// A cast expression: `foo as f64`. + Cast(ExprCast), + + /// A closure expression: `|a, b| a + b`. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + Closure(ExprClosure), + + /// A const block: `const { ... }`. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + Const(ExprConst), + + /// A `continue`, with an optional label. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + Continue(ExprContinue), + + /// Access of a named struct field (`obj.k`) or unnamed tuple struct + /// field (`obj.0`). + Field(ExprField), + + /// A for loop: `for pat in expr { ... }`. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + ForLoop(ExprForLoop), + + /// An expression contained within invisible delimiters. + /// + /// This variant is important for faithfully representing the precedence + /// of expressions and is related to `None`-delimited spans in a + /// `TokenStream`. + Group(ExprGroup), + + /// An `if` expression with an optional `else` block: `if expr { ... } + /// else { ... }`. + /// + /// The `else` branch expression may only be an `If` or `Block` + /// expression, not any of the other types of expression. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + If(ExprIf), + + /// A square bracketed indexing expression: `vector[2]`. + Index(ExprIndex), + + /// The inferred value of a const generic argument, denoted `_`. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + Infer(ExprInfer), + + /// A pattern application: `let Some(x) = opt`. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + Let(ExprLet), + + /// A literal in place of an expression: `1`, `"foo"`. + Lit(ExprLit), + + /// Conditionless loop: `loop { ... }`. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + Loop(ExprLoop), + + /// A macro invocation expression: `format!("{}", q)`. + Macro(ExprMacro), + + /// A `match` expression: `match n { Some(n) => {}, None => {} }`. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + Match(ExprMatch), + + /// A method call expression: `x.foo::(a, b)`. + MethodCall(ExprMethodCall), + + /// A parenthesized expression: `(a + b)`. + Paren(ExprParen), + + /// A path like `core::mem::replace` possibly containing generic + /// parameters and a qualified self-type. + /// + /// A plain identifier like `x` is a path of length 1. + Path(ExprPath), + + /// A range expression: `1..2`, `1..`, `..2`, `1..=2`, `..=2`. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + Range(ExprRange), + + /// Address-of operation: `&raw const place` or `&raw mut place`. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + RawAddr(ExprRawAddr), + + /// A referencing operation: `&a` or `&mut a`. + Reference(ExprReference), + + /// An array literal constructed from one repeated element: `[0u8; N]`. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + Repeat(ExprRepeat), + + /// A `return`, with an optional value to be returned. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + Return(ExprReturn), + + /// A struct literal expression: `Point { x: 1, y: 1 }`. + /// + /// The `rest` provides the value of the remaining fields as in `S { a: + /// 1, b: 1, ..rest }`. + Struct(ExprStruct), + + /// A try-expression: `expr?`. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + Try(ExprTry), + + /// A try block: `try { ... }`. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + TryBlock(ExprTryBlock), + + /// A tuple expression: `(a, b, c, d)`. + Tuple(ExprTuple), + + /// A unary operation: `!x`, `*x`, `-x`. + Unary(ExprUnary), + + /// An unsafe block: `unsafe { ... }`. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + Unsafe(ExprUnsafe), + + /// Tokens in expression position not interpreted by Syn. + /// + ///
+ /// + /// Important: see [Compatibility notes][crate#verbatim-variants]. + /// + ///
+ Verbatim(TokenStream), + + /// A while loop: `while expr { ... }`. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + While(ExprWhile), + + /// A yield expression: `yield expr`. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + Yield(ExprYield), + } +} + +ast_struct! { + /// A slice literal expression: `[a, b, c, d]`. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + pub struct ExprArray #full { + pub attrs: Vec, + pub bracket_token: token::Bracket, + pub elems: Punctuated, + } +} + +ast_struct! { + /// An assignment expression: `a = compute()`. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + pub struct ExprAssign #full { + pub attrs: Vec, + pub left: Box, + pub eq_token: Token![=], + pub right: Box, + } +} + +ast_struct! { + /// An async block: `async { ... }`. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + pub struct ExprAsync #full { + pub attrs: Vec, + pub async_token: Token![async], + pub capture: Option, + /// (Non-exhaustive) Additional optional information about a block. + pub modifiers: BlockModifiers, + pub block: Block, + } +} + +ast_struct! { + /// An await expression: `fut.await`. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + pub struct ExprAwait #full { + pub attrs: Vec, + pub base: Box, + pub dot_token: Token![.], + pub await_token: Token![await], + } +} + +ast_struct! { + /// A binary operation: `a + b`, `a += b`. + #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] + pub struct ExprBinary { + pub attrs: Vec, + pub left: Box, + pub op: BinOp, + pub right: Box, + } +} + +ast_struct! { + /// A braced block: `{ ... }`. + #[cfg_attr(docsrs, doc(cfg(feature = "full")))] + pub struct ExprBlock #full { + pub attrs: Vec, + pub label: Option
+ +Click to show Cargo.toml. +Run this code in the playground. + + +```toml +[dependencies] + +# The core APIs, including the Serialize and Deserialize traits. Always +# required when using Serde. The "derive" feature is only required when +# using #[derive(Serialize, Deserialize)] to make Serde work with structs +# and enums defined in your crate. +serde = { version = "1.0", features = ["derive"] } + +# Each data format lives in its own crate; the sample code below uses JSON +# but you may be using a different one. +serde_json = "1.0" +``` + +