summaryrefslogtreecommitdiffstats
path: root/third_party/rust/serde_with_macros
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/serde_with_macros')
-rw-r--r--third_party/rust/serde_with_macros/.cargo-checksum.json1
-rw-r--r--third_party/rust/serde_with_macros/CHANGELOG.md296
-rw-r--r--third_party/rust/serde_with_macros/Cargo.toml105
-rw-r--r--third_party/rust/serde_with_macros/LICENSE-APACHE201
-rw-r--r--third_party/rust/serde_with_macros/LICENSE-MIT25
-rw-r--r--third_party/rust/serde_with_macros/README.md212
-rw-r--r--third_party/rust/serde_with_macros/src/apply.rs313
-rw-r--r--third_party/rust/serde_with_macros/src/lib.rs1318
-rw-r--r--third_party/rust/serde_with_macros/src/utils.rs77
-rw-r--r--third_party/rust/serde_with_macros/tests/apply.rs247
-rw-r--r--third_party/rust/serde_with_macros/tests/compiler-messages.rs9
-rw-r--r--third_party/rust/serde_with_macros/tests/serde_as_issue_267.rs9
-rw-r--r--third_party/rust/serde_with_macros/tests/serde_as_issue_538.rs30
-rw-r--r--third_party/rust/serde_with_macros/tests/skip_serializing_null.rs149
-rw-r--r--third_party/rust/serde_with_macros/tests/version_numbers.rs21
15 files changed, 3013 insertions, 0 deletions
diff --git a/third_party/rust/serde_with_macros/.cargo-checksum.json b/third_party/rust/serde_with_macros/.cargo-checksum.json
new file mode 100644
index 0000000000..5637cb9953
--- /dev/null
+++ b/third_party/rust/serde_with_macros/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CHANGELOG.md":"63e4a849e730096c2c3817b3fe800abced26280c3a5f82021def0d927abdcce5","Cargo.toml":"61849c1007b396ccea0f8e64980c2a808df6b0cdfe25f2817b1246ee0e089ebc","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7576269ea71f767b99297934c0b2367532690f8c4badc695edf8e04ab6a1e545","README.md":"e678bfd60449ac137d780b29fcae8d3ecb706f43e8060369f7269151a0844c1a","src/apply.rs":"027092a97792cd40d5caf8919241009d352f20a064916c0410e0b669b6d6ffe2","src/lib.rs":"267d3ecd05f1009737b7810526b9a3325fb28190ce54f3602980f6e57b9a2128","src/utils.rs":"89588e77aff8d902cb733081453d1aef4a3566b378ec4e78b2f5c5a17ca83db2","tests/apply.rs":"7875d812f2a0342f2f7cbd9dfc0c5d2ca9a1d39290b79f727b454251c521454e","tests/compiler-messages.rs":"8dca4660b6d84d5c6a401a136b66f1fd98b2cccbab4a32f1c35590d21ce67970","tests/serde_as_issue_267.rs":"caaa744bd0fa854d58f8bd28214b7394e8bdd09cadc864a5d87db0c6b1ab491d","tests/serde_as_issue_538.rs":"50b131baf53812ae458b31b42f3b440d0b2508803f83d94204f7bdf600400c27","tests/skip_serializing_null.rs":"779f5478ed2ba80c312ae9e88c9ea0d0e53ebfd13ebb8c1d42f866e619521404","tests/version_numbers.rs":"63386f8e98a17ab28c15c21b1cb5357b351bee9c513b7b1693c9d9bb482cf15a"},"package":"edc7d5d3932fb12ce722ee5e64dd38c504efba37567f0c402f6ca728c3b8b070"} \ No newline at end of file
diff --git a/third_party/rust/serde_with_macros/CHANGELOG.md b/third_party/rust/serde_with_macros/CHANGELOG.md
new file mode 100644
index 0000000000..07ed2102e9
--- /dev/null
+++ b/third_party/rust/serde_with_macros/CHANGELOG.md
@@ -0,0 +1,296 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+
+## [3.0.0] - 2023-05-01
+
+No changes.
+
+## [2.3.3] - 2023-04-27
+
+### Changed
+
+* Update `syn` to v2 and `darling` to v0.20 (#578)
+ Update proc-macro dependencies.
+ This change should have no impact on users, but now uses the same dependency as `serde_derive`.
+
+## [2.3.2] - 2023-04-05
+
+No changes.
+
+## [2.3.1] - 2023-03-10
+
+No changes.
+
+## [2.3.0] - 2023-03-09
+
+No changes.
+
+## [2.2.0] - 2023-01-09
+
+### Fixed
+
+* `serde_with::apply` had an issue matching types when invisible token groups where in use (#538)
+ The token groups can stem from macro_rules expansion, but should be treated mostly transparent.
+ The old code required a group to match a group, while now groups are silently removed when checking for type patterns.
+
+## [2.1.0] - 2022-11-16
+
+### Added
+
+* Add new `apply` attribute to simplify repetitive attributes over many fields.
+ Multiple rules and multiple attributes can be provided each.
+
+ ```rust
+ #[serde_with::apply(
+ Option => #[serde(default)] #[serde(skip_serializing_if = "Option::is_none")],
+ Option<bool> => #[serde(rename = "bool")],
+ )]
+ #[derive(serde::Serialize)]
+ struct Data {
+ a: Option<String>,
+ b: Option<u64>,
+ c: Option<String>,
+ d: Option<bool>,
+ }
+ ```
+
+ The `apply` attribute will expand into this, applying the attributs to the matching fields:
+
+ ```rust
+ #[derive(serde::Serialize)]
+ struct Data {
+ #[serde(default)]
+ #[serde(skip_serializing_if = "Option::is_none")]
+ a: Option<String>,
+ #[serde(default)]
+ #[serde(skip_serializing_if = "Option::is_none")]
+ b: Option<u64>,
+ #[serde(default)]
+ #[serde(skip_serializing_if = "Option::is_none")]
+ c: Option<String>,
+ #[serde(default)]
+ #[serde(skip_serializing_if = "Option::is_none")]
+ #[serde(rename = "bool")]
+ d: Option<bool>,
+ }
+ ```
+
+ The attribute supports field matching using many rules, such as `_` to apply to all fields and partial generics like `Option` to match any `Option` be it `Option<String>`, `Option<bool>`, or `Option<T>`.
+
+### Fixed
+
+* The derive macros `SerializeDisplay` and `DeserializeFromStr` now take better care not to use conflicting names for generic values. (#526)
+ All used generics now start with `__` to make conflicts with manually written code unlikely.
+
+ Thanks to @Elrendio for submitting a PR fixing the issue.
+
+## [2.0.1] - 2022-09-09
+
+### Changed
+
+* Warn if `serde_as` is used on an enum variant.
+ Attributes on enum variants were never supported.
+ But `#[serde(with = "...")]` can be added on variants, such that some confusion can occur when migration ([#499](https://github.com/jonasbb/serde_with/issues/499)).
+
+## [2.0.0] - 2022-07-17
+
+No changes compared to v2.0.0-rc.0.
+
+### Changed
+
+* Make `#[serde_as]` behave more intuitive on `Option<T>` fields.
+
+ The `#[serde_as]` macro now detects if a `#[serde_as(as = "Option<S>")]` is used on a field of type `Option<T>` and applies `#[serde(default)]` to the field.
+ This restores the ability to deserialize with missing fields and fixes a common annoyance (#183, #185, #311, #417).
+ This is a breaking change, since now deserialization will pass where it did not before and this might be undesired.
+
+ The `Option` field and transformation are detected by directly matching on the type name.
+ These variants are detected as `Option`.
+ * `Option`
+ * `std::option::Option`, with or without leading `::`
+ * `core::option::Option`, with or without leading `::`
+
+ If an existing `default` attribute is detected, the attribute is not applied again.
+ This behavior can be supressed by using `#[serde_as(no_default)]` or `#[serde_as(as = "Option<S>", no_default)]`.
+
+### Fixed
+
+* Make the documentation clearer by stating that the `#[serde_as]` and `#[skip_serializing_none]` attributes must always be placed before `#[derive]`.
+
+## [2.0.0-rc.0] - 2022-06-29
+
+### Changed
+
+* Make `#[serde_as]` behave more intuitive on `Option<T>` fields.
+
+ The `#[serde_as]` macro now detects if a `#[serde_as(as = "Option<S>")]` is used on a field of type `Option<T>` and applies `#[serde(default)]` to the field.
+ This restores the ability to deserialize with missing fields and fixes a common annoyance (#183, #185, #311, #417).
+ This is a breaking change, since now deserialization will pass where it did not before and this might be undesired.
+
+ The `Option` field and transformation are detected by directly matching on the type name.
+ These variants are detected as `Option`.
+ * `Option`
+ * `std::option::Option`, with or without leading `::`
+ * `core::option::Option`, with or without leading `::`
+
+ If an existing `default` attribute is detected, the attribute is not applied again.
+ This behavior can be supressed by using `#[serde_as(no_default)]` or `#[serde_as(as = "Option<S>", no_default)]`.
+
+### Fixed
+
+* Make the documentation clearer by stating that the `#[serde_as]` and `#[skip_serializing_none]` attributes must always be placed before `#[derive]`.
+
+## [1.5.2] - 2022-04-07
+
+### Fixed
+
+* Account for generics when deriving implementations with `SerializeDisplay` and `DeserializeFromStr` #413
+* Provide better error messages when parsing types fails #423
+
+## [1.5.1] - 2021-10-18
+
+### Added
+
+* The minimal supported Rust version (MSRV) is now specified in the `Cargo.toml` via the `rust-version` field. The field is supported in Rust 1.56 and has no effect on versions before.
+
+ More details: https://doc.rust-lang.org/nightly/cargo/reference/manifest.html#the-rust-version-field
+
+## [1.5.0] - 2021-09-04
+
+### Added
+
+* Add the attribute `#[serde(borrow)]` on a field if `serde_as` is used in combination with the `BorrowCow` type.
+
+## [1.4.2] - 2021-06-07
+
+### Fixed
+
+* Describe how the `serde_as` macro works on a high level.
+* The derive macros `SerializeDisplay` and `DeserializeFromStr` were relying on the prelude where they were used.
+ Properly name all types and traits required for the expanded code to work.
+ The tests were improved to be better able to catch such problems.
+
+## [1.4.2] - 2021-02-16
+
+### Fixed
+
+* Fix compiling when having a struct field without the `serde_as` annotation.
+ This broke in 1.4.0 [#267](https://github.com/jonasbb/serde_with/issues/267)
+
+## [1.4.0] - 2021-02-15
+
+### Changed
+
+* Improve error messages when `#[serde_as(..)]` is misused as a field attribute.
+ Thanks to @Lehona for reporting the bug in #233.
+* Internal cleanup for assembling and parsing attributes during `serde_as` processing.
+* Change processing on `#[serde_as(...)]` attributes on fields.
+
+ The attributes will no longer be stripped during proc-macro processing.
+ Instead, a private derive macro is applied to the struct/enum which captures them and makes them inert, thus allowing compilation.
+
+ This should have no effect on the generated code and on the runtime behavior.
+ It eases integration of third-party crates with `serde_with`, since they can now process the `#[serde_as(...)]` field attributes reliably.
+ Before this was impossible for derive macros and lead to awkward ordering constraints on the attribute macros.
+
+ Thanks to @Lehona for reporting this problem and to @dtolnay for suggesting the dummy derive macro.
+
+## [1.3.0] - 2020-11-22
+
+### Added
+
+* Support specifying a path to the `serde_with` crate for the `serde_as` and derive macros.
+ This is useful when using crate renaming in Cargo.toml or while re-exporting the macros.
+
+ Many thanks to @tobz1000 for raising the issue and contributing fixes.
+
+### Changed
+
+* Bump minimum supported rust version to 1.40.0
+
+## [1.2.2] - 2020-10-06
+
+### Fixed
+
+* @adwhit contributed an improvement to `DeserializeFromStr` which allows it to deserialize from bytes (#186).
+ This makes the derived implementation applicable in more situations.
+
+## [1.2.1] - 2020-10-04
+
+### Fixed
+
+* The derive macros `SerializeDisplay` and `DeserializeFromStr` now use the properly namespaced types and traits.
+ This solves conflicts with `Result` if `Result` is not `std::result::Result`, e.g., a type alias.
+ Additionally, the code assumed that `FromStr` was in scope, which is now also not required.
+
+ Thanks goes to @adwhit for reporting and fixing the problem in #186.
+
+## [1.2.0] - 2020-10-01
+
+### Added
+
+* Add `serde_as` macro. Refer to the `serde_with` crate for details.
+* Add two derive macros, `SerializeDisplay` and `DeserializeFromStr`, which implement the `Serialize`/`Deserialize` traits based on `Display` and `FromStr`.
+ This is in addition to the already existing methods like `DisplayFromStr`, which act locally, whereas the derive macros provide the traits expected by the rest of the ecosystem.
+
+### Changed
+
+* Convert the code to use 2018 edition.
+
+### Fixed
+
+* The `serde_as` macro now supports serde attributes and no longer panic on unrecognized values in the attribute.
+
+## [1.2.0-alpha.3] - 2020-08-16
+
+### Added
+
+* Add two derive macros, `SerializeDisplay` and `DeserializeFromStr`, which implement the `Serialize`/`Deserialize` traits based on `Display` and `FromStr`.
+ This is in addition to the already existing methods like `DisplayFromStr`, which act locally, whereas the derive macros provide the traits expected by the rest of the ecosystem.
+
+## [1.2.0-alpha.2] - 2020-08-08
+
+### Fixed
+
+* The `serde_as` macro now supports serde attributes and no longer panic on unrecognized values in the attribute.
+
+## [1.2.0-alpha.1] - 2020-06-27
+
+### Added
+
+* Add `serde_as` macro. Refer to the `serde_with` crate for details.
+
+### Changed
+
+* Convert the code to use 2018 edition.
+
+## [1.1.0] - 2020-01-16
+
+### Changed
+
+* Bump minimal Rust version to 1.36.0 to support Rust Edition 2018
+* Improved CI pipeline by running `cargo audit` and `tarpaulin` in all configurations now.
+
+## [1.0.1] - 2019-04-09
+
+### Fixed
+
+* Features for the `syn` dependency were missing.
+ This was hidden due to the dev-dependencies whose features leaked into the normal build.
+
+## [1.0.0] - 2019-04-02
+
+Initial Release
+
+### Added
+
+* Add `skip_serializing_none` attribute, which adds `#[serde(skip_serializing_if = "Option::is_none")]` for each Option in a struct.
+ This is helpful for APIs which have many optional fields.
+ The effect of can be negated by adding `serialize_always` on those fields, which should always be serialized.
+ Existing `skip_serializing_if` will never be modified and those fields keep their behavior.
diff --git a/third_party/rust/serde_with_macros/Cargo.toml b/third_party/rust/serde_with_macros/Cargo.toml
new file mode 100644
index 0000000000..e833eb60e0
--- /dev/null
+++ b/third_party/rust/serde_with_macros/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.60"
+name = "serde_with_macros"
+version = "3.0.0"
+authors = ["Jonas Bushart"]
+include = [
+ "src/**/*",
+ "tests/**/*",
+ "!tests/compile-fail/**",
+ "LICENSE-*",
+ "README.md",
+ "CHANGELOG.md",
+]
+description = "proc-macro library for serde_with"
+documentation = "https://docs.rs/serde_with_macros/"
+readme = "README.md"
+keywords = [
+ "serde",
+ "utilities",
+ "serialization",
+ "deserialization",
+]
+categories = ["encoding"]
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/jonasbb/serde_with/"
+
+[package.metadata.docs.rs]
+all-features = true
+
+[package.metadata.release]
+tag = false
+
+[[package.metadata.release.pre-release-replacements]]
+file = "CHANGELOG.md"
+replace = """
+[Unreleased]
+
+## [{{version}}] - {{date}}"""
+search = '\[Unreleased\]'
+
+[[package.metadata.release.pre-release-replacements]]
+file = "src/lib.rs"
+replace = "https://docs.rs/serde_with/{{version}}/"
+search = 'https://docs\.rs/serde_with/[\d.]+/'
+
+[[package.metadata.release.pre-release-replacements]]
+file = "src/lib.rs"
+replace = "https://docs.rs/serde_with_macros/{{version}}/"
+search = 'https://docs\.rs/serde_with_macros/[\d.]+/'
+
+[lib]
+proc-macro = true
+
+[dependencies.darling]
+version = "0.20.0"
+
+[dependencies.proc-macro2]
+version = "1.0.1"
+
+[dependencies.quote]
+version = "1.0.0"
+
+[dependencies.syn]
+version = "2.0.0"
+features = [
+ "full",
+ "parsing",
+]
+
+[dev-dependencies.expect-test]
+version = "1.4.0"
+
+[dev-dependencies.pretty_assertions]
+version = "1.0.0"
+
+[dev-dependencies.rustversion]
+version = "1.0.0"
+
+[dev-dependencies.serde]
+version = "1.0.157"
+features = ["derive"]
+
+[dev-dependencies.serde_json]
+version = "1.0.25"
+
+[dev-dependencies.trybuild]
+version = "1.0.80"
+
+[dev-dependencies.version-sync]
+version = "0.9.1"
+
+[badges.maintenance]
+status = "actively-developed"
diff --git a/third_party/rust/serde_with_macros/LICENSE-APACHE b/third_party/rust/serde_with_macros/LICENSE-APACHE
new file mode 100644
index 0000000000..16fe87b06e
--- /dev/null
+++ b/third_party/rust/serde_with_macros/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ 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
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/third_party/rust/serde_with_macros/LICENSE-MIT b/third_party/rust/serde_with_macros/LICENSE-MIT
new file mode 100644
index 0000000000..9203baa055
--- /dev/null
+++ b/third_party/rust/serde_with_macros/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2015
+
+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/rust/serde_with_macros/README.md b/third_party/rust/serde_with_macros/README.md
new file mode 100644
index 0000000000..fd5c446f37
--- /dev/null
+++ b/third_party/rust/serde_with_macros/README.md
@@ -0,0 +1,212 @@
+# Custom de/serialization functions for Rust's [serde](https://serde.rs)
+
+[![crates.io badge](https://img.shields.io/crates/v/serde_with.svg)](https://crates.io/crates/serde_with/)
+[![Build Status](https://github.com/jonasbb/serde_with/workflows/Rust%20CI/badge.svg)](https://github.com/jonasbb/serde_with)
+[![codecov](https://codecov.io/gh/jonasbb/serde_with/branch/master/graph/badge.svg)](https://codecov.io/gh/jonasbb/serde_with)
+[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/4322/badge)](https://bestpractices.coreinfrastructure.org/projects/4322)
+[![Rustexplorer](https://img.shields.io/badge/Try%20on-rustexplorer-lightgrey?logo=rust&logoColor=orange)](https://www.rustexplorer.com/b/py7ida)
+
+---
+
+This crate provides custom de/serialization helpers to use in combination with [serde's with-annotation][with-annotation] and with the improved [`serde_as`][as-annotation]-annotation.
+Some common use cases are:
+
+* De/Serializing a type using the `Display` and `FromStr` traits, e.g., for `u8`, `url::Url`, or `mime::Mime`.
+ Check [`DisplayFromStr`] for details.
+* Support for arrays larger than 32 elements or using const generics.
+ With `serde_as` large arrays are supported, even if they are nested in other types.
+ `[bool; 64]`, `Option<[u8; M]>`, and `Box<[[u8; 64]; N]>` are all supported, as [this examples shows](#large-and-const-generic-arrays).
+* Skip serializing all empty `Option` types with [`#[skip_serializing_none]`][skip_serializing_none].
+* Apply a prefix to each field name of a struct, without changing the de/serialize implementations of the struct using [`with_prefix!`][].
+* Deserialize a comma separated list like `#hash,#tags,#are,#great` into a `Vec<String>`.
+ Check the documentation for [`serde_with::StringWithSeparator::<CommaSeparator, T>`][StringWithSeparator].
+
+### Getting Help
+
+**Check out the [user guide][user guide] to find out more tips and tricks about this crate.**
+
+For further help using this crate you can [open a new discussion](https://github.com/jonasbb/serde_with/discussions/new) or ask on [users.rust-lang.org](https://users.rust-lang.org/).
+For bugs, please open a [new issue](https://github.com/jonasbb/serde_with/issues/new) on GitHub.
+
+## Use `serde_with` in your Project
+
+```bash
+# Add the current version to your Cargo.toml
+cargo add serde_with
+```
+
+The crate contains different features for integration with other common crates.
+Check the [feature flags][] section for information about all available features.
+
+## Examples
+
+Annotate your struct or enum to enable the custom de/serializer.
+The `#[serde_as]` attribute must be placed *before* the `#[derive]`.
+
+The `as` is analogous to the `with` attribute of serde.
+You mirror the type structure of the field you want to de/serialize.
+You can specify converters for the inner types of a field, e.g., `Vec<DisplayFromStr>`.
+The default de/serialization behavior can be restored by using `_` as a placeholder, e.g., `BTreeMap<_, DisplayFromStr>`.
+
+### `DisplayFromStr`
+
+[![Rustexplorer](https://img.shields.io/badge/Try%20on-rustexplorer-lightgrey?logo=rust&logoColor=orange)](https://www.rustexplorer.com/b/py7ida)
+```rust
+#[serde_as]
+#[derive(Deserialize, Serialize)]
+struct Foo {
+ // Serialize with Display, deserialize with FromStr
+ #[serde_as(as = "DisplayFromStr")]
+ bar: u8,
+}
+
+// This will serialize
+Foo {bar: 12}
+
+// into this JSON
+{"bar": "12"}
+```
+
+### Large and const-generic arrays
+
+serde does not support arrays with more than 32 elements or using const-generics.
+The `serde_as` attribute allows circumventing this restriction, even for nested types and nested arrays.
+
+On top of it, `[u8; N]` (aka, bytes) can use the specialized `"Bytes"` for efficiency much like the `serde_bytes` crate.
+
+[![Rustexplorer](https://img.shields.io/badge/Try%20on-rustexplorer-lightgrey?logo=rust&logoColor=orange)](https://www.rustexplorer.com/b/um0xyi)
+```rust
+#[serde_as]
+#[derive(Deserialize, Serialize)]
+struct Arrays<const N: usize, const M: usize> {
+ #[serde_as(as = "[_; N]")]
+ constgeneric: [bool; N],
+
+ #[serde_as(as = "Box<[[_; 64]; N]>")]
+ nested: Box<[[u8; 64]; N]>,
+
+ #[serde_as(as = "Option<[_; M]>")]
+ optional: Option<[u8; M]>,
+
+ #[serde_as(as = "Bytes")]
+ bytes: [u8; M],
+}
+
+// This allows us to serialize a struct like this
+let arrays: Arrays<100, 128> = Arrays {
+ constgeneric: [true; 100],
+ nested: Box::new([[111; 64]; 100]),
+ optional: Some([222; 128]),
+ bytes: [0x42; 128],
+};
+assert!(serde_json::to_string(&arrays).is_ok());
+```
+
+### `skip_serializing_none`
+
+This situation often occurs with JSON, but other formats also support optional fields.
+If many fields are optional, putting the annotations on the structs can become tedious.
+The `#[skip_serializing_none]` attribute must be placed *before* the `#[derive]`.
+
+[![Rustexplorer](https://img.shields.io/badge/Try%20on-rustexplorer-lightgrey?logo=rust&logoColor=orange)](https://www.rustexplorer.com/b/xr1tm0)
+```rust
+#[skip_serializing_none]
+#[derive(Deserialize, Serialize)]
+struct Foo {
+ a: Option<usize>,
+ b: Option<usize>,
+ c: Option<usize>,
+ d: Option<usize>,
+ e: Option<usize>,
+ f: Option<usize>,
+ g: Option<usize>,
+}
+
+// This will serialize
+Foo {a: None, b: None, c: None, d: Some(4), e: None, f: None, g: Some(7)}
+
+// into this JSON
+{"d": 4, "g": 7}
+```
+
+### Advanced `serde_as` usage
+
+This example is mainly supposed to highlight the flexibility of the `serde_as`-annotation compared to [serde's with-annotation][with-annotation].
+More details about `serde_as` can be found in the [user guide].
+
+```rust
+use std::time::Duration;
+
+#[serde_as]
+#[derive(Deserialize, Serialize)]
+enum Foo {
+ Durations(
+ // Serialize them into a list of number as seconds
+ #[serde_as(as = "Vec<DurationSeconds>")]
+ Vec<Duration>,
+ ),
+ Bytes {
+ // We can treat a Vec like a map with duplicates.
+ // JSON only allows string keys, so convert i32 to strings
+ // The bytes will be hex encoded
+ #[serde_as(as = "Map<DisplayFromStr, Hex>")]
+ bytes: Vec<(i32, Vec<u8>)>,
+ }
+}
+
+// This will serialize
+Foo::Durations(
+ vec![Duration::new(5, 0), Duration::new(3600, 0), Duration::new(0, 0)]
+)
+// into this JSON
+{
+ "Durations": [5, 3600, 0]
+}
+
+// and serializes
+Foo::Bytes {
+ bytes: vec![
+ (1, vec![0, 1, 2]),
+ (-100, vec![100, 200, 255]),
+ (1, vec![0, 111, 222]),
+ ],
+}
+// into this JSON
+{
+ "Bytes": {
+ "bytes": {
+ "1": "000102",
+ "-100": "64c8ff",
+ "1": "006fde"
+ }
+ }
+}
+```
+
+[`DisplayFromStr`]: https://docs.rs/serde_with/3.0.0/serde_with/struct.DisplayFromStr.html
+[`with_prefix!`]: https://docs.rs/serde_with/3.0.0/serde_with/macro.with_prefix.html
+[feature flags]: https://docs.rs/serde_with/3.0.0/serde_with/guide/feature_flags/index.html
+[skip_serializing_none]: https://docs.rs/serde_with/3.0.0/serde_with/attr.skip_serializing_none.html
+[StringWithSeparator]: https://docs.rs/serde_with/3.0.0/serde_with/struct.StringWithSeparator.html
+[user guide]: https://docs.rs/serde_with/3.0.0/serde_with/guide/index.html
+[with-annotation]: https://serde.rs/field-attrs.html#with
+[as-annotation]: https://docs.rs/serde_with/3.0.0/serde_with/guide/serde_as/index.html
+
+## License
+
+Licensed under either of
+
+* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
+* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
+
+at your option.
+
+## Contribution
+
+For detailed contribution instructions please read [`CONTRIBUTING.md`].
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in the work by you, as defined in the Apache-2.0 license, shall
+be dual licensed as above, without any additional terms or conditions.
+
+[`CONTRIBUTING.md`]: https://github.com/jonasbb/serde_with/blob/master/CONTRIBUTING.md
diff --git a/third_party/rust/serde_with_macros/src/apply.rs b/third_party/rust/serde_with_macros/src/apply.rs
new file mode 100644
index 0000000000..9cab898482
--- /dev/null
+++ b/third_party/rust/serde_with_macros/src/apply.rs
@@ -0,0 +1,313 @@
+use darling::{ast::NestedMeta, Error as DarlingError, FromMeta};
+use proc_macro::TokenStream;
+use quote::ToTokens as _;
+use syn::{
+ parse::{Parse, ParseStream},
+ punctuated::Punctuated,
+ Attribute, Error, Field, Path, Token, Type, TypeArray, TypeGroup, TypeParen, TypePath, TypePtr,
+ TypeReference, TypeSlice, TypeTuple,
+};
+
+/// Parsed form of a single rule in the `#[apply(...)]` attribute.
+///
+/// This parses tokens in the shape of `Type => Attribute`.
+/// For example, `Option<String> => #[serde(default)]`.
+struct AddAttributesRule {
+ /// A type pattern determining the fields to which the attributes are applied.
+ ty: Type,
+ /// The attributes to apply.
+ ///
+ /// All attributes are appended to the list of existing field attributes.
+ attrs: Vec<Attribute>,
+}
+
+impl Parse for AddAttributesRule {
+ fn parse(input: ParseStream<'_>) -> Result<Self, Error> {
+ let ty: Type = input.parse()?;
+ input.parse::<Token![=>]>()?;
+ let attr = Attribute::parse_outer(input)?;
+ Ok(AddAttributesRule { ty, attrs: attr })
+ }
+}
+
+/// Parsed form of the `#[apply(...)]` attribute.
+///
+/// The `apply` attribute takes a comma separated list of rules in the shape of `Type => Attribute`.
+/// Each rule is stored as a [`AddAttributesRule`].
+struct ApplyInput {
+ metas: Vec<NestedMeta>,
+ rules: Punctuated<AddAttributesRule, Token![,]>,
+}
+
+impl Parse for ApplyInput {
+ fn parse(input: ParseStream<'_>) -> Result<Self, Error> {
+ let mut metas: Vec<NestedMeta> = Vec::new();
+
+ while input.peek2(Token![=]) && !input.peek2(Token![=>]) {
+ let value = NestedMeta::parse(input)?;
+ metas.push(value);
+ if !input.peek(Token![,]) {
+ break;
+ }
+ input.parse::<Token![,]>()?;
+ }
+
+ let rules: Punctuated<AddAttributesRule, Token![,]> =
+ input.parse_terminated(AddAttributesRule::parse, Token![,])?;
+ Ok(Self { metas, rules })
+ }
+}
+
+pub fn apply(args: TokenStream, input: TokenStream) -> TokenStream {
+ let args = syn::parse_macro_input!(args as ApplyInput);
+
+ #[derive(FromMeta)]
+ struct SerdeContainerOptions {
+ #[darling(rename = "crate")]
+ alt_crate_path: Option<Path>,
+ }
+
+ let container_options = match SerdeContainerOptions::from_list(&args.metas) {
+ Ok(v) => v,
+ Err(e) => {
+ return TokenStream::from(e.write_errors());
+ }
+ };
+ let serde_with_crate_path = container_options
+ .alt_crate_path
+ .unwrap_or_else(|| syn::parse_quote!(::serde_with));
+
+ let res = match super::apply_function_to_struct_and_enum_fields_darling(
+ input,
+ &serde_with_crate_path,
+ &prepare_apply_attribute_to_field(args),
+ ) {
+ Ok(res) => res,
+ Err(err) => err.write_errors(),
+ };
+ TokenStream::from(res)
+}
+
+/// Create a function compatible with [`super::apply_function_to_struct_and_enum_fields`] based on [`ApplyInput`].
+///
+/// A single [`ApplyInput`] can apply to multiple field types.
+/// To account for this a new function must be created to stay compatible with the function signature or [`super::apply_function_to_struct_and_enum_fields`].
+fn prepare_apply_attribute_to_field(
+ input: ApplyInput,
+) -> impl Fn(&mut Field) -> Result<(), DarlingError> {
+ move |field: &mut Field| {
+ let has_skip_attr = super::field_has_attribute(field, "serde_with", "skip_apply");
+ if has_skip_attr {
+ return Ok(());
+ }
+
+ for matcher in input.rules.iter() {
+ if ty_pattern_matches_ty(&matcher.ty, &field.ty) {
+ field.attrs.extend(matcher.attrs.clone());
+ }
+ }
+ Ok(())
+ }
+}
+
+fn ty_pattern_matches_ty(ty_pattern: &Type, ty: &Type) -> bool {
+ match (ty_pattern, ty) {
+ // Groups are invisible groupings which can for example come from macro_rules expansion.
+ // This can lead to a mismatch where the `ty` is "Group { Option<String> }" and the `ty_pattern` is "Option<String>".
+ // To account for this we unwrap the group and compare the inner types.
+ (
+ Type::Group(TypeGroup {
+ elem: ty_pattern, ..
+ }),
+ ty,
+ ) => ty_pattern_matches_ty(ty_pattern, ty),
+ (ty_pattern, Type::Group(TypeGroup { elem: ty, .. })) => {
+ ty_pattern_matches_ty(ty_pattern, ty)
+ }
+
+ // Processing of the other types
+ (
+ Type::Array(TypeArray {
+ elem: ty_pattern,
+ len: len_pattern,
+ ..
+ }),
+ Type::Array(TypeArray { elem: ty, len, .. }),
+ ) => {
+ let ty_match = ty_pattern_matches_ty(ty_pattern, ty);
+ dbg!(len_pattern);
+ let len_match = len_pattern == len || len_pattern.to_token_stream().to_string() == "_";
+ ty_match && len_match
+ }
+ (Type::BareFn(ty_pattern), Type::BareFn(ty)) => ty_pattern == ty,
+ (Type::ImplTrait(ty_pattern), Type::ImplTrait(ty)) => ty_pattern == ty,
+ (Type::Infer(_), _) => true,
+ (Type::Macro(ty_pattern), Type::Macro(ty)) => ty_pattern == ty,
+ (Type::Never(_), Type::Never(_)) => true,
+ (
+ Type::Paren(TypeParen {
+ elem: ty_pattern, ..
+ }),
+ Type::Paren(TypeParen { elem: ty, .. }),
+ ) => ty_pattern_matches_ty(ty_pattern, ty),
+ (
+ Type::Path(TypePath {
+ qself: qself_pattern,
+ path: path_pattern,
+ }),
+ Type::Path(TypePath { qself, path }),
+ ) => {
+ /// Compare two paths for relaxed equality.
+ ///
+ /// Two paths match if they are equal except for the path arguments.
+ /// Path arguments are generics on types or functions.
+ /// If the pattern has no argument, it can match with everthing.
+ /// If the pattern does have an argument, the other side must be equal.
+ fn path_pattern_matches_path(path_pattern: &Path, path: &Path) -> bool {
+ if path_pattern.leading_colon != path.leading_colon
+ || path_pattern.segments.len() != path.segments.len()
+ {
+ return false;
+ }
+ // Boths parts are equal length
+ std::iter::zip(&path_pattern.segments, &path.segments).all(
+ |(path_pattern_segment, path_segment)| {
+ let ident_equal = path_pattern_segment.ident == path_segment.ident;
+ let args_match =
+ match (&path_pattern_segment.arguments, &path_segment.arguments) {
+ (syn::PathArguments::None, _) => true,
+ (
+ syn::PathArguments::AngleBracketed(
+ syn::AngleBracketedGenericArguments {
+ args: args_pattern,
+ ..
+ },
+ ),
+ syn::PathArguments::AngleBracketed(
+ syn::AngleBracketedGenericArguments { args, .. },
+ ),
+ ) => {
+ args_pattern.len() == args.len()
+ && std::iter::zip(args_pattern, args).all(|(a, b)| {
+ match (a, b) {
+ (
+ syn::GenericArgument::Type(ty_pattern),
+ syn::GenericArgument::Type(ty),
+ ) => ty_pattern_matches_ty(ty_pattern, ty),
+ (a, b) => a == b,
+ }
+ })
+ }
+ (args_pattern, args) => args_pattern == args,
+ };
+ ident_equal && args_match
+ },
+ )
+ }
+ qself_pattern == qself && path_pattern_matches_path(path_pattern, path)
+ }
+ (
+ Type::Ptr(TypePtr {
+ const_token: const_token_pattern,
+ mutability: mutability_pattern,
+ elem: ty_pattern,
+ ..
+ }),
+ Type::Ptr(TypePtr {
+ const_token,
+ mutability,
+ elem: ty,
+ ..
+ }),
+ ) => {
+ const_token_pattern == const_token
+ && mutability_pattern == mutability
+ && ty_pattern_matches_ty(ty_pattern, ty)
+ }
+ (
+ Type::Reference(TypeReference {
+ lifetime: lifetime_pattern,
+ elem: ty_pattern,
+ ..
+ }),
+ Type::Reference(TypeReference {
+ lifetime, elem: ty, ..
+ }),
+ ) => {
+ (lifetime_pattern.is_none() || lifetime_pattern == lifetime)
+ && ty_pattern_matches_ty(ty_pattern, ty)
+ }
+ (
+ Type::Slice(TypeSlice {
+ elem: ty_pattern, ..
+ }),
+ Type::Slice(TypeSlice { elem: ty, .. }),
+ ) => ty_pattern_matches_ty(ty_pattern, ty),
+ (Type::TraitObject(ty_pattern), Type::TraitObject(ty)) => ty_pattern == ty,
+ (
+ Type::Tuple(TypeTuple {
+ elems: ty_pattern, ..
+ }),
+ Type::Tuple(TypeTuple { elems: ty, .. }),
+ ) => {
+ ty_pattern.len() == ty.len()
+ && std::iter::zip(ty_pattern, ty)
+ .all(|(ty_pattern, ty)| ty_pattern_matches_ty(ty_pattern, ty))
+ }
+ (Type::Verbatim(_), Type::Verbatim(_)) => false,
+ _ => false,
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[track_caller]
+ fn matches(ty_pattern: &str, ty: &str) -> bool {
+ let ty_pattern = syn::parse_str(ty_pattern).unwrap();
+ let ty = syn::parse_str(ty).unwrap();
+ ty_pattern_matches_ty(&ty_pattern, &ty)
+ }
+
+ #[test]
+ fn test_ty_generic() {
+ assert!(matches("Option<u8>", "Option<u8>"));
+ assert!(matches("Option", "Option<u8>"));
+ assert!(!matches("Option<u8>", "Option<String>"));
+
+ assert!(matches("BTreeMap<u8, u8>", "BTreeMap<u8, u8>"));
+ assert!(matches("BTreeMap", "BTreeMap<u8, u8>"));
+ assert!(!matches("BTreeMap<String, String>", "BTreeMap<u8, u8>"));
+ assert!(matches("BTreeMap<_, _>", "BTreeMap<u8, u8>"));
+ assert!(matches("BTreeMap<_, u8>", "BTreeMap<u8, u8>"));
+ assert!(!matches("BTreeMap<String, _>", "BTreeMap<u8, u8>"));
+ }
+
+ #[test]
+ fn test_array() {
+ assert!(matches("[u8; 1]", "[u8; 1]"));
+ assert!(matches("[_; 1]", "[u8; 1]"));
+ assert!(matches("[u8; _]", "[u8; 1]"));
+ assert!(matches("[u8; _]", "[u8; N]"));
+
+ assert!(!matches("[u8; 1]", "[u8; 2]"));
+ assert!(!matches("[u8; 1]", "[u8; _]"));
+ assert!(!matches("[u8; 1]", "[String; 1]"));
+ }
+
+ #[test]
+ fn test_reference() {
+ assert!(matches("&str", "&str"));
+ assert!(matches("&mut str", "&str"));
+ assert!(matches("&str", "&mut str"));
+ assert!(matches("&str", "&'a str"));
+ assert!(matches("&str", "&'static str"));
+ assert!(matches("&str", "&'static mut str"));
+
+ assert!(matches("&'a str", "&'a str"));
+ assert!(matches("&'a mut str", "&'a str"));
+
+ assert!(!matches("&'b str", "&'a str"));
+ }
+}
diff --git a/third_party/rust/serde_with_macros/src/lib.rs b/third_party/rust/serde_with_macros/src/lib.rs
new file mode 100644
index 0000000000..7f6d46ee37
--- /dev/null
+++ b/third_party/rust/serde_with_macros/src/lib.rs
@@ -0,0 +1,1318 @@
+#![forbid(unsafe_code)]
+#![warn(
+ clippy::semicolon_if_nothing_returned,
+ missing_copy_implementations,
+ missing_debug_implementations,
+ missing_docs,
+ rust_2018_idioms,
+ rustdoc::missing_crate_level_docs,
+ trivial_casts,
+ trivial_numeric_casts,
+ unused_extern_crates,
+ unused_import_braces,
+ unused_qualifications,
+ variant_size_differences
+)]
+#![doc(test(attr(forbid(unsafe_code))))]
+#![doc(test(attr(deny(
+ missing_copy_implementations,
+ missing_debug_implementations,
+ trivial_casts,
+ trivial_numeric_casts,
+ unused_extern_crates,
+ unused_import_braces,
+ unused_qualifications,
+))))]
+#![doc(test(attr(warn(rust_2018_idioms))))]
+// Not needed for 2018 edition and conflicts with `rust_2018_idioms`
+#![doc(test(no_crate_inject))]
+#![doc(html_root_url = "https://docs.rs/serde_with_macros/3.0.0/")]
+// Necessary to silence the warning about clippy::unknown_clippy_lints on nightly
+#![allow(renamed_and_removed_lints)]
+// Necessary for nightly clippy lints
+#![allow(clippy::unknown_clippy_lints)]
+// Tarpaulin does not work well with proc macros and marks most of the lines as uncovered.
+#![cfg(not(tarpaulin_include))]
+
+//! proc-macro extensions for [`serde_with`].
+//!
+//! This crate should **NEVER** be used alone.
+//! All macros **MUST** be used via the re-exports in the [`serde_with`] crate.
+//!
+//! [`serde_with`]: https://crates.io/crates/serde_with/
+
+#[allow(unused_extern_crates)]
+extern crate proc_macro;
+
+mod apply;
+mod utils;
+
+use crate::utils::{split_with_de_lifetime, DeriveOptions, IteratorExt as _};
+use darling::{
+ ast::NestedMeta,
+ util::{Flag, Override},
+ Error as DarlingError, FromField, FromMeta,
+};
+use proc_macro::TokenStream;
+use proc_macro2::{Span, TokenStream as TokenStream2};
+use quote::quote;
+use syn::{
+ parse::Parser,
+ parse_macro_input, parse_quote,
+ punctuated::{Pair, Punctuated},
+ spanned::Spanned,
+ DeriveInput, Error, Field, Fields, GenericArgument, ItemEnum, ItemStruct, Meta, Path,
+ PathArguments, ReturnType, Token, Type,
+};
+
+/// Apply function on every field of structs or enums
+fn apply_function_to_struct_and_enum_fields<F>(
+ input: TokenStream,
+ function: F,
+) -> Result<TokenStream2, Error>
+where
+ F: Copy,
+ F: Fn(&mut Field) -> Result<(), String>,
+{
+ /// Handle a single struct or a single enum variant
+ fn apply_on_fields<F>(fields: &mut Fields, function: F) -> Result<(), Error>
+ where
+ F: Fn(&mut Field) -> Result<(), String>,
+ {
+ match fields {
+ // simple, no fields, do nothing
+ Fields::Unit => Ok(()),
+ Fields::Named(ref mut fields) => fields
+ .named
+ .iter_mut()
+ .map(|field| function(field).map_err(|err| Error::new(field.span(), err)))
+ .collect_error(),
+ Fields::Unnamed(ref mut fields) => fields
+ .unnamed
+ .iter_mut()
+ .map(|field| function(field).map_err(|err| Error::new(field.span(), err)))
+ .collect_error(),
+ }
+ }
+
+ // For each field in the struct given by `input`, add the `skip_serializing_if` attribute,
+ // if and only if, it is of type `Option`
+ if let Ok(mut input) = syn::parse::<ItemStruct>(input.clone()) {
+ apply_on_fields(&mut input.fields, function)?;
+ Ok(quote!(#input))
+ } else if let Ok(mut input) = syn::parse::<ItemEnum>(input) {
+ input
+ .variants
+ .iter_mut()
+ .map(|variant| apply_on_fields(&mut variant.fields, function))
+ .collect_error()?;
+ Ok(quote!(#input))
+ } else {
+ Err(Error::new(
+ Span::call_site(),
+ "The attribute can only be applied to struct or enum definitions.",
+ ))
+ }
+}
+
+/// Like [apply_function_to_struct_and_enum_fields] but for darling errors
+fn apply_function_to_struct_and_enum_fields_darling<F>(
+ input: TokenStream,
+ serde_with_crate_path: &Path,
+ function: F,
+) -> Result<TokenStream2, DarlingError>
+where
+ F: Copy,
+ F: Fn(&mut Field) -> Result<(), DarlingError>,
+{
+ /// Handle a single struct or a single enum variant
+ fn apply_on_fields<F>(fields: &mut Fields, function: F) -> Result<(), DarlingError>
+ where
+ F: Fn(&mut Field) -> Result<(), DarlingError>,
+ {
+ match fields {
+ // simple, no fields, do nothing
+ Fields::Unit => Ok(()),
+ Fields::Named(ref mut fields) => {
+ let errors: Vec<DarlingError> = fields
+ .named
+ .iter_mut()
+ .map(|field| function(field).map_err(|err| err.with_span(&field)))
+ // turn the Err variant into the Some, such that we only collect errors
+ .filter_map(|res| match res {
+ Err(e) => Some(e),
+ Ok(()) => None,
+ })
+ .collect();
+ if errors.is_empty() {
+ Ok(())
+ } else {
+ Err(DarlingError::multiple(errors))
+ }
+ }
+ Fields::Unnamed(ref mut fields) => {
+ let errors: Vec<DarlingError> = fields
+ .unnamed
+ .iter_mut()
+ .map(|field| function(field).map_err(|err| err.with_span(&field)))
+ // turn the Err variant into the Some, such that we only collect errors
+ .filter_map(|res| match res {
+ Err(e) => Some(e),
+ Ok(()) => None,
+ })
+ .collect();
+ if errors.is_empty() {
+ Ok(())
+ } else {
+ Err(DarlingError::multiple(errors))
+ }
+ }
+ }
+ }
+
+ // Add a dummy derive macro which consumes (makes inert) all field attributes
+ let consume_serde_as_attribute = parse_quote!(
+ #[derive(#serde_with_crate_path::__private_consume_serde_as_attributes)]
+ );
+
+ // For each field in the struct given by `input`, add the `skip_serializing_if` attribute,
+ // if and only if, it is of type `Option`
+ if let Ok(mut input) = syn::parse::<ItemStruct>(input.clone()) {
+ apply_on_fields(&mut input.fields, function)?;
+ input.attrs.push(consume_serde_as_attribute);
+ Ok(quote!(#input))
+ } else if let Ok(mut input) = syn::parse::<ItemEnum>(input) {
+ // Prevent serde_as on enum variants
+ let mut errors: Vec<DarlingError> = input
+ .variants
+ .iter()
+ .flat_map(|variant| {
+ variant.attrs.iter().filter_map(|attr| {
+ if attr.path().is_ident("serde_as") {
+ Some(
+ DarlingError::custom(
+ "serde_as attribute is not allowed on enum variants",
+ )
+ .with_span(&attr),
+ )
+ } else {
+ None
+ }
+ })
+ })
+ .collect();
+ // Process serde_as on all fields
+ errors.extend(
+ input
+ .variants
+ .iter_mut()
+ .map(|variant| apply_on_fields(&mut variant.fields, function))
+ // turn the Err variant into the Some, such that we only collect errors
+ .filter_map(|res| match res {
+ Err(e) => Some(e),
+ Ok(()) => None,
+ }),
+ );
+
+ if errors.is_empty() {
+ input.attrs.push(consume_serde_as_attribute);
+ Ok(quote!(#input))
+ } else {
+ Err(DarlingError::multiple(errors))
+ }
+ } else {
+ Err(DarlingError::custom(
+ "The attribute can only be applied to struct or enum definitions.",
+ )
+ .with_span(&Span::call_site()))
+ }
+}
+
+/// Add `skip_serializing_if` annotations to [`Option`] fields.
+///
+/// The attribute can be added to structs and enums.
+/// The `#[skip_serializing_none]` attribute must be placed *before* the `#[derive]` attribute.
+///
+/// # Example
+///
+/// JSON APIs sometimes have many optional values.
+/// Missing values should not be serialized, to keep the serialized format smaller.
+/// Such a data type might look like:
+///
+/// ```rust
+/// # use serde::Serialize;
+/// #
+/// #[derive(Serialize)]
+/// struct Data {
+/// #[serde(skip_serializing_if = "Option::is_none")]
+/// a: Option<String>,
+/// #[serde(skip_serializing_if = "Option::is_none")]
+/// b: Option<u64>,
+/// #[serde(skip_serializing_if = "Option::is_none")]
+/// c: Option<String>,
+/// #[serde(skip_serializing_if = "Option::is_none")]
+/// d: Option<bool>,
+/// }
+/// ```
+///
+/// The `skip_serializing_if` annotation is repetitive and harms readability.
+/// Instead, the same struct can be written as:
+///
+/// ```rust
+/// # use serde::Serialize;
+/// # use serde_with_macros::skip_serializing_none;
+/// #[skip_serializing_none]
+/// #[derive(Serialize)]
+/// struct Data {
+/// a: Option<String>,
+/// b: Option<u64>,
+/// c: Option<String>,
+/// // Always serialize field d even if None
+/// #[serialize_always]
+/// d: Option<bool>,
+/// }
+/// ```
+///
+/// Existing `skip_serializing_if` annotations will not be altered.
+///
+/// If some values should always be serialized, then `serialize_always` can be used.
+///
+/// # Limitations
+///
+/// The `serialize_always` cannot be used together with a manual `skip_serializing_if` annotations,
+/// as these conflict in their meaning. A compile error will be generated if this occurs.
+///
+/// The `skip_serializing_none` only works if the type is called [`Option`],
+/// [`std::option::Option`], or [`core::option::Option`]. Type aliasing an [`Option`] and giving it
+/// another name, will cause this field to be ignored. This cannot be supported, as proc-macros run
+/// before type checking, thus it is not possible to determine if a type alias refers to an
+/// [`Option`].
+///
+/// ```rust
+/// # use serde::Serialize;
+/// # use serde_with_macros::skip_serializing_none;
+/// type MyOption<T> = Option<T>;
+///
+/// #[skip_serializing_none]
+/// #[derive(Serialize)]
+/// struct Data {
+/// a: MyOption<String>, // This field will not be skipped
+/// }
+/// ```
+///
+/// Likewise, if you import a type and name it `Option`, the `skip_serializing_if` attributes will
+/// be added and compile errors will occur, if `Option::is_none` is not a valid function.
+/// Here the function `Vec::is_none` does not exist, and therefore the example fails to compile.
+///
+/// ```rust,compile_fail
+/// # use serde::Serialize;
+/// # use serde_with_macros::skip_serializing_none;
+/// use std::vec::Vec as Option;
+///
+/// #[skip_serializing_none]
+/// #[derive(Serialize)]
+/// struct Data {
+/// a: Option<String>,
+/// }
+/// ```
+#[proc_macro_attribute]
+pub fn skip_serializing_none(_args: TokenStream, input: TokenStream) -> TokenStream {
+ let res = match apply_function_to_struct_and_enum_fields(
+ input,
+ skip_serializing_none_add_attr_to_field,
+ ) {
+ Ok(res) => res,
+ Err(err) => err.to_compile_error(),
+ };
+ TokenStream::from(res)
+}
+
+/// Add the skip_serializing_if annotation to each field of the struct
+fn skip_serializing_none_add_attr_to_field(field: &mut Field) -> Result<(), String> {
+ if is_std_option(&field.ty) {
+ let has_skip_serializing_if = field_has_attribute(field, "serde", "skip_serializing_if");
+
+ // Remove the `serialize_always` attribute
+ let mut has_always_attr = false;
+ field.attrs.retain(|attr| {
+ let has_attr = attr.path().is_ident("serialize_always");
+ has_always_attr |= has_attr;
+ !has_attr
+ });
+
+ // Error on conflicting attributes
+ if has_always_attr && has_skip_serializing_if {
+ let mut msg = r#"The attributes `serialize_always` and `serde(skip_serializing_if = "...")` cannot be used on the same field"#.to_string();
+ if let Some(ident) = &field.ident {
+ msg += ": `";
+ msg += &ident.to_string();
+ msg += "`";
+ }
+ msg += ".";
+ return Err(msg);
+ }
+
+ // Do nothing if `skip_serializing_if` or `serialize_always` is already present
+ if has_skip_serializing_if || has_always_attr {
+ return Ok(());
+ }
+
+ // Add the `skip_serializing_if` attribute
+ let attr = parse_quote!(
+ #[serde(skip_serializing_if = "Option::is_none")]
+ );
+ field.attrs.push(attr);
+ } else {
+ // Warn on use of `serialize_always` on non-Option fields
+ let has_attr = field
+ .attrs
+ .iter()
+ .any(|attr| attr.path().is_ident("serialize_always"));
+ if has_attr {
+ return Err("`serialize_always` may only be used on fields of type `Option`.".into());
+ }
+ }
+ Ok(())
+}
+
+/// Return `true`, if the type path refers to `std::option::Option`
+///
+/// Accepts
+///
+/// * `Option`
+/// * `std::option::Option`, with or without leading `::`
+/// * `core::option::Option`, with or without leading `::`
+fn is_std_option(type_: &Type) -> bool {
+ match type_ {
+ Type::Array(_)
+ | Type::BareFn(_)
+ | Type::ImplTrait(_)
+ | Type::Infer(_)
+ | Type::Macro(_)
+ | Type::Never(_)
+ | Type::Ptr(_)
+ | Type::Reference(_)
+ | Type::Slice(_)
+ | Type::TraitObject(_)
+ | Type::Tuple(_)
+ | Type::Verbatim(_) => false,
+
+ Type::Group(syn::TypeGroup { elem, .. })
+ | Type::Paren(syn::TypeParen { elem, .. })
+ | Type::Path(syn::TypePath {
+ qself: Some(syn::QSelf { ty: elem, .. }),
+ ..
+ }) => is_std_option(elem),
+
+ Type::Path(syn::TypePath { qself: None, path }) => {
+ (path.leading_colon.is_none()
+ && path.segments.len() == 1
+ && path.segments[0].ident == "Option")
+ || (path.segments.len() == 3
+ && (path.segments[0].ident == "std" || path.segments[0].ident == "core")
+ && path.segments[1].ident == "option"
+ && path.segments[2].ident == "Option")
+ }
+ _ => false,
+ }
+}
+
+/// Determine if the `field` has an attribute with given `namespace` and `name`
+///
+/// On the example of
+/// `#[serde(skip_serializing_if = "Option::is_none")]`
+///
+/// * `serde` is the outermost path, here namespace
+/// * it contains a Meta::List
+/// * which contains in another Meta a Meta::NameValue
+/// * with the name being `skip_serializing_if`
+fn field_has_attribute(field: &Field, namespace: &str, name: &str) -> bool {
+ for attr in &field.attrs {
+ if attr.path().is_ident(namespace) {
+ // Ignore non parsable attributes, as these are not important for us
+ if let Meta::List(expr) = &attr.meta {
+ let nested = match Punctuated::<Meta, Token![,]>::parse_terminated
+ .parse2(expr.tokens.clone())
+ {
+ Ok(nested) => nested,
+ Err(_) => continue,
+ };
+ for expr in nested {
+ match expr {
+ Meta::NameValue(expr) => {
+ if let Some(ident) = expr.path.get_ident() {
+ if *ident == name {
+ return true;
+ }
+ }
+ }
+ Meta::Path(expr) => {
+ if let Some(ident) = expr.get_ident() {
+ if *ident == name {
+ return true;
+ }
+ }
+ }
+ _ => (),
+ }
+ }
+ }
+ }
+ }
+ false
+}
+
+/// Convenience macro to use the [`serde_as`] system.
+///
+/// The [`serde_as`] system is designed as a more flexible alternative to serde's with-annotation.
+/// The `#[serde_as]` attribute must be placed *before* the `#[derive]` attribute.
+/// Each field of a struct or enum can be annotated with `#[serde_as(...)]` to specify which
+/// transformations should be applied. `serde_as` is *not* supported on enum variants.
+/// This is in contrast to `#[serde(with = "...")]`.
+///
+/// # Example
+///
+/// ```rust,ignore
+/// use serde_with::{serde_as, DisplayFromStr, Map};
+///
+/// #[serde_as]
+/// #[derive(Serialize, Deserialize)]
+/// struct Data {
+/// /// Serialize into number
+/// #[serde_as(as = "_")]
+/// a: u32,
+///
+/// /// Serialize into String
+/// #[serde_as(as = "DisplayFromStr")]
+/// b: u32,
+///
+/// /// Serialize into a map from String to String
+/// #[serde_as(as = "Map<DisplayFromStr, _>")]
+/// c: Vec<(u32, String)>,
+/// }
+/// ```
+///
+/// # Alternative path to `serde_with` crate
+///
+/// If `serde_with` is not available at the default path, its path should be specified with the
+/// `crate` argument. See [re-exporting `serde_as`] for more use case information.
+///
+/// ```rust,ignore
+/// #[serde_as(crate = "::some_other_lib::serde_with")]
+/// #[derive(Deserialize)]
+/// struct Data {
+/// #[serde_as(as = "_")]
+/// a: u32,
+/// }
+/// ```
+///
+/// # What this macro does
+///
+/// The `serde_as` macro only serves a convenience function.
+/// All the steps it performs, can easily be done manually, in case the cost of an attribute macro
+/// is deemed too high. The functionality can best be described with an example.
+///
+/// ```rust,ignore
+/// #[serde_as]
+/// #[derive(serde::Serialize)]
+/// struct Foo {
+/// #[serde_as(as = "Vec<_>")]
+/// bar: Vec<u32>,
+///
+/// #[serde_as(as = "Option<DisplayFromStr>")]
+/// baz: Option<u32>,
+/// }
+/// ```
+///
+/// 1. All the placeholder type `_` will be replaced with `::serde_with::Same`.
+/// The placeholder type `_` marks all the places where the type's `Serialize` implementation
+/// should be used. In the example, it means that the `u32` values will serialize with the
+/// `Serialize` implementation of `u32`. The `Same` type implements `SerializeAs` whenever the
+/// underlying type implements `Serialize` and is used to make the two traits compatible.
+///
+/// If you specify a custom path for `serde_with` via the `crate` attribute, the path to the
+/// `Same` type will be altered accordingly.
+///
+/// 2. Wrap the type from the annotation inside a `::serde_with::As`.
+/// In the above example we now have something like `::serde_with::As::<Vec<::serde_with::Same>>`.
+/// The `As` type acts as the opposite of the `Same` type.
+/// It allows using a `SerializeAs` type whenever a `Serialize` is required.
+///
+/// 3. Translate the `*as` attributes into the serde equivalent ones.
+/// `#[serde_as(as = ...)]` will become `#[serde(with = ...)]`.
+/// Similarly, `serialize_as` is translated to `serialize_with`.
+///
+/// The field attributes will be kept on the struct/enum such that other macros can use them
+/// too.
+///
+/// 4. It searches `#[serde_as(as = ...)]` if there is a type named `BorrowCow` under any path.
+/// If `BorrowCow` is found, the attribute `#[serde(borrow)]` is added to the field.
+/// If `#[serde(borrow)]` or `#[serde(borrow = "...")]` is already present, this step will be
+/// skipped.
+///
+/// 5. Restore the ability of accepting missing fields if both the field and the
+/// transformation are `Option`.
+///
+/// An `Option` is detected by an exact text match.
+/// Renaming an import or type aliases can cause confusion here.
+/// The following variants are supported.
+/// * `Option`
+/// * `std::option::Option`, with or without leading `::`
+/// * `core::option::Option`, with or without leading `::`
+///
+/// If the field is of type `Option<T>` and the attribute `#[serde_as(as = "Option<S>")]` (also
+/// `deserialize_as`; for any `T`/`S`) then `#[serde(default)]` is applied to the field.
+///
+/// This restores the ability of accepting missing fields, which otherwise often leads to confusing [serde_with#185](https://github.com/jonasbb/serde_with/issues/185).
+/// `#[serde(default)]` is not applied, if it already exists.
+/// It only triggers if both field and transformation are `Option`s.
+/// For example, using `#[serde_as(as = "NoneAsEmptyString")]` on `Option<String>` will not see
+/// any change.
+///
+/// If the automatically applied attribute is undesired, the behavior can be supressed by adding
+/// `#[serde_as(no_default)]`.
+
+/// This can be combined like `#[serde_as(as = "Option<S>", no_default)]`.
+///
+/// After all these steps, the code snippet will have transformed into roughly this.
+///
+/// ```rust,ignore
+/// #[derive(serde::Serialize)]
+/// struct Foo {
+/// #[serde_as(as = "Vec<_>")]
+/// #[serde(with = "::serde_with::As::<Vec<::serde_with::Same>>")]
+/// bar: Vec<u32>,
+///
+/// #[serde_as(as = "Option<DisplayFromStr>")]
+/// #[serde(default)]
+/// #[serde(with = "::serde_with::As::<Option<DisplayFromStr>>")]
+/// baz: Option<u32>,
+/// }
+/// ```
+///
+/// [`serde_as`]: https://docs.rs/serde_with/3.0.0/serde_with/guide/index.html
+/// [re-exporting `serde_as`]: https://docs.rs/serde_with/3.0.0/serde_with/guide/serde_as/index.html#re-exporting-serde_as
+#[proc_macro_attribute]
+pub fn serde_as(args: TokenStream, input: TokenStream) -> TokenStream {
+ #[derive(FromMeta)]
+ struct SerdeContainerOptions {
+ #[darling(rename = "crate")]
+ alt_crate_path: Option<Path>,
+ }
+
+ match NestedMeta::parse_meta_list(args.into()) {
+ Ok(list) => {
+ let container_options = match SerdeContainerOptions::from_list(&list) {
+ Ok(v) => v,
+ Err(e) => {
+ return TokenStream::from(e.write_errors());
+ }
+ };
+
+ let serde_with_crate_path = container_options
+ .alt_crate_path
+ .unwrap_or_else(|| syn::parse_quote!(::serde_with));
+
+ // Convert any error message into a nice compiler error
+ let res = match apply_function_to_struct_and_enum_fields_darling(
+ input,
+ &serde_with_crate_path,
+ |field| serde_as_add_attr_to_field(field, &serde_with_crate_path),
+ ) {
+ Ok(res) => res,
+ Err(err) => err.write_errors(),
+ };
+ TokenStream::from(res)
+ }
+ Err(e) => TokenStream::from(DarlingError::from(e).write_errors()),
+ }
+}
+
+/// Inspect the field and convert the `serde_as` attribute into the classical `serde`
+fn serde_as_add_attr_to_field(
+ field: &mut Field,
+ serde_with_crate_path: &Path,
+) -> Result<(), DarlingError> {
+ #[derive(FromField)]
+ #[darling(attributes(serde_as))]
+ struct SerdeAsOptions {
+ r#as: Option<Type>,
+ deserialize_as: Option<Type>,
+ serialize_as: Option<Type>,
+ no_default: Flag,
+ }
+
+ impl SerdeAsOptions {
+ fn has_any_set(&self) -> bool {
+ self.r#as.is_some() || self.deserialize_as.is_some() || self.serialize_as.is_some()
+ }
+ }
+
+ #[derive(FromField)]
+ #[darling(attributes(serde), allow_unknown_fields)]
+ struct SerdeOptions {
+ with: Option<String>,
+ deserialize_with: Option<String>,
+ serialize_with: Option<String>,
+
+ borrow: Option<Override<String>>,
+ default: Option<Override<String>>,
+ }
+
+ impl SerdeOptions {
+ fn has_any_set(&self) -> bool {
+ self.with.is_some() || self.deserialize_with.is_some() || self.serialize_with.is_some()
+ }
+ }
+
+ /// Emit a `borrow` annotation, if the replacement type requires borrowing.
+ fn emit_borrow_annotation(serde_options: &SerdeOptions, as_type: &Type, field: &mut Field) {
+ let type_borrowcow = &syn::parse_quote!(BorrowCow);
+ // If the field is not borrowed yet, check if we need to borrow it.
+ if serde_options.borrow.is_none() && has_type_embedded(as_type, type_borrowcow) {
+ let attr_borrow = parse_quote!(#[serde(borrow)]);
+ field.attrs.push(attr_borrow);
+ }
+ }
+
+ /// Emit a `default` annotation, if `as_type` and `field` are both `Option`.
+ fn emit_default_annotation(
+ serde_as_options: &SerdeAsOptions,
+ serde_options: &SerdeOptions,
+ as_type: &Type,
+ field: &mut Field,
+ ) {
+ if !serde_as_options.no_default.is_present()
+ && serde_options.default.is_none()
+ && is_std_option(as_type)
+ && is_std_option(&field.ty)
+ {
+ let attr_borrow = parse_quote!(#[serde(default)]);
+ field.attrs.push(attr_borrow);
+ }
+ }
+
+ // syn v2 no longer supports keywords in the path position of an attribute.
+ // That breaks #[serde_as(as = "FooBar")], since `as` is a keyword.
+ // For each attribute, that is named `serde_as`, we replace the `as` keyword with `r#as`.
+ let mut has_serde_as = false;
+ field.attrs.iter_mut().for_each(|attr| {
+ if attr.path().is_ident("serde_as") {
+ // We found a `serde_as` attribute.
+ // Remember that such that we can quick exit otherwise
+ has_serde_as = true;
+
+ if let Meta::List(metalist) = &mut attr.meta {
+ metalist.tokens = std::mem::take(&mut metalist.tokens)
+ .into_iter()
+ .map(|token| {
+ use proc_macro2::{Ident, TokenTree};
+
+ // Replace `as` with `r#as`.
+ match token {
+ TokenTree::Ident(ident) if ident == "as" => {
+ TokenTree::Ident(Ident::new_raw("as", ident.span()))
+ }
+ _ => token,
+ }
+ })
+ .collect();
+ }
+ }
+ });
+ // If there is no `serde_as` attribute, we can exit early.
+ if !has_serde_as {
+ return Ok(());
+ }
+ let serde_as_options = SerdeAsOptions::from_field(field)?;
+ let serde_options = SerdeOptions::from_field(field)?;
+
+ let mut errors = Vec::new();
+ if !serde_as_options.has_any_set() {
+ errors.push(DarlingError::custom("An empty `serde_as` attribute on a field has no effect. You are missing an `as`, `serialize_as`, or `deserialize_as` parameter."));
+ }
+
+ // Check if there are any conflicting attributes
+ if serde_as_options.has_any_set() && serde_options.has_any_set() {
+ errors.push(DarlingError::custom("Cannot combine `serde_as` with serde's `with`, `deserialize_with`, or `serialize_with`."));
+ }
+
+ if serde_as_options.r#as.is_some() && serde_as_options.deserialize_as.is_some() {
+ errors.push(DarlingError::custom("Cannot combine `as` with `deserialize_as`. Use `serialize_as` to specify different serialization code."));
+ } else if serde_as_options.r#as.is_some() && serde_as_options.serialize_as.is_some() {
+ errors.push(DarlingError::custom("Cannot combine `as` with `serialize_as`. Use `deserialize_as` to specify different deserialization code."));
+ }
+
+ if !errors.is_empty() {
+ return Err(DarlingError::multiple(errors));
+ }
+
+ let type_same = &syn::parse_quote!(#serde_with_crate_path::Same);
+ if let Some(type_) = &serde_as_options.r#as {
+ emit_borrow_annotation(&serde_options, type_, field);
+ emit_default_annotation(&serde_as_options, &serde_options, type_, field);
+
+ let replacement_type = replace_infer_type_with_type(type_.clone(), type_same);
+ let attr_inner_tokens = quote!(#serde_with_crate_path::As::<#replacement_type>).to_string();
+ let attr = parse_quote!(#[serde(with = #attr_inner_tokens)]);
+ field.attrs.push(attr);
+ }
+ if let Some(type_) = &serde_as_options.deserialize_as {
+ emit_borrow_annotation(&serde_options, type_, field);
+ emit_default_annotation(&serde_as_options, &serde_options, type_, field);
+
+ let replacement_type = replace_infer_type_with_type(type_.clone(), type_same);
+ let attr_inner_tokens =
+ quote!(#serde_with_crate_path::As::<#replacement_type>::deserialize).to_string();
+ let attr = parse_quote!(#[serde(deserialize_with = #attr_inner_tokens)]);
+ field.attrs.push(attr);
+ }
+ if let Some(type_) = serde_as_options.serialize_as {
+ let replacement_type = replace_infer_type_with_type(type_, type_same);
+ let attr_inner_tokens =
+ quote!(#serde_with_crate_path::As::<#replacement_type>::serialize).to_string();
+ let attr = parse_quote!(#[serde(serialize_with = #attr_inner_tokens)]);
+ field.attrs.push(attr);
+ }
+
+ Ok(())
+}
+
+/// Recursively replace all occurrences of `_` with `replacement` in a [Type][]
+///
+/// The [serde_as][macro@serde_as] macro allows to use the infer type, i.e., `_`, as shortcut for
+/// `serde_with::As`. This function replaces all occurrences of the infer type with another type.
+fn replace_infer_type_with_type(to_replace: Type, replacement: &Type) -> Type {
+ match to_replace {
+ // Base case
+ // Replace the infer type with the actual replacement type
+ Type::Infer(_) => replacement.clone(),
+
+ // Recursive cases
+ // Iterate through all positions where a type could occur and recursively call this function
+ Type::Array(mut inner) => {
+ *inner.elem = replace_infer_type_with_type(*inner.elem, replacement);
+ Type::Array(inner)
+ }
+ Type::Group(mut inner) => {
+ *inner.elem = replace_infer_type_with_type(*inner.elem, replacement);
+ Type::Group(inner)
+ }
+ Type::Never(inner) => Type::Never(inner),
+ Type::Paren(mut inner) => {
+ *inner.elem = replace_infer_type_with_type(*inner.elem, replacement);
+ Type::Paren(inner)
+ }
+ Type::Path(mut inner) => {
+ match inner.path.segments.pop() {
+ Some(Pair::End(mut t)) | Some(Pair::Punctuated(mut t, _)) => {
+ t.arguments = match t.arguments {
+ PathArguments::None => PathArguments::None,
+ PathArguments::AngleBracketed(mut inner) => {
+ // Iterate over the args between the angle brackets
+ inner.args = inner
+ .args
+ .into_iter()
+ .map(|generic_argument| match generic_argument {
+ // replace types within the generics list, but leave other stuff
+ // like lifetimes untouched
+ GenericArgument::Type(type_) => GenericArgument::Type(
+ replace_infer_type_with_type(type_, replacement),
+ ),
+ ga => ga,
+ })
+ .collect();
+ PathArguments::AngleBracketed(inner)
+ }
+ PathArguments::Parenthesized(mut inner) => {
+ inner.inputs = inner
+ .inputs
+ .into_iter()
+ .map(|type_| replace_infer_type_with_type(type_, replacement))
+ .collect();
+ inner.output = match inner.output {
+ ReturnType::Type(arrow, mut type_) => {
+ *type_ = replace_infer_type_with_type(*type_, replacement);
+ ReturnType::Type(arrow, type_)
+ }
+ default => default,
+ };
+ PathArguments::Parenthesized(inner)
+ }
+ };
+ inner.path.segments.push(t);
+ }
+ None => {}
+ }
+ Type::Path(inner)
+ }
+ Type::Ptr(mut inner) => {
+ *inner.elem = replace_infer_type_with_type(*inner.elem, replacement);
+ Type::Ptr(inner)
+ }
+ Type::Reference(mut inner) => {
+ *inner.elem = replace_infer_type_with_type(*inner.elem, replacement);
+ Type::Reference(inner)
+ }
+ Type::Slice(mut inner) => {
+ *inner.elem = replace_infer_type_with_type(*inner.elem, replacement);
+ Type::Slice(inner)
+ }
+ Type::Tuple(mut inner) => {
+ inner.elems = inner
+ .elems
+ .into_pairs()
+ .map(|pair| match pair {
+ Pair::Punctuated(type_, p) => {
+ Pair::Punctuated(replace_infer_type_with_type(type_, replacement), p)
+ }
+ Pair::End(type_) => Pair::End(replace_infer_type_with_type(type_, replacement)),
+ })
+ .collect();
+ Type::Tuple(inner)
+ }
+
+ // Pass unknown types or non-handleable types (e.g., bare Fn) without performing any
+ // replacements
+ type_ => type_,
+ }
+}
+
+/// Check if a type ending in the `syn::Ident` `embedded_type` is contained in `type_`.
+fn has_type_embedded(type_: &Type, embedded_type: &syn::Ident) -> bool {
+ match type_ {
+ // Base cases
+ Type::Infer(_) => false,
+ Type::Never(_inner) => false,
+
+ // Recursive cases
+ // Iterate through all positions where a type could occur and recursively call this function
+ Type::Array(inner) => has_type_embedded(&inner.elem, embedded_type),
+ Type::Group(inner) => has_type_embedded(&inner.elem, embedded_type),
+ Type::Paren(inner) => has_type_embedded(&inner.elem, embedded_type),
+ Type::Path(inner) => {
+ match inner.path.segments.last() {
+ Some(t) => {
+ if t.ident == *embedded_type {
+ return true;
+ }
+
+ match &t.arguments {
+ PathArguments::None => false,
+ PathArguments::AngleBracketed(inner) => {
+ // Iterate over the args between the angle brackets
+ inner
+ .args
+ .iter()
+ .any(|generic_argument| match generic_argument {
+ // replace types within the generics list, but leave other stuff
+ // like lifetimes untouched
+ GenericArgument::Type(type_) => {
+ has_type_embedded(type_, embedded_type)
+ }
+ _ga => false,
+ })
+ }
+ PathArguments::Parenthesized(inner) => {
+ inner
+ .inputs
+ .iter()
+ .any(|type_| has_type_embedded(type_, embedded_type))
+ || match &inner.output {
+ ReturnType::Type(_arrow, type_) => {
+ has_type_embedded(type_, embedded_type)
+ }
+ _default => false,
+ }
+ }
+ }
+ }
+ None => false,
+ }
+ }
+ Type::Ptr(inner) => has_type_embedded(&inner.elem, embedded_type),
+ Type::Reference(inner) => has_type_embedded(&inner.elem, embedded_type),
+ Type::Slice(inner) => has_type_embedded(&inner.elem, embedded_type),
+ Type::Tuple(inner) => inner.elems.pairs().any(|pair| match pair {
+ Pair::Punctuated(type_, _) | Pair::End(type_) => {
+ has_type_embedded(type_, embedded_type)
+ }
+ }),
+
+ // Pass unknown types or non-handleable types (e.g., bare Fn) without performing any
+ // replacements
+ _type_ => false,
+ }
+}
+
+/// Deserialize value by using its [`FromStr`] implementation
+///
+/// This is an alternative way to implement `Deserialize` for types, which also implement
+/// [`FromStr`] by deserializing the type from string. Ensure that the struct/enum also implements
+/// [`FromStr`]. If the implementation is missing, you will get an error message like
+/// ```text
+/// error[E0277]: the trait bound `Struct: std::str::FromStr` is not satisfied
+/// ```
+/// Additionally, `FromStr::Err` **must** implement [`Display`] as otherwise you will see a rather
+/// unhelpful error message
+///
+/// Serialization with [`Display`] is available with the matching [`SerializeDisplay`] derive.
+///
+/// # Attributes
+///
+/// Attributes for the derive can be specified via the `#[serde_with(...)]` attribute on the struct
+/// or enum. Currently, these arguments to the attribute are possible:
+///
+/// * **`#[serde_with(crate = "...")]`**: This allows using `DeserializeFromStr` when `serde_with`
+/// is not available from the crate root. This happens while [renaming dependencies in
+/// Cargo.toml][cargo-toml-rename] or when re-exporting the macro from a different crate.
+///
+/// This argument is analogue to [serde's crate argument][serde-crate] and the [crate argument
+/// to `serde_as`][serde-as-crate].
+///
+/// # Example
+///
+/// ```rust,ignore
+/// use std::str::FromStr;
+///
+/// #[derive(DeserializeFromStr)]
+/// struct A {
+/// a: u32,
+/// b: bool,
+/// }
+///
+/// impl FromStr for A {
+/// type Err = String;
+///
+/// /// Parse a value like `123<>true`
+/// fn from_str(s: &str) -> Result<Self, Self::Err> {
+/// let mut parts = s.split("<>");
+/// let number = parts
+/// .next()
+/// .ok_or_else(|| "Missing first value".to_string())?
+/// .parse()
+/// .map_err(|err: ParseIntError| err.to_string())?;
+/// let bool = parts
+/// .next()
+/// .ok_or_else(|| "Missing second value".to_string())?
+/// .parse()
+/// .map_err(|err: ParseBoolError| err.to_string())?;
+/// Ok(Self { a: number, b: bool })
+/// }
+/// }
+///
+/// let a: A = serde_json::from_str("\"159<>true\"").unwrap();
+/// assert_eq!(A { a: 159, b: true }, a);
+/// ```
+///
+/// [`Display`]: std::fmt::Display
+/// [`FromStr`]: std::str::FromStr
+/// [cargo-toml-rename]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml
+/// [serde-as-crate]: https://docs.rs/serde_with/3.0.0/serde_with/guide/serde_as/index.html#re-exporting-serde_as
+/// [serde-crate]: https://serde.rs/container-attrs.html#crate
+#[proc_macro_derive(DeserializeFromStr, attributes(serde_with))]
+pub fn derive_deserialize_fromstr(item: TokenStream) -> TokenStream {
+ let input: DeriveInput = parse_macro_input!(item);
+ let derive_options = match DeriveOptions::from_derive_input(&input) {
+ Ok(opt) => opt,
+ Err(err) => {
+ return err;
+ }
+ };
+ TokenStream::from(deserialize_fromstr(
+ input,
+ derive_options.get_serde_with_path(),
+ ))
+}
+
+fn deserialize_fromstr(mut input: DeriveInput, serde_with_crate_path: Path) -> TokenStream2 {
+ let ident = input.ident;
+ let where_clause = &mut input.generics.make_where_clause().predicates;
+ where_clause.push(parse_quote!(Self: #serde_with_crate_path::__private__::FromStr));
+ where_clause.push(parse_quote!(
+ <Self as #serde_with_crate_path::__private__::FromStr>::Err: #serde_with_crate_path::__private__::Display
+ ));
+ let (de_impl_generics, ty_generics, where_clause) = split_with_de_lifetime(&input.generics);
+ quote! {
+ #[automatically_derived]
+ impl #de_impl_generics #serde_with_crate_path::serde::Deserialize<'de> for #ident #ty_generics #where_clause {
+ fn deserialize<__D>(deserializer: __D) -> #serde_with_crate_path::__private__::Result<Self, __D::Error>
+ where
+ __D: #serde_with_crate_path::serde::Deserializer<'de>,
+ {
+ struct Helper<__S>(#serde_with_crate_path::__private__::PhantomData<__S>);
+
+ impl<'de, __S> #serde_with_crate_path::serde::de::Visitor<'de> for Helper<__S>
+ where
+ __S: #serde_with_crate_path::__private__::FromStr,
+ <__S as #serde_with_crate_path::__private__::FromStr>::Err: #serde_with_crate_path::__private__::Display,
+ {
+ type Value = __S;
+
+ fn expecting(&self, formatter: &mut #serde_with_crate_path::core::fmt::Formatter<'_>) -> #serde_with_crate_path::core::fmt::Result {
+ #serde_with_crate_path::__private__::Display::fmt("a string", formatter)
+ }
+
+ fn visit_str<__E>(
+ self,
+ value: &str
+ ) -> #serde_with_crate_path::__private__::Result<Self::Value, __E>
+ where
+ __E: #serde_with_crate_path::serde::de::Error,
+ {
+ value.parse::<Self::Value>().map_err(#serde_with_crate_path::serde::de::Error::custom)
+ }
+
+ fn visit_bytes<__E>(
+ self,
+ value: &[u8]
+ ) -> #serde_with_crate_path::__private__::Result<Self::Value, __E>
+ where
+ __E: #serde_with_crate_path::serde::de::Error,
+ {
+ let utf8 = #serde_with_crate_path::core::str::from_utf8(value).map_err(#serde_with_crate_path::serde::de::Error::custom)?;
+ self.visit_str(utf8)
+ }
+ }
+
+ deserializer.deserialize_str(Helper(#serde_with_crate_path::__private__::PhantomData))
+ }
+ }
+ }
+}
+
+/// Serialize value by using it's [`Display`] implementation
+///
+/// This is an alternative way to implement `Serialize` for types, which also implement [`Display`]
+/// by serializing the type as string. Ensure that the struct/enum also implements [`Display`].
+/// If the implementation is missing, you will get an error message like
+/// ```text
+/// error[E0277]: `Struct` doesn't implement `std::fmt::Display`
+/// ```
+///
+/// Deserialization with [`FromStr`] is available with the matching [`DeserializeFromStr`] derive.
+///
+/// # Attributes
+///
+/// Attributes for the derive can be specified via the `#[serde_with(...)]` attribute on the struct
+/// or enum. Currently, these arguments to the attribute are possible:
+///
+/// * **`#[serde_with(crate = "...")]`**: This allows using `SerializeDisplay` when `serde_with` is
+/// not available from the crate root. This happens while [renaming dependencies in
+/// Cargo.toml][cargo-toml-rename] or when re-exporting the macro from a different crate.
+///
+/// This argument is analogue to [serde's crate argument][serde-crate] and the [crate argument
+/// to `serde_as`][serde-as-crate].
+///
+/// # Example
+///
+/// ```rust,ignore
+/// use std::fmt;
+///
+/// #[derive(SerializeDisplay)]
+/// struct A {
+/// a: u32,
+/// b: bool,
+/// }
+///
+/// impl fmt::Display for A {
+/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+/// write!(f, "{}<>{}", self.a, self.b)
+/// }
+/// }
+///
+/// let a = A { a: 123, b: false };
+/// assert_eq!(r#""123<>false""#, serde_json::to_string(&a).unwrap());
+/// ```
+///
+/// [`Display`]: std::fmt::Display
+/// [`FromStr`]: std::str::FromStr
+/// [cargo-toml-rename]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml
+/// [serde-as-crate]: https://docs.rs/serde_with/3.0.0/serde_with/guide/serde_as/index.html#re-exporting-serde_as
+/// [serde-crate]: https://serde.rs/container-attrs.html#crate
+#[proc_macro_derive(SerializeDisplay, attributes(serde_with))]
+pub fn derive_serialize_display(item: TokenStream) -> TokenStream {
+ let input: DeriveInput = parse_macro_input!(item);
+ let derive_options = match DeriveOptions::from_derive_input(&input) {
+ Ok(opt) => opt,
+ Err(err) => {
+ return err;
+ }
+ };
+ TokenStream::from(serialize_display(
+ input,
+ derive_options.get_serde_with_path(),
+ ))
+}
+
+fn serialize_display(mut input: DeriveInput, serde_with_crate_path: Path) -> TokenStream2 {
+ let ident = input.ident;
+ input
+ .generics
+ .make_where_clause()
+ .predicates
+ .push(parse_quote!(Self: #serde_with_crate_path::__private__::Display));
+ let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
+ quote! {
+ #[automatically_derived]
+ impl #impl_generics #serde_with_crate_path::serde::Serialize for #ident #ty_generics #where_clause {
+ fn serialize<__S>(
+ &self,
+ serializer: __S
+ ) -> #serde_with_crate_path::__private__::Result<__S::Ok, __S::Error>
+ where
+ __S: #serde_with_crate_path::serde::Serializer,
+ {
+ serializer.collect_str(&self)
+ }
+ }
+ }
+}
+
+#[doc(hidden)]
+/// Private function. Not part of the public API
+///
+/// The only task of this derive macro is to consume any `serde_as` attributes and turn them into
+/// inert attributes. This allows the serde_as macro to keep the field attributes without causing
+/// compiler errors. The intend is that keeping the field attributes allows downstream crates to
+/// consume and act on them without causing an ordering dependency to the serde_as macro.
+///
+/// Otherwise, downstream proc-macros would need to be placed *in front of* the main `#[serde_as]`
+/// attribute, since otherwise the field attributes would already be stripped off.
+///
+/// More details about the use-cases in the GitHub discussion: <https://github.com/jonasbb/serde_with/discussions/260>.
+#[proc_macro_derive(
+ __private_consume_serde_as_attributes,
+ attributes(serde_as, serde_with)
+)]
+pub fn __private_consume_serde_as_attributes(_: TokenStream) -> TokenStream {
+ TokenStream::new()
+}
+
+/// Apply attributes to all fields with matching types
+///
+/// Whenever you experience the need to apply the same attributes to multiple fields, you can use
+/// this macro. It allows you to specify a list of types and a list of attributes.
+/// Each field with a "matching" type will then get the attributes applied.
+/// The `apply` attribute must be place *before* any consuming attributes, such as `derive`, because
+/// Rust expands all attributes in order.
+///
+/// For example, if your struct or enum contains many `Option<T>` fields, but you do not want to
+/// serialize `None` values, you can use this macro to apply the `#[serde(skip_serializing_if =
+/// "Option::is_none")]` attribute to all fields of type `Option<T>`.
+///
+/// ```rust
+/// # use serde_with_macros as serde_with;
+/// #[serde_with::apply(
+/// # crate="serde_with",
+/// Option => #[serde(skip_serializing_if = "Option::is_none")],
+/// )]
+/// #[derive(serde::Serialize)]
+/// # #[derive(Default)]
+/// struct Data {
+/// a: Option<String>,
+/// b: Option<u64>,
+/// c: Option<String>,
+/// d: Option<bool>,
+/// }
+/// #
+/// # assert_eq!("{}", serde_json::to_string(&Data::default()).unwrap());
+/// ```
+///
+/// Each rule starts with a type pattern, specifying which fields to match and a list of attributes
+/// to apply. Multiple rules can be provided in a single `apply` attribute.
+///
+/// ```rust
+/// # use serde_with_macros as serde_with;
+/// #[serde_with::apply(
+/// # crate="serde_with",
+/// Option => #[serde(default)] #[serde(skip_serializing_if = "Option::is_none")],
+/// Option<bool> => #[serde(rename = "bool")],
+/// )]
+/// # #[derive(serde::Serialize)]
+/// # #[derive(Default)]
+/// # struct Data {
+/// # a: Option<String>,
+/// # b: Option<u64>,
+/// # c: Option<String>,
+/// # d: Option<bool>,
+/// # }
+/// #
+/// # assert_eq!("{}", serde_json::to_string(&Data::default()).unwrap());
+/// ```
+///
+/// ## Type Patterns
+///
+/// The type pattern left of the `=>` specifies which fields to match.
+///
+/// | Type Pattern | Matching Types | Notes |
+/// | :---------------------- | ---------------------------------------------------: | :------------------------------------------------------------------------------ |
+/// | `_` | `Option<bool>`<br>`BTreeMap<&'static str, Vec<u32>>` | `_` matches all fields. |
+/// | `Option` | `Option<bool>`<br>`Option<String>` | A missing generic is compatible with any generic arguments. |
+/// | `Option<bool>` | `Option<bool>` | A fully specified type only matches exactly. |
+/// | `BTreeMap<String, u32>` | `BTreeMap<String, u32>` | A fully specified type only matches exactly. |
+/// | `BTreeMap<String, _>` | `BTreeMap<String, u32>`<br>`BTreeMap<String, bool>` | Any `String` key `BTreeMap` matches, as the value is using the `_` placeholder. |
+/// | `[u8; _]` | `[u8; 1]`<br>`[u8; N]` | `_` also works as a placeholder for any array length. |
+///
+/// ## Opt-out for Individual Fields
+///
+/// The `apply` attribute will find all fields with a compatible type.
+/// This can be overly eager and a different set of attributes might be required for a specific
+/// field. You can opt-out of the `apply` attribute by adding the `#[serde_with(skip_apply)]`
+/// attribute to the field. This will prevent any `apply` to apply to this field.
+/// If two rules apply to the same field, it is impossible to opt-out of only a single one.
+/// In this case the attributes must be applied to the field manually.
+///
+/// ```rust
+/// # use serde_json::json;
+/// # use serde_with_macros as serde_with;
+/// #[serde_with::apply(
+/// # crate="serde_with",
+/// Option => #[serde(skip_serializing_if = "Option::is_none")],
+/// )]
+/// #[derive(serde::Serialize)]
+/// struct Data {
+/// a: Option<String>,
+/// #[serde_with(skip_apply)]
+/// always_serialize_this_field: Option<u64>,
+/// c: Option<String>,
+/// d: Option<bool>,
+/// }
+///
+/// let data = Data {
+/// a: None,
+/// always_serialize_this_field: None,
+/// c: None,
+/// d: None,
+/// };
+///
+/// // serializes into this JSON:
+/// # assert_eq!(json!(
+/// {
+/// "always_serialize_this_field": null
+/// }
+/// # ), serde_json::to_value(&data).unwrap());
+/// ```
+///
+/// # Alternative path to `serde_with` crate
+///
+/// If `serde_with` is not available at the default path, its path should be specified with the
+/// `crate` argument. See [re-exporting `serde_as`] for more use case information.
+///
+/// ```rust,ignore
+/// #[serde_with::apply(
+/// crate = "::some_other_lib::serde_with"
+/// Option => #[serde(skip_serializing_if = "Option::is_none")],
+/// )]
+/// #[derive(serde::Serialize)]
+/// struct Data {
+/// a: Option<String>,
+/// b: Option<u64>,
+/// c: Option<String>,
+/// d: Option<bool>,
+/// }
+/// ```
+#[proc_macro_attribute]
+pub fn apply(args: TokenStream, input: TokenStream) -> TokenStream {
+ apply::apply(args, input)
+}
diff --git a/third_party/rust/serde_with_macros/src/utils.rs b/third_party/rust/serde_with_macros/src/utils.rs
new file mode 100644
index 0000000000..068cbce6ed
--- /dev/null
+++ b/third_party/rust/serde_with_macros/src/utils.rs
@@ -0,0 +1,77 @@
+use core::iter::Iterator;
+use darling::FromDeriveInput;
+use proc_macro::TokenStream;
+use proc_macro2::TokenStream as TokenStream2;
+use quote::ToTokens;
+use syn::{parse_quote, Error, Generics, Path, TypeGenerics};
+
+/// Merge multiple [`syn::Error`] into one.
+pub(crate) trait IteratorExt {
+ fn collect_error(self) -> Result<(), Error>
+ where
+ Self: Iterator<Item = Result<(), Error>> + Sized,
+ {
+ let accu = Ok(());
+ self.fold(accu, |accu, error| match (accu, error) {
+ (Ok(()), error) => error,
+ (accu, Ok(())) => accu,
+ (Err(mut err), Err(error)) => {
+ err.combine(error);
+ Err(err)
+ }
+ })
+ }
+}
+impl<I> IteratorExt for I where I: Iterator<Item = Result<(), Error>> + Sized {}
+
+/// Attributes usable for derive macros
+#[derive(FromDeriveInput)]
+#[darling(attributes(serde_with))]
+pub(crate) struct DeriveOptions {
+ /// Path to the crate
+ #[darling(rename = "crate", default)]
+ pub(crate) alt_crate_path: Option<Path>,
+}
+
+impl DeriveOptions {
+ pub(crate) fn from_derive_input(input: &syn::DeriveInput) -> Result<Self, TokenStream> {
+ match <Self as FromDeriveInput>::from_derive_input(input) {
+ Ok(v) => Ok(v),
+ Err(e) => Err(TokenStream::from(e.write_errors())),
+ }
+ }
+
+ pub(crate) fn get_serde_with_path(&self) -> Path {
+ self.alt_crate_path
+ .clone()
+ .unwrap_or_else(|| syn::parse_str("::serde_with").unwrap())
+ }
+}
+
+// Inspired by https://github.com/serde-rs/serde/blob/fb2fe409c8f7ad6c95e3096e5e9ede865c8cfb49/serde_derive/src/de.rs#L3120
+// Serde is also licensed Apache 2 + MIT
+pub(crate) fn split_with_de_lifetime(
+ generics: &Generics,
+) -> (
+ DeImplGenerics<'_>,
+ TypeGenerics<'_>,
+ Option<&syn::WhereClause>,
+) {
+ let de_impl_generics = DeImplGenerics(generics);
+ let (_, ty_generics, where_clause) = generics.split_for_impl();
+ (de_impl_generics, ty_generics, where_clause)
+}
+
+pub(crate) struct DeImplGenerics<'a>(&'a Generics);
+
+impl<'a> ToTokens for DeImplGenerics<'a> {
+ fn to_tokens(&self, tokens: &mut TokenStream2) {
+ let mut generics = self.0.clone();
+ generics.params = Some(parse_quote!('de))
+ .into_iter()
+ .chain(generics.params)
+ .collect();
+ let (impl_generics, _, _) = generics.split_for_impl();
+ impl_generics.to_tokens(tokens);
+ }
+}
diff --git a/third_party/rust/serde_with_macros/tests/apply.rs b/third_party/rust/serde_with_macros/tests/apply.rs
new file mode 100644
index 0000000000..33b721325d
--- /dev/null
+++ b/third_party/rust/serde_with_macros/tests/apply.rs
@@ -0,0 +1,247 @@
+#![allow(dead_code)]
+
+use expect_test::expect;
+use serde_with_macros::apply;
+use std::collections::BTreeMap;
+
+/// Fields `a` and `c` match, as each has a fully specified pattern.
+#[test]
+fn test_apply_fully_specified() {
+ #[apply(
+ crate="serde_with_macros",
+
+ Option<String> => #[serde(skip)],
+ BTreeMap<String, String> => #[serde(skip)],
+)]
+ #[derive(Default, serde::Serialize)]
+ struct FooBar<'a> {
+ a: Option<String>,
+ b: Option<i32>,
+ c: BTreeMap<String, String>,
+ d: BTreeMap<String, i32>,
+ e: BTreeMap<i32, String>,
+ f: &'a str,
+ g: &'static str,
+
+ #[serde_with(skip_apply)]
+ skip: Option<String>,
+ }
+
+ expect![[r#"
+ {
+ "b": null,
+ "d": {},
+ "e": {},
+ "f": "",
+ "g": "",
+ "skip": null
+ }"#]]
+ .assert_eq(&serde_json::to_string_pretty(&FooBar::<'static>::default()).unwrap());
+}
+
+/// All fields match as `_` matches any type.
+///
+/// The `skip` field is ignored because of the `#[serde_with(skip_apply)]` attribute.
+#[test]
+fn test_apply_all() {
+ #[apply(
+ crate="serde_with_macros",
+
+ _ => #[serde(skip)],
+)]
+ #[derive(Default, serde::Serialize)]
+ struct FooBar<'a> {
+ a: Option<String>,
+ b: Option<i32>,
+ c: BTreeMap<String, String>,
+ d: BTreeMap<String, i32>,
+ e: BTreeMap<i32, String>,
+ f: &'a str,
+ g: &'static str,
+
+ #[serde_with(skip_apply)]
+ skip: Option<String>,
+ }
+
+ expect![[r#"
+ {
+ "skip": null
+ }"#]]
+ .assert_eq(&serde_json::to_string_pretty(&FooBar::<'static>::default()).unwrap());
+}
+
+/// Fields `a` and `b` match, since both are variants of `Option`.
+///
+/// No generic in the pattern allows matching with any number of generics on the fields.
+/// The `skip` field is ignored because of the `#[serde_with(skip_apply)]` attribute.
+#[test]
+fn test_apply_partial_no_generic() {
+ #[apply(
+ crate="serde_with_macros",
+
+ Option => #[serde(skip)],
+)]
+ #[derive(Default, serde::Serialize)]
+ struct FooBar<'a> {
+ a: Option<String>,
+ b: Option<i32>,
+ c: BTreeMap<String, String>,
+ d: BTreeMap<String, i32>,
+ e: BTreeMap<i32, String>,
+ f: &'a str,
+ g: &'static str,
+
+ #[serde_with(skip_apply)]
+ skip: Option<String>,
+ }
+
+ expect![[r#"
+ {
+ "c": {},
+ "d": {},
+ "e": {},
+ "f": "",
+ "g": "",
+ "skip": null
+ }"#]]
+ .assert_eq(&serde_json::to_string_pretty(&FooBar::<'static>::default()).unwrap());
+}
+
+/// Fields `c` and `d` match, as both have a `String` key and `_` matches any type.
+#[test]
+fn test_apply_partial_generic() {
+ #[apply(
+ crate="serde_with_macros",
+
+ BTreeMap<String, _> => #[serde(skip)],
+)]
+ #[derive(Default, serde::Serialize)]
+ struct FooBar<'a> {
+ a: Option<String>,
+ b: Option<i32>,
+ c: BTreeMap<String, String>,
+ d: BTreeMap<String, i32>,
+ e: BTreeMap<i32, String>,
+ f: &'a str,
+ g: &'static str,
+
+ #[serde_with(skip_apply)]
+ skip: Option<String>,
+ }
+
+ expect![[r#"
+ {
+ "a": null,
+ "b": null,
+ "e": {},
+ "f": "",
+ "g": "",
+ "skip": null
+ }"#]]
+ .assert_eq(&serde_json::to_string_pretty(&FooBar::<'static>::default()).unwrap());
+}
+
+/// Fields `f` and `g` match, since no lifetime matches any reference.
+#[test]
+fn test_apply_no_lifetime() {
+ #[apply(
+ crate="serde_with_macros",
+
+ &str => #[serde(skip)],
+)]
+ #[derive(Default, serde::Serialize)]
+ struct FooBar<'a> {
+ a: Option<String>,
+ b: Option<i32>,
+ c: BTreeMap<String, String>,
+ d: BTreeMap<String, i32>,
+ e: BTreeMap<i32, String>,
+ f: &'a str,
+ g: &'static str,
+
+ #[serde_with(skip_apply)]
+ skip: Option<String>,
+ }
+
+ expect![[r#"
+ {
+ "a": null,
+ "b": null,
+ "c": {},
+ "d": {},
+ "e": {},
+ "skip": null
+ }"#]]
+ .assert_eq(&serde_json::to_string_pretty(&FooBar::<'static>::default()).unwrap());
+}
+
+/// Field `f` matches as the lifetime is identical and `mut` is ignored.
+#[test]
+fn test_apply_lifetime() {
+ #[apply(
+ crate="serde_with_macros",
+
+ &'a mut str => #[serde(skip)],
+)]
+ #[derive(Default, serde::Serialize)]
+ struct FooBar<'a> {
+ a: Option<String>,
+ b: Option<i32>,
+ c: BTreeMap<String, String>,
+ d: BTreeMap<String, i32>,
+ e: BTreeMap<i32, String>,
+ f: &'a str,
+ g: &'static str,
+
+ #[serde_with(skip_apply)]
+ skip: Option<String>,
+ }
+
+ expect![[r#"
+ {
+ "a": null,
+ "b": null,
+ "c": {},
+ "d": {},
+ "e": {},
+ "g": "",
+ "skip": null
+ }"#]]
+ .assert_eq(&serde_json::to_string_pretty(&FooBar::<'static>::default()).unwrap());
+}
+
+/// No field matches as the explicit lifetimes are different
+#[test]
+fn test_apply_mismatched_lifetime() {
+ #[apply(
+ crate="serde_with_macros",
+
+ &'b str => #[serde(skip)],
+)]
+ #[derive(Default, serde::Serialize)]
+ struct FooBar<'a> {
+ a: Option<String>,
+ b: Option<i32>,
+ c: BTreeMap<String, String>,
+ d: BTreeMap<String, i32>,
+ e: BTreeMap<i32, String>,
+ f: &'a str,
+ g: &'static str,
+
+ #[serde_with(skip_apply)]
+ skip: Option<String>,
+ }
+
+ expect![[r#"
+ {
+ "a": null,
+ "b": null,
+ "c": {},
+ "d": {},
+ "e": {},
+ "f": "",
+ "g": "",
+ "skip": null
+ }"#]]
+ .assert_eq(&serde_json::to_string_pretty(&FooBar::<'static>::default()).unwrap());
+}
diff --git a/third_party/rust/serde_with_macros/tests/compiler-messages.rs b/third_party/rust/serde_with_macros/tests/compiler-messages.rs
new file mode 100644
index 0000000000..bbb16c32d6
--- /dev/null
+++ b/third_party/rust/serde_with_macros/tests/compiler-messages.rs
@@ -0,0 +1,9 @@
+#[cfg_attr(tarpaulin, ignore)]
+// The error messages are different on beta and nightly, thus breaking the test.
+#[rustversion::attr(beta, ignore)]
+#[rustversion::attr(nightly, ignore)]
+#[test]
+fn compile_test() {
+ let t = trybuild::TestCases::new();
+ t.compile_fail("tests/compile-fail/*.rs");
+}
diff --git a/third_party/rust/serde_with_macros/tests/serde_as_issue_267.rs b/third_party/rust/serde_with_macros/tests/serde_as_issue_267.rs
new file mode 100644
index 0000000000..2db1bbea00
--- /dev/null
+++ b/third_party/rust/serde_with_macros/tests/serde_as_issue_267.rs
@@ -0,0 +1,9 @@
+use serde::Serialize;
+use serde_with_macros::serde_as;
+
+// The field has no serde_as annotation and should not trigger any error
+#[serde_as(crate = "serde_with_macros")]
+#[derive(Serialize)]
+pub struct Thing {
+ pub id: u8,
+}
diff --git a/third_party/rust/serde_with_macros/tests/serde_as_issue_538.rs b/third_party/rust/serde_with_macros/tests/serde_as_issue_538.rs
new file mode 100644
index 0000000000..2ac2f08cc8
--- /dev/null
+++ b/third_party/rust/serde_with_macros/tests/serde_as_issue_538.rs
@@ -0,0 +1,30 @@
+//! Check for the correct processing of ExprGroups in types
+//!
+//! They occur when the types is passed in as a macro_rules argument like here.
+//! https://github.com/jonasbb/serde_with/issues/538
+
+macro_rules! t {
+ ($($param:ident : $ty:ty),*) => {
+ #[derive(Default)]
+ #[serde_with_macros::apply(
+ crate = "serde_with_macros",
+ Option => #[serde(skip_serializing_if = "Option::is_none")],
+ )]
+ #[derive(serde::Serialize)]
+ struct Data {
+ a: Option<String>,
+ b: Option<u64>,
+ c: Option<String>,
+ $(pub $param: $ty),*
+ }
+ }
+}
+
+t!(d: Option<bool>);
+
+#[test]
+fn t() {
+ let expected = r#"{}"#;
+ let data: Data = Default::default();
+ assert_eq!(expected, serde_json::to_string(&data).unwrap());
+}
diff --git a/third_party/rust/serde_with_macros/tests/skip_serializing_null.rs b/third_party/rust/serde_with_macros/tests/skip_serializing_null.rs
new file mode 100644
index 0000000000..53412ef1c7
--- /dev/null
+++ b/third_party/rust/serde_with_macros/tests/skip_serializing_null.rs
@@ -0,0 +1,149 @@
+use pretty_assertions::assert_eq;
+use serde::{Deserialize, Serialize};
+use serde_json::json;
+use serde_with_macros::skip_serializing_none;
+
+macro_rules! test {
+ ($fn:ident, $struct:ident) => {
+ #[test]
+ fn $fn() {
+ let expected = json!({});
+ let data = $struct {
+ a: None,
+ b: None,
+ c: None,
+ d: None,
+ };
+ let res = serde_json::to_value(&data).unwrap();
+ assert_eq!(expected, res);
+ assert_eq!(data, serde_json::from_value(res).unwrap());
+ }
+ };
+}
+
+macro_rules! test_tuple {
+ ($fn:ident, $struct:ident) => {
+ #[test]
+ fn $fn() {
+ let expected = json!([]);
+ let data = $struct(None, None);
+ let res = serde_json::to_value(&data).unwrap();
+ assert_eq!(expected, res);
+ }
+ };
+}
+
+#[skip_serializing_none]
+#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
+struct DataBasic {
+ a: Option<String>,
+ b: Option<String>,
+ c: Option<String>,
+ d: Option<String>,
+}
+test!(test_basic, DataBasic);
+
+#[skip_serializing_none]
+#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
+struct DataFullyQualified {
+ a: ::std::option::Option<String>,
+ b: std::option::Option<String>,
+ c: ::std::option::Option<i64>,
+ d: core::option::Option<String>,
+}
+test!(test_fully_qualified, DataFullyQualified);
+
+fn never<T>(_t: &T) -> bool {
+ false
+}
+
+#[skip_serializing_none]
+#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
+struct DataExistingAnnotation {
+ #[serde(skip_serializing_if = "Option::is_none")]
+ a: Option<String>,
+ #[serde(default, skip_serializing_if = "Option::is_none", rename = "abc")]
+ b: Option<String>,
+ #[serde(default)]
+ c: Option<String>,
+ #[serde(skip_serializing_if = "never")]
+ #[serde(rename = "name")]
+ d: Option<String>,
+}
+
+#[test]
+fn test_existing_annotation() {
+ let expected = json!({ "name": null });
+ let data = DataExistingAnnotation {
+ a: None,
+ b: None,
+ c: None,
+ d: None,
+ };
+ let res = serde_json::to_value(&data).unwrap();
+ assert_eq!(expected, res);
+ assert_eq!(data, serde_json::from_value(res).unwrap());
+}
+
+#[skip_serializing_none]
+#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
+struct DataSerializeAlways {
+ #[serialize_always]
+ a: Option<String>,
+ #[serialize_always]
+ b: Option<String>,
+ c: i64,
+ #[serialize_always]
+ d: Option<String>,
+}
+
+#[test]
+fn test_serialize_always() {
+ let expected = json!({
+ "a": null,
+ "b": null,
+ "c": 0,
+ "d": null
+ });
+ let data = DataSerializeAlways {
+ a: None,
+ b: None,
+ c: 0,
+ d: None,
+ };
+ let res = serde_json::to_value(&data).unwrap();
+ assert_eq!(expected, res);
+ assert_eq!(data, serde_json::from_value(res).unwrap());
+}
+
+#[skip_serializing_none]
+#[derive(Debug, Eq, PartialEq, Serialize)]
+struct DataTuple(Option<String>, std::option::Option<String>);
+test_tuple!(test_tuple, DataTuple);
+
+#[skip_serializing_none]
+#[derive(Debug, Eq, PartialEq, Serialize)]
+enum DataEnum {
+ Tuple(Option<i64>, std::option::Option<bool>),
+ Struct {
+ a: Option<String>,
+ b: Option<String>,
+ },
+}
+
+#[test]
+fn test_enum() {
+ let expected = json!({
+ "Tuple": []
+ });
+ let data = DataEnum::Tuple(None, None);
+ let res = serde_json::to_value(data).unwrap();
+ assert_eq!(expected, res);
+
+ let expected = json!({
+ "Struct": {}
+ });
+ let data = DataEnum::Struct { a: None, b: None };
+ let res = serde_json::to_value(data).unwrap();
+ assert_eq!(expected, res);
+}
diff --git a/third_party/rust/serde_with_macros/tests/version_numbers.rs b/third_party/rust/serde_with_macros/tests/version_numbers.rs
new file mode 100644
index 0000000000..35560b024b
--- /dev/null
+++ b/third_party/rust/serde_with_macros/tests/version_numbers.rs
@@ -0,0 +1,21 @@
+// Needed to supress a 2021 incompatability warning in the macro generated code
+// The non_fmt_panic lint is not yet available on most Rust versions
+#![allow(unknown_lints, non_fmt_panics)]
+
+#[test]
+fn test_html_root_url() {
+ version_sync::assert_html_root_url_updated!("src/lib.rs");
+}
+
+#[test]
+fn test_changelog() {
+ version_sync::assert_contains_regex!("CHANGELOG.md", r#"## \[{version}\]"#);
+}
+
+#[test]
+fn test_serde_with_dependency() {
+ version_sync::assert_contains_regex!(
+ "../serde_with/Cargo.toml",
+ r#"^serde_with_macros = .*? version = "={version}""#
+ );
+}