summaryrefslogtreecommitdiffstats
path: root/third_party/rust/serde_with
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/serde_with')
-rw-r--r--third_party/rust/serde_with/.cargo-checksum.json1
-rw-r--r--third_party/rust/serde_with/CHANGELOG.md117
-rw-r--r--third_party/rust/serde_with/Cargo.toml73
-rw-r--r--third_party/rust/serde_with/LICENSE-APACHE201
-rw-r--r--third_party/rust/serde_with/LICENSE-MIT25
-rw-r--r--third_party/rust/serde_with/README.md80
-rw-r--r--third_party/rust/serde_with/src/chrono.rs160
-rw-r--r--third_party/rust/serde_with/src/duplicate_key_impls/error_on_duplicate.rs86
-rw-r--r--third_party/rust/serde_with/src/duplicate_key_impls/first_value_wins.rs104
-rw-r--r--third_party/rust/serde_with/src/duplicate_key_impls/mod.rs7
-rw-r--r--third_party/rust/serde_with/src/flatten_maybe.rs86
-rw-r--r--third_party/rust/serde_with/src/json.rs88
-rw-r--r--third_party/rust/serde_with/src/lib.rs140
-rw-r--r--third_party/rust/serde_with/src/rust.rs1534
-rw-r--r--third_party/rust/serde_with/src/with_prefix.rs607
-rw-r--r--third_party/rust/serde_with/tests/chrono.rs53
-rw-r--r--third_party/rust/serde_with/tests/rust.rs573
-rw-r--r--third_party/rust/serde_with/tests/version_numbers.rs20
-rw-r--r--third_party/rust/serde_with/tests/with_prefix.rs130
19 files changed, 4085 insertions, 0 deletions
diff --git a/third_party/rust/serde_with/.cargo-checksum.json b/third_party/rust/serde_with/.cargo-checksum.json
new file mode 100644
index 0000000000..4eeae6822f
--- /dev/null
+++ b/third_party/rust/serde_with/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CHANGELOG.md":"cc6d02ac64ef3a405c8755730d7ac83311776faacfb5ac97679017faed7a9322","Cargo.toml":"d8d8ebb20c9ab9364bd4c34396475e9287a0f7e0a290acc3f1b3cadc10486e6f","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7576269ea71f767b99297934c0b2367532690f8c4badc695edf8e04ab6a1e545","README.md":"dc4c1547049c0d11d544b1347aa67f4d947d761842c373729c2014dbb337e70b","src/chrono.rs":"0ac03930e4dff3f404f1dac33e4135eb0eb860156d6986665e6f9c8be933a9c7","src/duplicate_key_impls/error_on_duplicate.rs":"5f1809d1e0285953720cb5872ad3ef30aeadab8baacf064de7afd02d492641d8","src/duplicate_key_impls/first_value_wins.rs":"c766668a3831eb808ba5b995677b266924617fcc07dd103840595eb1d16fd92d","src/duplicate_key_impls/mod.rs":"10aa3b346c0637ff944545d4875844fe71db3ba19dce4f78c0e6d5052b1cdc81","src/flatten_maybe.rs":"5cdb868eca2f43494440150942ba6995e94eed9e194322d7bdcf1e85d9a20d8c","src/json.rs":"33e3a48200e5d9537ca7f5fffc9c58e07836ba8e85d910ecb80abc246da888dd","src/lib.rs":"eb1aa53d0c04c5b1156a0588938ece37913e3c5038c1e646d6e042827ccce6c9","src/rust.rs":"de4a4f9beed67640b358c6b1ff4454c0de59aedbd7633c54a69cb121e0dfdd56","src/with_prefix.rs":"6d168b0f0034b314c1475cc1f7e89ebb9b6c3f130a2a40169a4ae37f213a7198","tests/chrono.rs":"d038fc0ea9f8cc8870e0148ad4327f9ddca0733510a4b20dd9ac449bc8e0d180","tests/rust.rs":"ac3de3639778ea5c99397386c92108ff9cfb4fb009c0d8d4fa5784711da8756a","tests/version_numbers.rs":"1920c271c281db116ca674e6a6bde4e1c09289d48f577f4f9a331ff5ce3cfa42","tests/with_prefix.rs":"c1bc8bf95d717f7becc73468d580add8e29f8a876ea3f040c09520c8bc4bc9c0"},"package":"89d3d595d64120bbbc70b7f6d5ae63298b62a3d9f373ec2f56acf5365ca8a444"} \ No newline at end of file
diff --git a/third_party/rust/serde_with/CHANGELOG.md b/third_party/rust/serde_with/CHANGELOG.md
new file mode 100644
index 0000000000..99119e5e37
--- /dev/null
+++ b/third_party/rust/serde_with/CHANGELOG.md
@@ -0,0 +1,117 @@
+# 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]
+
+### Added
+
+* Add a helper to deserialize a `Vec<u8>` from `String` (#35)
+* Add `default_on_error` helper, which turns errors into `Default`s of the type
+* Add `default_on_null` helper, which turns `null` values into `Default`s of the type
+
+### Changed
+
+* Bump minimal Rust version to 1.36.0
+ * Support Rust Edition 2018
+ * version-sync depends on smallvec which requires 1.36
+* Improved CI pipeline by running `cargo audit` and `tarpaulin` in all configurations now.
+
+## [1.3.1]
+
+### Fixed
+
+* Use `serde_with_macros` with proper dependencies specified.
+
+## [1.3.0]
+
+### Added
+
+* Add `skip_serializing_none` attribute, which adds `#[serde(skip_serializing_if = "Option::is_none")]` for each Option in a struct.
+ This is helpfull 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.
+
+## [1.2.0]
+
+### Added
+
+* Add macro helper to support deserializing values with nested or flattened syntax #38
+* Serialize tuple list as map helper
+
+### Changed
+
+* Bumped minimal Rust version to 1.30.0
+
+## [1.1.0]
+
+### Added
+
+* Serialize HashMap/BTreeMap as list of tuples
+
+## [1.0.0]
+
+### Added
+
+* No changes in this release.
+* Bumped version number to indicate the stability of the library.
+
+## [0.2.5]
+
+### Added
+
+* Helper which deserializes an empty string as `None` and otherwise uses `FromStr` and `AsRef<str>`.
+
+## [0.2.4]
+
+### Added
+
+* De/Serialize sequences by using `Display` and `FromStr` implementations on each element. Contributed by @katyo
+
+## [0.2.3]
+
+### Added
+
+* Add missing docs and enable deny missing_docs
+* Add badges to Cargo.toml and crates.io
+
+### Changed
+
+* Improve Travis configuration
+* Various clippy improvements
+
+## [0.2.2]
+
+### Added
+
+* `unwrap_or_skip` allows to transparently serialize the inner part of a `Some(T)`
+* Add deserialization helpser for sets and maps, inspired by [comment](https://github.com/serde-rs/serde/issues/553#issuecomment-299711855)
+ * Create an error if duplicate values for a set are detected
+ * Create an error if duplicate keys for a map are detected
+ * Implement a first-value wins strategy for sets/maps. This is different to serde's default
+ which implements a last value wins strategy.
+
+## [0.2.1]
+
+### Added
+
+* Double Option pattern to differentiate between missing, unset, or existing value
+* `with_prefix!` macro, which puts a prefix on every struct field
+
+## [0.2.0]
+
+### Added
+
+* Add chrono support: Deserialize timestamps from int, float, and string
+* Serialization of embedded JSON strings
+* De/Serialization using `Display` and `FromStr` implementations
+* String-based collections using `Display` and `FromStr`, allows to deserialize "#foo,#bar"
+
+## [0.1.0]
+
+### Added
+
+* Reserve name on crates.io
diff --git a/third_party/rust/serde_with/Cargo.toml b/third_party/rust/serde_with/Cargo.toml
new file mode 100644
index 0000000000..26a7ce2a6b
--- /dev/null
+++ b/third_party/rust/serde_with/Cargo.toml
@@ -0,0 +1,73 @@
+# 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 believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+name = "serde_with"
+version = "1.4.0"
+authors = ["jonasbb"]
+exclude = [".codecov.yml", ".gitignore", ".pre-commit-config.yaml", ".travis.yml", "bors.toml", "README.tpl", "rustfmt.toml"]
+description = "Custom de/serialization functions for Rust's serde"
+documentation = "https://docs.rs/serde_with/"
+readme = "README.md"
+keywords = ["serde", "utilities", "serialization", "deserialization"]
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/jonasbb/serde_with"
+[package.metadata.docs.rs]
+all-features = true
+[dependencies.chrono]
+version = "0.4.1"
+features = ["serde"]
+optional = true
+
+[dependencies.serde]
+version = "1.0.75"
+
+[dependencies.serde_json]
+version = "1.0.1"
+optional = true
+
+[dependencies.serde_with_macros]
+version = "1.1.0"
+optional = true
+[dev-dependencies.fnv]
+version = "1.0.6"
+
+[dev-dependencies.pretty_assertions]
+version = "0.6.1"
+
+[dev-dependencies.ron]
+version = ">=0.3.0, <0.6"
+
+[dev-dependencies.serde_derive]
+version = "1.0.75"
+
+[dev-dependencies.serde_json]
+version = "1.0.25"
+
+[dev-dependencies.version-sync]
+version = "0.8.1"
+
+[features]
+default = ["macros"]
+json = ["serde_json"]
+macros = ["serde_with_macros"]
+[badges.codecov]
+branch = "master"
+repository = "jonasbb/serde_with"
+service = "github"
+
+[badges.maintenance]
+status = "actively-developed"
+
+[badges.travis-ci]
+branch = "master"
+repository = "jonasbb/serde_with"
diff --git a/third_party/rust/serde_with/LICENSE-APACHE b/third_party/rust/serde_with/LICENSE-APACHE
new file mode 100644
index 0000000000..16fe87b06e
--- /dev/null
+++ b/third_party/rust/serde_with/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/LICENSE-MIT b/third_party/rust/serde_with/LICENSE-MIT
new file mode 100644
index 0000000000..9203baa055
--- /dev/null
+++ b/third_party/rust/serde_with/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/README.md b/third_party/rust/serde_with/README.md
new file mode 100644
index 0000000000..ac02301fe9
--- /dev/null
+++ b/third_party/rust/serde_with/README.md
@@ -0,0 +1,80 @@
+# Custom de/serialization functions for Rust's [serde](https://serde.rs)
+
+[![docs.rs badge](https://docs.rs/serde_with/badge.svg)](https://docs.rs/serde_with/)
+[![crates.io badge](https://img.shields.io/crates/v/serde_with.svg)](https://crates.io/crates/serde_with/)
+[![Build Status](https://travis-ci.org/jonasbb/serde_with.svg?branch=master)](https://travis-ci.org/jonasbb/serde_with)
+[![codecov](https://codecov.io/gh/jonasbb/serde_with/branch/master/graph/badge.svg)](https://codecov.io/gh/jonasbb/serde_with)
+
+---
+
+This crate provides custom de/serialization helpers to use in combination with [serde's with-annotation][with-annotation].
+
+Serde tracks a wishlist of similar helpers at [serde#553].
+
+## Usage
+
+Add this to your `Cargo.toml`:
+
+```toml
+[dependencies.serde_with]
+version = "1.4.0"
+features = [ "..." ]
+```
+
+The crate is divided into different modules.
+They contain helpers for external crates and must be enabled with the correspondig feature.
+
+Annotate your struct or enum to enable the custom de/serializer.
+
+```rust
+#[derive(Deserialize, Serialize)]
+struct Foo {
+ #[serde(with = "serde_with::rust::display_fromstr")]
+ bar: u8,
+}
+```
+
+Most helpers implement both deserialize and serialize.
+If you do not want to derive both, you can simply derive only the necessary parts.
+If you want to mix different helpers, you can write your annotations like
+
+```rust
+#[derive(Deserialize, Serialize)]
+struct Foo {
+ #[serde(
+ deserialize_with = "serde_with::rust::display_fromstr::deserialize",
+ serialize_with = "serde_with::json::nested::serialize"
+ )]
+ bar: u8,
+}
+```
+
+However, this will prohibit you from applying deserialize on the value returned by serializing a struct.
+
+## Attributes
+
+The crate comes with custom attributes, which futher extend how serde serialization can be customized.
+They are enabled by default, but can be disabled, by removing the default features from this crate.
+
+The `serde_with` crate re-exports all items from `serde_with_macros`.
+This means, if you want to use any proc_macros, import them like `use serde_with::skip_serializing_none`.
+
+[The documentation for the custom attributes can be found here.](serde_with_macros)
+
+[with-annotation]: https://serde.rs/field-attrs.html#serdewith--module
+[serde#553]: https://github.com/serde-rs/serde/issues/553
+
+## 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
+
+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.
diff --git a/third_party/rust/serde_with/src/chrono.rs b/third_party/rust/serde_with/src/chrono.rs
new file mode 100644
index 0000000000..ea0118d798
--- /dev/null
+++ b/third_party/rust/serde_with/src/chrono.rs
@@ -0,0 +1,160 @@
+//! De/Serialization of [chrono][] types
+//!
+//! This modules is only available if using the `chrono` feature of the crate.
+//!
+//! [chrono]: https://docs.rs/chrono/
+
+/// Deserialize a Unix timestamp with optional subsecond precision into a `DateTime<Utc>`.
+///
+/// The `DateTime<Utc>` can be serialized from an integer, a float, or a string representing a number.
+///
+/// # Examples
+///
+/// ```
+/// # extern crate chrono;
+/// # extern crate serde;
+/// # extern crate serde_derive;
+/// # extern crate serde_json;
+/// # extern crate serde_with;
+/// #
+/// # use chrono::{DateTime, Utc};
+/// # use serde_derive::{Deserialize, Serialize};
+/// #
+/// #[derive(Debug, Deserialize)]
+/// struct S {
+/// #[serde(with = "serde_with::chrono::datetime_utc_ts_seconds_from_any")]
+/// date: DateTime<Utc>,
+/// }
+///
+/// // Deserializes integers
+/// assert!(serde_json::from_str::<S>(r#"{ "date": 1478563200 }"#).is_ok());
+/// // floats
+/// assert!(serde_json::from_str::<S>(r#"{ "date": 1478563200.123 }"#).is_ok());
+/// // and strings with numbers, for high-precision values
+/// assert!(serde_json::from_str::<S>(r#"{ "date": "1478563200.123" }"#).is_ok());
+/// ```
+///
+pub mod datetime_utc_ts_seconds_from_any {
+ use chrono_crate::{DateTime, NaiveDateTime, Utc};
+ use serde::de::{Deserializer, Error, Unexpected, Visitor};
+
+ /// Deserialize a Unix timestamp with optional subsecond precision into a `DateTime<Utc>`.
+ pub fn deserialize<'de, D>(deserializer: D) -> Result<DateTime<Utc>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct Helper;
+ impl<'de> Visitor<'de> for Helper {
+ type Value = DateTime<Utc>;
+
+ fn expecting(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+ formatter.write_str("Invalid timestamp. Must be an integer, float, or string with optional subsecond precision.")
+ }
+
+ fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ let ndt = NaiveDateTime::from_timestamp_opt(value, 0);
+ if let Some(ndt) = ndt {
+ Ok(DateTime::<Utc>::from_utc(ndt, Utc))
+ } else {
+ Err(Error::custom(format!(
+ "Invalid or out of range value '{}' for DateTime",
+ value
+ )))
+ }
+ }
+
+ fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ let ndt = NaiveDateTime::from_timestamp_opt(value as i64, 0);
+ if let Some(ndt) = ndt {
+ Ok(DateTime::<Utc>::from_utc(ndt, Utc))
+ } else {
+ Err(Error::custom(format!(
+ "Invalid or out of range value '{}' for DateTime",
+ value
+ )))
+ }
+ }
+
+ fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ let seconds = value.trunc() as i64;
+ let nsecs = (value.fract() * 1_000_000_000_f64).abs() as u32;
+ let ndt = NaiveDateTime::from_timestamp_opt(seconds, nsecs);
+ if let Some(ndt) = ndt {
+ Ok(DateTime::<Utc>::from_utc(ndt, Utc))
+ } else {
+ Err(Error::custom(format!(
+ "Invalid or out of range value '{}' for DateTime",
+ value
+ )))
+ }
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ let parts: Vec<_> = value.split('.').collect();
+
+ match *parts.as_slice() {
+ [seconds] => {
+ if let Ok(seconds) = i64::from_str_radix(seconds, 10) {
+ let ndt = NaiveDateTime::from_timestamp_opt(seconds, 0);
+ if let Some(ndt) = ndt {
+ Ok(DateTime::<Utc>::from_utc(ndt, Utc))
+ } else {
+ Err(Error::custom(format!(
+ "Invalid or out of range value '{}' for DateTime",
+ value
+ )))
+ }
+ } else {
+ Err(Error::invalid_value(Unexpected::Str(value), &self))
+ }
+ }
+ [seconds, subseconds] => {
+ if let Ok(seconds) = i64::from_str_radix(seconds, 10) {
+ let subseclen = subseconds.chars().count() as u32;
+ if subseclen > 9 {
+ return Err(Error::custom(format!(
+ "DateTimes only support nanosecond precision but '{}' has more than 9 digits.",
+ value
+ )));
+ }
+
+ if let Ok(mut subseconds) = u32::from_str_radix(subseconds, 10) {
+ // convert subseconds to nanoseconds (10^-9), require 9 places for nanoseconds
+ subseconds *= 10u32.pow(9 - subseclen);
+ let ndt = NaiveDateTime::from_timestamp_opt(seconds, subseconds);
+ if let Some(ndt) = ndt {
+ Ok(DateTime::<Utc>::from_utc(ndt, Utc))
+ } else {
+ Err(Error::custom(format!(
+ "Invalid or out of range value '{}' for DateTime",
+ value
+ )))
+ }
+ } else {
+ Err(Error::invalid_value(Unexpected::Str(value), &self))
+ }
+ } else {
+ Err(Error::invalid_value(Unexpected::Str(value), &self))
+ }
+ }
+
+ _ => Err(Error::invalid_value(Unexpected::Str(value), &self)),
+ }
+ }
+ }
+
+ deserializer.deserialize_any(Helper)
+ }
+}
diff --git a/third_party/rust/serde_with/src/duplicate_key_impls/error_on_duplicate.rs b/third_party/rust/serde_with/src/duplicate_key_impls/error_on_duplicate.rs
new file mode 100644
index 0000000000..3fc08e8c57
--- /dev/null
+++ b/third_party/rust/serde_with/src/duplicate_key_impls/error_on_duplicate.rs
@@ -0,0 +1,86 @@
+use std::{
+ collections::{BTreeMap, BTreeSet, HashMap, HashSet},
+ hash::{BuildHasher, Hash},
+};
+
+pub trait PreventDuplicateInsertsSet<T> {
+ fn new(size_hint: Option<usize>) -> Self;
+
+ /// Return true if the insert was successful and the value did not exist in the set
+ fn insert(&mut self, value: T) -> bool;
+}
+
+pub trait PreventDuplicateInsertsMap<K, V> {
+ fn new(size_hint: Option<usize>) -> Self;
+
+ /// Return true if the insert was successful and the key did not exist in the map
+ fn insert(&mut self, key: K, value: V) -> bool;
+}
+
+impl<T, S> PreventDuplicateInsertsSet<T> for HashSet<T, S>
+where
+ T: Eq + Hash,
+ S: BuildHasher + Default,
+{
+ #[inline]
+ fn new(size_hint: Option<usize>) -> Self {
+ match size_hint {
+ Some(size) => Self::with_capacity_and_hasher(size, S::default()),
+ None => Self::with_hasher(S::default()),
+ }
+ }
+
+ #[inline]
+ fn insert(&mut self, value: T) -> bool {
+ self.insert(value)
+ }
+}
+
+impl<T> PreventDuplicateInsertsSet<T> for BTreeSet<T>
+where
+ T: Ord,
+{
+ #[inline]
+ fn new(_size_hint: Option<usize>) -> Self {
+ Self::new()
+ }
+
+ #[inline]
+ fn insert(&mut self, value: T) -> bool {
+ self.insert(value)
+ }
+}
+
+impl<K, V, S> PreventDuplicateInsertsMap<K, V> for HashMap<K, V, S>
+where
+ K: Eq + Hash,
+ S: BuildHasher + Default,
+{
+ #[inline]
+ fn new(size_hint: Option<usize>) -> Self {
+ match size_hint {
+ Some(size) => Self::with_capacity_and_hasher(size, S::default()),
+ None => Self::with_hasher(S::default()),
+ }
+ }
+
+ #[inline]
+ fn insert(&mut self, key: K, value: V) -> bool {
+ self.insert(key, value).is_none()
+ }
+}
+
+impl<K, V> PreventDuplicateInsertsMap<K, V> for BTreeMap<K, V>
+where
+ K: Ord,
+{
+ #[inline]
+ fn new(_size_hint: Option<usize>) -> Self {
+ Self::new()
+ }
+
+ #[inline]
+ fn insert(&mut self, key: K, value: V) -> bool {
+ self.insert(key, value).is_none()
+ }
+}
diff --git a/third_party/rust/serde_with/src/duplicate_key_impls/first_value_wins.rs b/third_party/rust/serde_with/src/duplicate_key_impls/first_value_wins.rs
new file mode 100644
index 0000000000..e60ee9227a
--- /dev/null
+++ b/third_party/rust/serde_with/src/duplicate_key_impls/first_value_wins.rs
@@ -0,0 +1,104 @@
+use std::{
+ collections::{BTreeMap, BTreeSet, HashMap, HashSet},
+ hash::{BuildHasher, Hash},
+};
+
+pub trait DuplicateInsertsFirstWinsSet<T> {
+ fn new(size_hint: Option<usize>) -> Self;
+
+ /// Insert the value into the set, if there is not already an existing value
+ fn insert(&mut self, value: T);
+}
+
+pub trait DuplicateInsertsFirstWinsMap<K, V> {
+ fn new(size_hint: Option<usize>) -> Self;
+
+ /// Insert the value into the map, if there is not already an existing value
+ fn insert(&mut self, key: K, value: V);
+}
+
+impl<T, S> DuplicateInsertsFirstWinsSet<T> for HashSet<T, S>
+where
+ T: Eq + Hash,
+ S: BuildHasher + Default,
+{
+ #[inline]
+ fn new(size_hint: Option<usize>) -> Self {
+ match size_hint {
+ Some(size) => Self::with_capacity_and_hasher(size, S::default()),
+ None => Self::with_hasher(S::default()),
+ }
+ }
+
+ #[inline]
+ fn insert(&mut self, value: T) {
+ // Hashset already fullfils the contract and always keeps the first value
+ self.insert(value);
+ }
+}
+
+impl<T> DuplicateInsertsFirstWinsSet<T> for BTreeSet<T>
+where
+ T: Ord,
+{
+ #[inline]
+ fn new(_size_hint: Option<usize>) -> Self {
+ Self::new()
+ }
+
+ #[inline]
+ fn insert(&mut self, value: T) {
+ // BTreeSet already fullfils the contract and always keeps the first value
+ self.insert(value);
+ }
+}
+
+impl<K, V, S> DuplicateInsertsFirstWinsMap<K, V> for HashMap<K, V, S>
+where
+ K: Eq + Hash,
+ S: BuildHasher + Default,
+{
+ #[inline]
+ fn new(size_hint: Option<usize>) -> Self {
+ match size_hint {
+ Some(size) => Self::with_capacity_and_hasher(size, S::default()),
+ None => Self::with_hasher(S::default()),
+ }
+ }
+
+ #[inline]
+ fn insert(&mut self, key: K, value: V) {
+ use std::collections::hash_map::Entry;
+
+ match self.entry(key) {
+ // we want to keep the first value, so do nothing
+ Entry::Occupied(_) => {}
+ Entry::Vacant(vacant) => {
+ vacant.insert(value);
+ }
+ }
+ }
+}
+
+impl<K, V> DuplicateInsertsFirstWinsMap<K, V> for BTreeMap<K, V>
+where
+ K: Ord,
+{
+ #[inline]
+ fn new(_size_hint: Option<usize>) -> Self {
+ Self::new()
+ }
+
+ #[inline]
+ fn insert(&mut self, key: K, value: V) {
+ use std::collections::btree_map::Entry;
+
+ match self.entry(key) {
+ // we want to keep the first value, so do nothing
+ Entry::Occupied(_) => {}
+ Entry::Vacant(vacant) => {
+ vacant.insert(value);
+ }
+ }
+ }
+}
diff --git a/third_party/rust/serde_with/src/duplicate_key_impls/mod.rs b/third_party/rust/serde_with/src/duplicate_key_impls/mod.rs
new file mode 100644
index 0000000000..e433baa0ac
--- /dev/null
+++ b/third_party/rust/serde_with/src/duplicate_key_impls/mod.rs
@@ -0,0 +1,7 @@
+mod error_on_duplicate;
+mod first_value_wins;
+
+pub use self::{
+ error_on_duplicate::{PreventDuplicateInsertsMap, PreventDuplicateInsertsSet},
+ first_value_wins::{DuplicateInsertsFirstWinsMap, DuplicateInsertsFirstWinsSet},
+};
diff --git a/third_party/rust/serde_with/src/flatten_maybe.rs b/third_party/rust/serde_with/src/flatten_maybe.rs
new file mode 100644
index 0000000000..6ea64ed4fd
--- /dev/null
+++ b/third_party/rust/serde_with/src/flatten_maybe.rs
@@ -0,0 +1,86 @@
+/// Support deserializing from flattened and non-flattened representation
+///
+/// When working with different serialization formats, sometimes it is more idiomatic to flatten
+/// fields, while other formats prefer nesting. Using `#[serde(flatten)]` only the flattened form
+/// is supported.
+///
+/// This helper creates a function, which support deserializing from either the flattened or the
+/// nested form. It gives an error, when both forms are provided. The `flatten` attribute is
+/// required on the field such that the helper works. The serialization format will always be
+/// flattened.
+///
+/// # Examples
+///
+/// ```rust
+/// # extern crate serde;
+/// # extern crate serde_json;
+/// # #[macro_use]
+/// # extern crate serde_with;
+/// #
+/// # use serde::Deserialize;
+/// #
+/// // Setup the types
+/// #[derive(Deserialize, Debug)]
+/// struct S {
+/// #[serde(flatten, deserialize_with = "deserialize_t")]
+/// t: T,
+/// }
+///
+/// #[derive(Deserialize, Debug)]
+/// struct T {
+/// i: i32,
+/// }
+///
+/// // The macro creates custom deserialization code.
+/// // You need to specify a function name and the field name of the flattened field.
+/// flattened_maybe!(deserialize_t, "t");
+///
+///
+/// # fn main() {
+/// // Supports both flattened
+/// let j = r#" {"i":1} "#;
+/// assert!(serde_json::from_str::<S>(j).is_ok());
+///
+/// // and non-flattened versions.
+/// let j = r#" {"t":{"i":1}} "#;
+/// assert!(serde_json::from_str::<S>(j).is_ok());
+///
+/// // Ensure that the value is given
+/// let j = r#" {} "#;
+/// assert!(serde_json::from_str::<S>(j).is_err());
+///
+/// // and only occurs once, not multiple times.
+/// let j = r#" {"i":1,"t":{"i":1}} "#;
+/// assert!(serde_json::from_str::<S>(j).is_err());
+/// # }
+/// ```
+#[macro_export]
+macro_rules! flattened_maybe {
+ // TODO Change $field to literal, once the compiler version is bumped enough.
+ ($fn:ident, $field:expr) => {
+ fn $fn<'de, T, D>(deserializer: D) -> Result<T, D::Error>
+ where
+ T: serde::Deserialize<'de>,
+ D: serde::Deserializer<'de>,
+ {
+ #[derive(serde::Deserialize)]
+ struct Both<T> {
+ #[serde(flatten)]
+ flat: Option<T>,
+ #[serde(rename = $field)]
+ not_flat: Option<T>,
+ }
+
+ let both: Both<T> = serde::Deserialize::deserialize(deserializer)?;
+ match (both.flat, both.not_flat) {
+ (Some(t), None) | (None, Some(t)) => Ok(t),
+ (None, None) => Err(serde::de::Error::missing_field($field)),
+ (Some(_), Some(_)) => Err(serde::de::Error::custom(concat!(
+ "`",
+ $field,
+ "` is both flattened and not"
+ ))),
+ }
+ }
+ };
+}
diff --git a/third_party/rust/serde_with/src/json.rs b/third_party/rust/serde_with/src/json.rs
new file mode 100644
index 0000000000..9123713856
--- /dev/null
+++ b/third_party/rust/serde_with/src/json.rs
@@ -0,0 +1,88 @@
+//! De/Serialization of JSON
+//!
+//! This modules is only available if using the `json` feature of the crate.
+
+/// Serialize value as string containing JSON
+///
+/// # Examples
+///
+/// ```
+/// # extern crate serde;
+/// # extern crate serde_derive;
+/// # extern crate serde_json;
+/// # extern crate serde_with;
+/// #
+/// # use serde_derive::{Deserialize, Serialize};
+/// #
+/// #[derive(Deserialize, Serialize)]
+/// struct A {
+/// #[serde(with = "serde_with::json::nested")]
+/// other_struct: B,
+/// }
+/// #[derive(Deserialize, Serialize)]
+/// struct B {
+/// value: usize,
+/// }
+///
+/// let v: A = serde_json::from_str(r#"{"other_struct":"{\"value\":5}"}"#).unwrap();
+/// assert_eq!(5, v.other_struct.value);
+///
+/// let x = A {
+/// other_struct: B { value: 10 },
+/// };
+/// assert_eq!(r#"{"other_struct":"{\"value\":10}"}"#, serde_json::to_string(&x).unwrap());
+/// ```
+///
+pub mod nested {
+ use serde::{
+ de::{DeserializeOwned, Deserializer, Error, Visitor},
+ ser::{self, Serialize, Serializer},
+ };
+ use serde_json;
+ use std::{fmt, marker::PhantomData};
+
+ /// Deserialize value from a string which is valid JSON
+ pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
+ where
+ D: Deserializer<'de>,
+ T: DeserializeOwned,
+ {
+ #[derive(Default)]
+ struct Helper<S: DeserializeOwned>(PhantomData<S>);
+
+ impl<'de, S> Visitor<'de> for Helper<S>
+ where
+ S: DeserializeOwned,
+ {
+ type Value = S;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "valid json object")
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<S, E>
+ where
+ E: Error,
+ {
+ serde_json::from_str(value).map_err(Error::custom)
+ }
+ }
+
+ deserializer.deserialize_str(Helper(PhantomData))
+ }
+
+ /// Serialize value as string containing JSON
+ ///
+ /// # Errors
+ ///
+ /// Serialization can fail if `T`'s implementation of `Serialize` decides to
+ /// fail, or if `T` contains a map with non-string keys.
+ pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ T: Serialize,
+ S: Serializer,
+ {
+ let s = serde_json::to_string(value).map_err(ser::Error::custom)?;
+ serializer.serialize_str(&*s)
+ }
+}
diff --git a/third_party/rust/serde_with/src/lib.rs b/third_party/rust/serde_with/src/lib.rs
new file mode 100644
index 0000000000..5856a0d339
--- /dev/null
+++ b/third_party/rust/serde_with/src/lib.rs
@@ -0,0 +1,140 @@
+#![deny(
+ missing_debug_implementations,
+ missing_copy_implementations,
+ missing_docs,
+ trivial_casts,
+ trivial_numeric_casts,
+ unused_extern_crates,
+ unused_import_braces,
+ unused_qualifications,
+ variant_size_differences
+)]
+#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
+#![doc(html_root_url = "https://docs.rs/serde_with/1.4.0")]
+
+//! [![docs.rs badge](https://docs.rs/serde_with/badge.svg)](https://docs.rs/serde_with/)
+//! [![crates.io badge](https://img.shields.io/crates/v/serde_with.svg)](https://crates.io/crates/serde_with/)
+//! [![Build Status](https://travis-ci.org/jonasbb/serde_with.svg?branch=master)](https://travis-ci.org/jonasbb/serde_with)
+//! [![codecov](https://codecov.io/gh/jonasbb/serde_with/branch/master/graph/badge.svg)](https://codecov.io/gh/jonasbb/serde_with)
+//!
+//! ---
+//!
+//! This crate provides custom de/serialization helpers to use in combination with [serde's with-annotation][with-annotation].
+//!
+//! Serde tracks a wishlist of similar helpers at [serde#553].
+//!
+//! # Usage
+//!
+//! Add this to your `Cargo.toml`:
+//!
+//! ```toml
+//! [dependencies.serde_with]
+//! version = "1.4.0"
+//! features = [ "..." ]
+//! ```
+//!
+//! The crate is divided into different modules.
+//! They contain helpers for external crates and must be enabled with the correspondig feature.
+//!
+//! Annotate your struct or enum to enable the custom de/serializer.
+//!
+//! ```rust
+//! # extern crate serde;
+//! # extern crate serde_derive;
+//! # extern crate serde_with;
+//! # use serde_derive::{Deserialize, Serialize};
+//! #[derive(Deserialize, Serialize)]
+//! struct Foo {
+//! #[serde(with = "serde_with::rust::display_fromstr")]
+//! bar: u8,
+//! }
+//! # fn main() {}
+//! ```
+//!
+//! Most helpers implement both deserialize and serialize.
+//! If you do not want to derive both, you can simply derive only the necessary parts.
+//! If you want to mix different helpers, you can write your annotations like
+//!
+//! ```rust
+//! # extern crate serde;
+//! # extern crate serde_derive;
+//! # extern crate serde_with;
+//! # use serde_derive::{Deserialize, Serialize};
+//! # #[cfg(feature = "json")]
+//! #[derive(Deserialize, Serialize)]
+//! struct Foo {
+//! #[serde(
+//! deserialize_with = "serde_with::rust::display_fromstr::deserialize",
+//! serialize_with = "serde_with::json::nested::serialize"
+//! )]
+//! bar: u8,
+//! }
+//! # fn main() {}
+//! ```
+//!
+//! However, this will prohibit you from applying deserialize on the value returned by serializing a struct.
+//!
+//! # Attributes
+//!
+//! The crate comes with custom attributes, which futher extend how serde serialization can be customized.
+//! They are enabled by default, but can be disabled, by removing the default features from this crate.
+//!
+//! The `serde_with` crate re-exports all items from `serde_with_macros`.
+//! This means, if you want to use any proc_macros, import them like `use serde_with::skip_serializing_none`.
+//!
+//! [The documentation for the custom attributes can be found here.](serde_with_macros)
+//!
+//! [with-annotation]: https://serde.rs/field-attrs.html#serdewith--module
+//! [serde#553]: https://github.com/serde-rs/serde/issues/553
+
+#[cfg(feature = "chrono")]
+extern crate chrono as chrono_crate;
+#[doc(hidden)]
+pub extern crate serde;
+#[cfg(feature = "json")]
+extern crate serde_json;
+#[cfg(feature = "macros")]
+extern crate serde_with_macros;
+
+#[cfg(feature = "chrono")]
+pub mod chrono;
+mod duplicate_key_impls;
+mod flatten_maybe;
+#[cfg(feature = "json")]
+pub mod json;
+pub mod rust;
+#[doc(hidden)]
+pub mod with_prefix;
+
+// Re-Export all proc_macros, as these should be seen as part of the serde_with crate
+#[cfg(feature = "macros")]
+#[doc(inline)]
+pub use serde_with_macros::*;
+
+/// Separator for string-based collection de/serialization
+pub trait Separator {
+ /// Return the string delimiting two elements in the string-based collection
+ fn separator() -> &'static str;
+}
+
+/// Predefined separator using a single space
+#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
+pub struct SpaceSeparator;
+
+impl Separator for SpaceSeparator {
+ #[inline]
+ fn separator() -> &'static str {
+ " "
+ }
+}
+
+/// Predefined separator using a single comma
+#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
+pub struct CommaSeparator;
+
+impl Separator for CommaSeparator {
+ #[inline]
+ fn separator() -> &'static str {
+ ","
+ }
+}
diff --git a/third_party/rust/serde_with/src/rust.rs b/third_party/rust/serde_with/src/rust.rs
new file mode 100644
index 0000000000..3a984ed7e4
--- /dev/null
+++ b/third_party/rust/serde_with/src/rust.rs
@@ -0,0 +1,1534 @@
+//! De/Serialization for Rust's builtin and std types
+
+use serde::{
+ de::{Deserialize, DeserializeOwned, Deserializer, Error, MapAccess, SeqAccess, Visitor},
+ ser::{Serialize, SerializeMap, SerializeSeq, Serializer},
+};
+use std::{
+ cmp::Eq,
+ collections::{BTreeMap, HashMap},
+ fmt::{self, Display},
+ hash::{BuildHasher, Hash},
+ iter::FromIterator,
+ marker::PhantomData,
+ str::FromStr,
+};
+use Separator;
+
+/// De/Serialize using [`Display`] and [`FromStr`] implementation
+///
+/// This allows to deserialize a string as a number.
+/// It can be very useful for serialization formats like JSON, which do not support integer
+/// numbers and have to resort to strings to represent them.
+///
+/// # Examples
+///
+/// ```
+/// # extern crate serde;
+/// # extern crate serde_derive;
+/// # extern crate serde_json;
+/// # extern crate serde_with;
+/// #
+/// # use serde_derive::{Deserialize, Serialize};
+/// # use std::net::Ipv4Addr;
+/// #
+/// #[derive(Deserialize, Serialize)]
+/// struct A {
+/// #[serde(with = "serde_with::rust::display_fromstr")]
+/// address: Ipv4Addr,
+/// #[serde(with = "serde_with::rust::display_fromstr")]
+/// b: bool,
+/// }
+///
+/// let v: A = serde_json::from_str(r#"{
+/// "address": "192.168.2.1",
+/// "b": "true"
+/// }"#).unwrap();
+/// assert_eq!(Ipv4Addr::new(192, 168, 2, 1), v.address);
+/// assert!(v.b);
+///
+/// let x = A {
+/// address: Ipv4Addr::new(127, 53, 0, 1),
+/// b: false,
+/// };
+/// assert_eq!(r#"{"address":"127.53.0.1","b":"false"}"#, serde_json::to_string(&x).unwrap());
+/// ```
+pub mod display_fromstr {
+ use super::*;
+ use std::str::FromStr;
+
+ /// Deserialize T using [FromStr]
+ pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
+ where
+ D: Deserializer<'de>,
+ T: FromStr,
+ T::Err: Display,
+ {
+ struct Helper<S>(PhantomData<S>);
+
+ impl<'de, S> Visitor<'de> for Helper<S>
+ where
+ S: FromStr,
+ <S as FromStr>::Err: Display,
+ {
+ type Value = S;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "valid json object")
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ value.parse::<Self::Value>().map_err(Error::custom)
+ }
+ }
+
+ deserializer.deserialize_str(Helper(PhantomData))
+ }
+
+ /// Serialize T using [Display]
+ pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ T: Display,
+ S: Serializer,
+ {
+ serializer.serialize_str(&*value.to_string())
+ }
+}
+
+/// De/Serialize sequences using [`FromIterator`] and [`IntoIterator`] implementation for it and [`Display`] and [`FromStr`] implementation for each element
+///
+/// This allows to serialize and deserialize collections with elements which can be represented as strings.
+///
+/// # Examples
+///
+/// ```
+/// # extern crate serde;
+/// # extern crate serde_derive;
+/// # extern crate serde_json;
+/// # extern crate serde_with;
+/// #
+/// # use serde_derive::{Deserialize, Serialize};
+/// #
+/// use std::collections::BTreeSet;
+/// use std::net::Ipv4Addr;
+///
+/// #[derive(Deserialize, Serialize)]
+/// struct A {
+/// #[serde(with = "serde_with::rust::seq_display_fromstr")]
+/// addresses: BTreeSet<Ipv4Addr>,
+/// #[serde(with = "serde_with::rust::seq_display_fromstr")]
+/// bs: Vec<bool>,
+/// }
+///
+/// let v: A = serde_json::from_str(r#"{
+/// "addresses": ["192.168.2.1", "192.168.2.2", "192.168.1.1", "192.168.2.2"],
+/// "bs": ["true", "false"]
+/// }"#).unwrap();
+/// assert_eq!(v.addresses.len(), 3);
+/// assert!(v.addresses.contains(&Ipv4Addr::new(192, 168, 2, 1)));
+/// assert!(v.addresses.contains(&Ipv4Addr::new(192, 168, 2, 2)));
+/// assert!(!v.addresses.contains(&Ipv4Addr::new(192, 168, 1, 2)));
+/// assert_eq!(v.bs.len(), 2);
+/// assert!(v.bs[0]);
+/// assert!(!v.bs[1]);
+///
+/// let x = A {
+/// addresses: vec![
+/// Ipv4Addr::new(127, 53, 0, 1),
+/// Ipv4Addr::new(127, 53, 1, 1),
+/// Ipv4Addr::new(127, 53, 0, 2)
+/// ].into_iter().collect(),
+/// bs: vec![false, true],
+/// };
+/// assert_eq!(r#"{"addresses":["127.53.0.1","127.53.0.2","127.53.1.1"],"bs":["false","true"]}"#, serde_json::to_string(&x).unwrap());
+/// ```
+pub mod seq_display_fromstr {
+ use serde::{
+ de::{Deserializer, Error, SeqAccess, Visitor},
+ ser::{SerializeSeq, Serializer},
+ };
+ use std::{
+ fmt::{self, Display},
+ iter::{FromIterator, IntoIterator},
+ marker::PhantomData,
+ str::FromStr,
+ };
+
+ /// Deserialize collection T using [FromIterator] and [FromStr] for each element
+ pub fn deserialize<'de, D, T, I>(deserializer: D) -> Result<T, D::Error>
+ where
+ D: Deserializer<'de>,
+ T: FromIterator<I> + Sized,
+ I: FromStr,
+ I::Err: Display,
+ {
+ struct Helper<S>(PhantomData<S>);
+
+ impl<'de, S> Visitor<'de> for Helper<S>
+ where
+ S: FromStr,
+ <S as FromStr>::Err: Display,
+ {
+ type Value = Vec<S>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "a sequence")
+ }
+
+ fn visit_seq<A>(self, mut access: A) -> Result<Self::Value, A::Error>
+ where
+ A: SeqAccess<'de>,
+ {
+ let mut values = access
+ .size_hint()
+ .map(Self::Value::with_capacity)
+ .unwrap_or_else(Self::Value::new);
+
+ while let Some(value) = access.next_element::<&str>()? {
+ values.push(value.parse::<S>().map_err(Error::custom)?);
+ }
+
+ Ok(values)
+ }
+ }
+
+ deserializer
+ .deserialize_seq(Helper(PhantomData))
+ .map(T::from_iter)
+ }
+
+ /// Serialize collection T using [IntoIterator] and [Display] for each element
+ pub fn serialize<S, T, I>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ for<'a> &'a T: IntoIterator<Item = &'a I>,
+ I: Display,
+ {
+ let iter = value.into_iter();
+ let (_, to) = iter.size_hint();
+ let mut seq = serializer.serialize_seq(to)?;
+ for item in iter {
+ seq.serialize_element(&item.to_string())?;
+ }
+ seq.end()
+ }
+}
+
+/// De/Serialize a delimited collection using [`Display`] and [`FromStr`] implementation
+///
+/// You can define an arbitrary separator, by specifying a type which implements [`Separator`].
+/// Some common ones, like space and comma are already predefined and you can find them [here][Separator].
+///
+/// An empty string deserializes as an empty collection.
+///
+/// # Examples
+///
+/// ```
+/// # extern crate serde;
+/// # extern crate serde_derive;
+/// # extern crate serde_json;
+/// # extern crate serde_with;
+/// #
+/// # use serde_derive::{Deserialize, Serialize};
+/// #
+/// use serde_with::{CommaSeparator, SpaceSeparator};
+/// use std::collections::BTreeSet;
+///
+/// #[derive(Deserialize, Serialize)]
+/// struct A {
+/// #[serde(with = "serde_with::rust::StringWithSeparator::<SpaceSeparator>")]
+/// tags: Vec<String>,
+/// #[serde(with = "serde_with::rust::StringWithSeparator::<CommaSeparator>")]
+/// more_tags: BTreeSet<String>,
+/// }
+///
+/// let v: A = serde_json::from_str(r##"{
+/// "tags": "#hello #world",
+/// "more_tags": "foo,bar,bar"
+/// }"##).unwrap();
+/// assert_eq!(vec!["#hello", "#world"], v.tags);
+/// assert_eq!(2, v.more_tags.len());
+///
+/// let x = A {
+/// tags: vec!["1".to_string(), "2".to_string(), "3".to_string()],
+/// more_tags: BTreeSet::new(),
+/// };
+/// assert_eq!(r#"{"tags":"1 2 3","more_tags":""}"#, serde_json::to_string(&x).unwrap());
+/// ```
+#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
+pub struct StringWithSeparator<Sep>(PhantomData<Sep>);
+
+impl<Sep> StringWithSeparator<Sep>
+where
+ Sep: Separator,
+{
+ /// Serialize collection into a string with separator symbol
+ pub fn serialize<S, T, V>(values: T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ T: IntoIterator<Item = V>,
+ V: Display,
+ {
+ let mut s = String::new();
+ for v in values {
+ s.push_str(&*v.to_string());
+ s.push_str(Sep::separator());
+ }
+ serializer.serialize_str(if !s.is_empty() {
+ // remove trailing separator if present
+ &s[..s.len() - Sep::separator().len()]
+ } else {
+ &s[..]
+ })
+ }
+
+ /// Deserialize a collection from a string with separator symbol
+ pub fn deserialize<'de, D, T, V>(deserializer: D) -> Result<T, D::Error>
+ where
+ D: Deserializer<'de>,
+ T: FromIterator<V>,
+ V: FromStr,
+ V::Err: Display,
+ {
+ let s = String::deserialize(deserializer)?;
+ if s.is_empty() {
+ Ok(None.into_iter().collect())
+ } else {
+ s.split(Sep::separator())
+ .map(FromStr::from_str)
+ .collect::<Result<_, _>>()
+ .map_err(Error::custom)
+ }
+ }
+}
+
+/// Makes a distinction between a missing, unset, or existing value
+///
+/// Some serialization formats make a distinction between missing fields, fields with a `null`
+/// value, and existing values. One such format is JSON. By default it is not easily possible to
+/// differentiate between a missing value and a field which is `null`, as they deserialize to the
+/// same value. This helper changes it, by using an `Option<Option<T>>` to deserialize into.
+///
+/// * `None`: Represents a missing value.
+/// * `Some(None)`: Represents a `null` value.
+/// * `Some(Some(value))`: Represents an existing value.
+///
+/// # Examples
+///
+/// ```rust
+/// # extern crate serde;
+/// # extern crate serde_derive;
+/// # extern crate serde_json;
+/// # extern crate serde_with;
+/// #
+/// # use serde_derive::{Deserialize, Serialize};
+/// #
+/// # #[derive(Debug, PartialEq, Eq)]
+/// #[derive(Deserialize, Serialize)]
+/// struct Doc {
+/// #[serde(
+/// default, // <- important for deserialization
+/// skip_serializing_if = "Option::is_none", // <- important for serialization
+/// with = "::serde_with::rust::double_option",
+/// )]
+/// a: Option<Option<u8>>,
+/// }
+/// // Missing Value
+/// let s = r#"{}"#;
+/// assert_eq!(Doc {a: None}, serde_json::from_str(s).unwrap());
+/// assert_eq!(s, serde_json::to_string(&Doc {a: None}).unwrap());
+///
+/// // Unset Value
+/// let s = r#"{"a":null}"#;
+/// assert_eq!(Doc {a: Some(None)}, serde_json::from_str(s).unwrap());
+/// assert_eq!(s, serde_json::to_string(&Doc {a: Some(None)}).unwrap());
+///
+/// // Existing Value
+/// let s = r#"{"a":5}"#;
+/// assert_eq!(Doc {a: Some(Some(5))}, serde_json::from_str(s).unwrap());
+/// assert_eq!(s, serde_json::to_string(&Doc {a: Some(Some(5))}).unwrap());
+/// ```
+#[cfg_attr(feature = "cargo-clippy", allow(option_option))]
+pub mod double_option {
+ use super::*;
+
+ /// Deserialize potentially non-existing optional value
+ pub fn deserialize<'de, T, D>(deserializer: D) -> Result<Option<Option<T>>, D::Error>
+ where
+ T: Deserialize<'de>,
+ D: Deserializer<'de>,
+ {
+ Deserialize::deserialize(deserializer).map(Some)
+ }
+
+ /// Serialize optional value
+ pub fn serialize<S, T>(values: &Option<Option<T>>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ T: Serialize,
+ {
+ match values {
+ None => serializer.serialize_unit(),
+ Some(None) => serializer.serialize_none(),
+ Some(Some(v)) => serializer.serialize_some(&v),
+ }
+ }
+}
+
+/// Serialize inner value if [`Some`]`(T)`. If [`None`], serialize the unit struct `()`.
+///
+/// When used in conjunction with `skip_serializing_if = "Option::is_none"` and
+/// `default`, you can build an optional value by skipping if it is [`None`], or serializing its
+/// inner value if [`Some`]`(T)`.
+///
+/// Not all serialization formats easily support optional values.
+/// While JSON uses the [`Option`] type to represent optional values and only serializes the inner
+/// part of the [`Some`]`()`, other serialization formats, such as [RON][], choose to serialize the
+/// [`Some`] around a value.
+/// This helper helps building a truly optional value for such serializers.
+///
+/// [RON]: https://github.com/ron-rs/ron
+///
+/// # Example
+///
+/// ```rust
+/// # extern crate serde;
+/// # extern crate serde_derive;
+/// # extern crate serde_json;
+/// # extern crate serde_with;
+/// # extern crate ron;
+/// #
+/// # use serde_derive::{Deserialize, Serialize};
+/// #
+/// # #[derive(Debug, Eq, PartialEq)]
+/// #[derive(Deserialize, Serialize)]
+/// struct Doc {
+/// mandatory: usize,
+/// #[serde(
+/// default, // <- important for deserialization
+/// skip_serializing_if = "Option::is_none", // <- important for serialization
+/// with = "::serde_with::rust::unwrap_or_skip",
+/// )]
+/// optional: Option<usize>,
+/// }
+///
+/// // Transparently add/remove Some() wrapper
+/// # let pretty_config = ron::ser::PrettyConfig {
+/// # new_line: "\n".into(),
+/// # ..Default::default()
+/// # };
+/// let s = r#"(
+/// mandatory: 1,
+/// optional: 2,
+/// )"#;
+/// let v = Doc {
+/// mandatory: 1,
+/// optional: Some(2),
+/// };
+/// assert_eq!(v, ron::de::from_str(s).unwrap());
+/// assert_eq!(s, ron::ser::to_string_pretty(&v, pretty_config).unwrap());
+///
+/// // Missing values are deserialized as `None`
+/// // while `None` values are skipped during serialization.
+/// # let pretty_config = ron::ser::PrettyConfig {
+/// # new_line: "\n".into(),
+/// # ..Default::default()
+/// # };
+/// let s = r#"(
+/// mandatory: 1,
+/// )"#;
+/// let v = Doc {
+/// mandatory: 1,
+/// optional: None,
+/// };
+/// assert_eq!(v, ron::de::from_str(s).unwrap());
+/// assert_eq!(s, ron::ser::to_string_pretty(&v, pretty_config).unwrap());
+/// ```
+pub mod unwrap_or_skip {
+ use super::*;
+
+ /// Deserialize value wrapped in Some(T)
+ pub fn deserialize<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
+ where
+ D: Deserializer<'de>,
+ T: DeserializeOwned,
+ {
+ T::deserialize(deserializer).map(Some)
+ }
+
+ /// Serialize value if Some(T), unit struct if None
+ pub fn serialize<T, S>(option: &Option<T>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ T: Serialize,
+ S: Serializer,
+ {
+ if let Some(value) = option {
+ value.serialize(serializer)
+ } else {
+ ().serialize(serializer)
+ }
+ }
+}
+
+/// Ensure no duplicate values exist in a set.
+///
+/// By default serde has a last-value-wins implementation, if duplicate values for a set exist.
+/// Sometimes it is desirable to know when such an event happens, as the first value is overwritten
+/// and it can indicate an error in the serialized data.
+///
+/// This helper returns an error if two identical values exist in a set.
+///
+/// The implementation supports both the [`HashSet`] and the [`BTreeSet`] from the standard library.
+///
+/// [`HashSet`]: std::collections::HashSet
+/// [`BTreeSet`]: std::collections::HashSet
+///
+/// # Example
+///
+/// ```rust
+/// # extern crate serde;
+/// # extern crate serde_derive;
+/// # extern crate serde_json;
+/// # extern crate serde_with;
+/// #
+/// # use std::{collections::HashSet, iter::FromIterator};
+/// # use serde_derive::{Deserialize, Serialize};
+/// #
+/// # #[derive(Debug, Eq, PartialEq)]
+/// #[derive(Deserialize)]
+/// struct Doc {
+/// #[serde(with = "::serde_with::rust::sets_duplicate_value_is_error")]
+/// set: HashSet<usize>,
+/// }
+///
+/// // Sets are serialized normally,
+/// let s = r#"{"set": [1, 2, 3, 4]}"#;
+/// let v = Doc {
+/// set: HashSet::from_iter(vec![1, 2, 3, 4]),
+/// };
+/// assert_eq!(v, serde_json::from_str(s).unwrap());
+///
+/// // but create an error if duplicate values, like the `1`, exist.
+/// let s = r#"{"set": [1, 2, 3, 4, 1]}"#;
+/// let res: Result<Doc, _> = serde_json::from_str(s);
+/// assert!(res.is_err());
+/// ```
+pub mod sets_duplicate_value_is_error {
+ use super::*;
+ use duplicate_key_impls::PreventDuplicateInsertsSet;
+
+ /// Deserialize a set and return an error on duplicate values
+ pub fn deserialize<'de, D, T, V>(deserializer: D) -> Result<T, D::Error>
+ where
+ T: PreventDuplicateInsertsSet<V>,
+ V: Deserialize<'de>,
+ D: Deserializer<'de>,
+ {
+ struct SeqVisitor<T, V> {
+ marker: PhantomData<T>,
+ set_item_type: PhantomData<V>,
+ };
+
+ impl<'de, T, V> Visitor<'de> for SeqVisitor<T, V>
+ where
+ T: PreventDuplicateInsertsSet<V>,
+ V: Deserialize<'de>,
+ {
+ type Value = T;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a sequence")
+ }
+
+ #[inline]
+ fn visit_seq<A>(self, mut access: A) -> Result<Self::Value, A::Error>
+ where
+ A: SeqAccess<'de>,
+ {
+ let mut values = Self::Value::new(access.size_hint());
+
+ while let Some(value) = access.next_element()? {
+ if !values.insert(value) {
+ return Err(Error::custom("invalid entry: found duplicate value"));
+ };
+ }
+
+ Ok(values)
+ }
+ }
+
+ let visitor = SeqVisitor {
+ marker: PhantomData,
+ set_item_type: PhantomData,
+ };
+ deserializer.deserialize_seq(visitor)
+ }
+}
+
+/// Ensure no duplicate keys exist in a map.
+///
+/// By default serde has a last-value-wins implementation, if duplicate keys for a map exist.
+/// Sometimes it is desirable to know when such an event happens, as the first value is overwritten
+/// and it can indicate an error in the serialized data.
+///
+/// This helper returns an error if two identical keys exist in a map.
+///
+/// The implementation supports both the [`HashMap`] and the [`BTreeMap`] from the standard library.
+///
+/// [`HashMap`]: std::collections::HashMap
+/// [`BTreeMap`]: std::collections::HashMap
+///
+/// # Example
+///
+/// ```rust
+/// # extern crate serde;
+/// # extern crate serde_derive;
+/// # extern crate serde_json;
+/// # extern crate serde_with;
+/// #
+/// # use serde_derive::{Deserialize, Serialize};
+/// # use std::collections::HashMap;
+/// #
+/// # #[derive(Debug, Eq, PartialEq)]
+/// #[derive(Deserialize)]
+/// struct Doc {
+/// #[serde(with = "::serde_with::rust::maps_duplicate_key_is_error")]
+/// map: HashMap<usize, usize>,
+/// }
+///
+/// // Maps are serialized normally,
+/// let s = r#"{"map": {"1": 1, "2": 2, "3": 3}}"#;
+/// let mut v = Doc {
+/// map: HashMap::new(),
+/// };
+/// v.map.insert(1, 1);
+/// v.map.insert(2, 2);
+/// v.map.insert(3, 3);
+/// assert_eq!(v, serde_json::from_str(s).unwrap());
+///
+/// // but create an error if duplicate keys, like the `1`, exist.
+/// let s = r#"{"map": {"1": 1, "2": 2, "1": 3}}"#;
+/// let res: Result<Doc, _> = serde_json::from_str(s);
+/// assert!(res.is_err());
+/// ```
+pub mod maps_duplicate_key_is_error {
+ use super::*;
+ use duplicate_key_impls::PreventDuplicateInsertsMap;
+
+ /// Deserialize a map and return an error on duplicate keys
+ pub fn deserialize<'de, D, T, K, V>(deserializer: D) -> Result<T, D::Error>
+ where
+ T: PreventDuplicateInsertsMap<K, V>,
+ K: Deserialize<'de>,
+ V: Deserialize<'de>,
+ D: Deserializer<'de>,
+ {
+ struct MapVisitor<T, K, V> {
+ marker: PhantomData<T>,
+ map_key_type: PhantomData<K>,
+ map_value_type: PhantomData<V>,
+ };
+
+ impl<'de, T, K, V> Visitor<'de> for MapVisitor<T, K, V>
+ where
+ T: PreventDuplicateInsertsMap<K, V>,
+ K: Deserialize<'de>,
+ V: Deserialize<'de>,
+ {
+ type Value = T;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a map")
+ }
+
+ #[inline]
+ fn visit_map<A>(self, mut access: A) -> Result<Self::Value, A::Error>
+ where
+ A: MapAccess<'de>,
+ {
+ let mut values = Self::Value::new(access.size_hint());
+
+ while let Some((key, value)) = access.next_entry()? {
+ if !values.insert(key, value) {
+ return Err(Error::custom("invalid entry: found duplicate key"));
+ };
+ }
+
+ Ok(values)
+ }
+ }
+
+ let visitor = MapVisitor {
+ marker: PhantomData,
+ map_key_type: PhantomData,
+ map_value_type: PhantomData,
+ };
+ deserializer.deserialize_map(visitor)
+ }
+}
+
+/// Ensure that the first value is taken, if duplicate values exist
+///
+/// By default serde has a last-value-wins implementation, if duplicate keys for a set exist.
+/// Sometimes the opposite strategy is desired. This helper implements a first-value-wins strategy.
+///
+/// The implementation supports both the [`HashSet`] and the [`BTreeSet`] from the standard library.
+///
+/// [`HashSet`]: std::collections::HashSet
+/// [`BTreeSet`]: std::collections::HashSet
+pub mod sets_first_value_wins {
+ use super::*;
+ use duplicate_key_impls::DuplicateInsertsFirstWinsSet;
+
+ /// Deserialize a set and return an error on duplicate values
+ pub fn deserialize<'de, D, T, V>(deserializer: D) -> Result<T, D::Error>
+ where
+ T: DuplicateInsertsFirstWinsSet<V>,
+ V: Deserialize<'de>,
+ D: Deserializer<'de>,
+ {
+ struct SeqVisitor<T, V> {
+ marker: PhantomData<T>,
+ set_item_type: PhantomData<V>,
+ };
+
+ impl<'de, T, V> Visitor<'de> for SeqVisitor<T, V>
+ where
+ T: DuplicateInsertsFirstWinsSet<V>,
+ V: Deserialize<'de>,
+ {
+ type Value = T;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a sequence")
+ }
+
+ #[inline]
+ fn visit_seq<A>(self, mut access: A) -> Result<Self::Value, A::Error>
+ where
+ A: SeqAccess<'de>,
+ {
+ let mut values = Self::Value::new(access.size_hint());
+
+ while let Some(value) = access.next_element()? {
+ values.insert(value);
+ }
+
+ Ok(values)
+ }
+ }
+
+ let visitor = SeqVisitor {
+ marker: PhantomData,
+ set_item_type: PhantomData,
+ };
+ deserializer.deserialize_seq(visitor)
+ }
+}
+
+/// Ensure that the first key is taken, if duplicate keys exist
+///
+/// By default serde has a last-key-wins implementation, if duplicate keys for a map exist.
+/// Sometimes the opposite strategy is desired. This helper implements a first-key-wins strategy.
+///
+/// The implementation supports both the [`HashMap`] and the [`BTreeMap`] from the standard library.
+///
+/// [`HashMap`]: std::collections::HashMap
+/// [`BTreeMap`]: std::collections::HashMap
+///
+/// # Example
+///
+/// ```rust
+/// # extern crate serde;
+/// # extern crate serde_derive;
+/// # extern crate serde_json;
+/// # extern crate serde_with;
+/// #
+/// # use serde_derive::{Deserialize, Serialize};
+/// # use std::collections::HashMap;
+/// #
+/// # #[derive(Debug, Eq, PartialEq)]
+/// #[derive(Deserialize)]
+/// struct Doc {
+/// #[serde(with = "::serde_with::rust::maps_first_key_wins")]
+/// map: HashMap<usize, usize>,
+/// }
+///
+/// // Maps are serialized normally,
+/// let s = r#"{"map": {"1": 1, "2": 2, "3": 3}}"#;
+/// let mut v = Doc {
+/// map: HashMap::new(),
+/// };
+/// v.map.insert(1, 1);
+/// v.map.insert(2, 2);
+/// v.map.insert(3, 3);
+/// assert_eq!(v, serde_json::from_str(s).unwrap());
+///
+/// // but create an error if duplicate keys, like the `1`, exist.
+/// let s = r#"{"map": {"1": 1, "2": 2, "1": 3}}"#;
+/// let mut v = Doc {
+/// map: HashMap::new(),
+/// };
+/// v.map.insert(1, 1);
+/// v.map.insert(2, 2);
+/// assert_eq!(v, serde_json::from_str(s).unwrap());
+/// ```
+pub mod maps_first_key_wins {
+ use super::*;
+ use duplicate_key_impls::DuplicateInsertsFirstWinsMap;
+
+ /// Deserialize a map and return an error on duplicate keys
+ pub fn deserialize<'de, D, T, K, V>(deserializer: D) -> Result<T, D::Error>
+ where
+ T: DuplicateInsertsFirstWinsMap<K, V>,
+ K: Deserialize<'de>,
+ V: Deserialize<'de>,
+ D: Deserializer<'de>,
+ {
+ struct MapVisitor<T, K, V> {
+ marker: PhantomData<T>,
+ map_key_type: PhantomData<K>,
+ map_value_type: PhantomData<V>,
+ };
+
+ impl<'de, T, K, V> Visitor<'de> for MapVisitor<T, K, V>
+ where
+ T: DuplicateInsertsFirstWinsMap<K, V>,
+ K: Deserialize<'de>,
+ V: Deserialize<'de>,
+ {
+ type Value = T;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a map")
+ }
+
+ #[inline]
+ fn visit_map<A>(self, mut access: A) -> Result<Self::Value, A::Error>
+ where
+ A: MapAccess<'de>,
+ {
+ let mut values = Self::Value::new(access.size_hint());
+
+ while let Some((key, value)) = access.next_entry()? {
+ values.insert(key, value);
+ }
+
+ Ok(values)
+ }
+ }
+
+ let visitor = MapVisitor {
+ marker: PhantomData,
+ map_key_type: PhantomData,
+ map_value_type: PhantomData,
+ };
+ deserializer.deserialize_map(visitor)
+ }
+}
+
+/// De/Serialize a [`Option`]`<String>` type while transforming the empty string to [`None`]
+///
+/// Convert an [`Option`]`<T>` from/to string using [`FromStr`] and [`AsRef`]`<str>` implementations.
+/// An empty string is deserialized as [`None`] and a [`None`] vice versa.
+///
+/// # Examples
+///
+/// ```
+/// # extern crate serde;
+/// # extern crate serde_derive;
+/// # extern crate serde_json;
+/// # extern crate serde_with;
+/// #
+/// # use serde_derive::{Deserialize, Serialize};
+/// #
+/// #[derive(Deserialize, Serialize)]
+/// struct A {
+/// #[serde(with = "serde_with::rust::string_empty_as_none")]
+/// tags: Option<String>,
+/// }
+///
+/// let v: A = serde_json::from_str(r##"{
+/// "tags": ""
+/// }"##).unwrap();
+/// assert!(v.tags.is_none());
+///
+/// let v: A = serde_json::from_str(r##"{
+/// "tags": "Hi"
+/// }"##).unwrap();
+/// assert_eq!(Some("Hi".to_string()), v.tags);
+///
+/// let x = A {
+/// tags: Some("This is text".to_string()),
+/// };
+/// assert_eq!(r#"{"tags":"This is text"}"#, serde_json::to_string(&x).unwrap());
+///
+/// let x = A {
+/// tags: None,
+/// };
+/// assert_eq!(r#"{"tags":""}"#, serde_json::to_string(&x).unwrap());
+/// ```
+pub mod string_empty_as_none {
+ use super::*;
+
+ /// Deserialize an `Option<T>` from a string using `FromStr`
+ pub fn deserialize<'de, D, S>(deserializer: D) -> Result<Option<S>, D::Error>
+ where
+ D: Deserializer<'de>,
+ S: FromStr,
+ S::Err: Display,
+ {
+ struct OptionStringEmptyNone<S>(PhantomData<S>);
+ impl<'de, S> Visitor<'de> for OptionStringEmptyNone<S>
+ where
+ S: FromStr,
+ S::Err: Display,
+ {
+ type Value = Option<S>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("any string")
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ match value {
+ "" => Ok(None),
+ v => S::from_str(v).map(Some).map_err(Error::custom),
+ }
+ }
+
+ fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ match &*value {
+ "" => Ok(None),
+ v => S::from_str(v).map(Some).map_err(Error::custom),
+ }
+ }
+
+ // handles the `null` case
+ fn visit_unit<E>(self) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ Ok(None)
+ }
+ }
+
+ deserializer.deserialize_any(OptionStringEmptyNone(PhantomData))
+ }
+
+ /// Serialize a string from `Option<T>` using `AsRef<str>` or using the empty string if `None`.
+ pub fn serialize<T, S>(option: &Option<T>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ T: AsRef<str>,
+ S: Serializer,
+ {
+ if let Some(value) = option {
+ value.as_ref().serialize(serializer)
+ } else {
+ "".serialize(serializer)
+ }
+ }
+}
+
+/// De/Serialize a [`HashMap`] into a list of tuples
+///
+/// Some formats, like JSON, have limitations on the type of keys for maps.
+/// In case of JSON, keys are restricted to strings.
+/// Rust features more powerfull keys, for example tuple, which can not be serialized to JSON.
+///
+/// This helper serializes the [`HashMap`] into a list of tuples, which does not have the same type restrictions.
+///
+/// If you need to de/serialize a [`BTreeMap`] then use [`btreemap_as_tuple_list`].
+///
+/// # Examples
+///
+/// ```
+/// # extern crate serde;
+/// # extern crate serde_derive;
+/// # extern crate serde_json;
+/// # extern crate serde_with;
+/// #
+/// # use serde_derive::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// # use std::collections::HashMap;
+/// #
+/// #[derive(Deserialize, Serialize)]
+/// struct A {
+/// #[serde(with = "serde_with::rust::hashmap_as_tuple_list")]
+/// s: HashMap<(String, u32), u32>,
+/// }
+///
+/// let v: A = serde_json::from_value(json!({
+/// "s": [
+/// [["Hello", 123], 0],
+/// [["World", 456], 1]
+/// ]
+/// })).unwrap();
+///
+/// assert_eq!(2, v.s.len());
+/// assert_eq!(1, v.s[&("World".to_string(), 456)]);
+/// ```
+///
+/// The helper is generic over the hasher type of the [`HashMap`] and works with different variants, such as `FnvHashMap`.
+///
+/// ```
+/// # extern crate fnv;
+/// # extern crate serde;
+/// # extern crate serde_derive;
+/// # extern crate serde_json;
+/// # extern crate serde_with;
+/// #
+/// # use serde_derive::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// #
+/// use fnv::FnvHashMap;
+///
+/// #[derive(Deserialize, Serialize)]
+/// struct A {
+/// #[serde(with = "serde_with::rust::hashmap_as_tuple_list")]
+/// s: FnvHashMap<u32, bool>,
+/// }
+///
+/// let v: A = serde_json::from_value(json!({
+/// "s": [
+/// [0, false],
+/// [1, true]
+/// ]
+/// })).unwrap();
+///
+/// assert_eq!(2, v.s.len());
+/// assert_eq!(true, v.s[&1]);
+/// ```
+pub mod hashmap_as_tuple_list {
+ use super::{SerializeSeq, *}; // Needed to remove the unused import warning in the parent scope
+
+ /// Serialize the [`HashMap`] as a list of tuples
+ pub fn serialize<K, V, S, BH>(map: &HashMap<K, V, BH>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ K: Eq + Hash + Serialize,
+ V: Serialize,
+ BH: BuildHasher,
+ {
+ let mut seq = serializer.serialize_seq(Some(map.len()))?;
+ for item in map.iter() {
+ seq.serialize_element(&item)?;
+ }
+ seq.end()
+ }
+
+ /// Deserialize a [`HashMap`] from a list of tuples
+ pub fn deserialize<'de, K, V, BH, D>(deserializer: D) -> Result<HashMap<K, V, BH>, D::Error>
+ where
+ D: Deserializer<'de>,
+ K: Eq + Hash + Deserialize<'de>,
+ V: Deserialize<'de>,
+ BH: BuildHasher + Default,
+ {
+ deserializer.deserialize_seq(HashMapVisitor(PhantomData))
+ }
+
+ #[cfg_attr(feature = "cargo-clippy", allow(type_complexity))]
+ struct HashMapVisitor<K, V, BH>(PhantomData<fn() -> HashMap<K, V, BH>>);
+
+ impl<'de, K, V, BH> Visitor<'de> for HashMapVisitor<K, V, BH>
+ where
+ K: Deserialize<'de> + Eq + Hash,
+ V: Deserialize<'de>,
+ BH: BuildHasher + Default,
+ {
+ type Value = HashMap<K, V, BH>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a list of key-value pairs")
+ }
+
+ fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
+ where
+ A: SeqAccess<'de>,
+ {
+ let mut map =
+ HashMap::with_capacity_and_hasher(seq.size_hint().unwrap_or(0), BH::default());
+ while let Some((key, value)) = seq.next_element()? {
+ map.insert(key, value);
+ }
+ Ok(map)
+ }
+ }
+}
+
+/// De/Serialize a [`BTreeMap`] into a list of tuples
+///
+/// Some formats, like JSON, have limitations on the type of keys for maps.
+/// In case of JSON, keys are restricted to strings.
+/// Rust features more powerfull keys, for example tuple, which can not be serialized to JSON.
+///
+/// This helper serializes the [`BTreeMap`] into a list of tuples, which does not have the same type restrictions.
+///
+/// If you need to de/serialize a [`HashMap`] then use [`hashmap_as_tuple_list`].
+///
+/// # Examples
+///
+/// ```
+/// # extern crate serde;
+/// # extern crate serde_derive;
+/// # extern crate serde_json;
+/// # extern crate serde_with;
+/// #
+/// # use serde_derive::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// # use std::collections::BTreeMap;
+/// #
+/// #[derive(Deserialize, Serialize)]
+/// struct A {
+/// #[serde(with = "serde_with::rust::btreemap_as_tuple_list")]
+/// s: BTreeMap<(String, u32), u32>,
+/// }
+///
+/// let v: A = serde_json::from_value(json!({
+/// "s": [
+/// [["Hello", 123], 0],
+/// [["World", 456], 1]
+/// ]
+/// })).unwrap();
+///
+/// assert_eq!(2, v.s.len());
+/// assert_eq!(1, v.s[&("World".to_string(), 456)]);
+/// ```
+pub mod btreemap_as_tuple_list {
+ use super::*;
+
+ /// Serialize the [`BTreeMap`] as a list of tuples
+ pub fn serialize<K, V, S>(map: &BTreeMap<K, V>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ K: Eq + Hash + Serialize,
+ V: Serialize,
+ {
+ let mut seq = serializer.serialize_seq(Some(map.len()))?;
+ for item in map.iter() {
+ seq.serialize_element(&item)?;
+ }
+ seq.end()
+ }
+
+ /// Deserialize a [`BTreeMap`] from a list of tuples
+ pub fn deserialize<'de, K, V, D>(deserializer: D) -> Result<BTreeMap<K, V>, D::Error>
+ where
+ D: Deserializer<'de>,
+ K: Deserialize<'de> + Ord,
+ V: Deserialize<'de>,
+ {
+ deserializer.deserialize_seq(BTreeMapVisitor(PhantomData))
+ }
+
+ #[cfg_attr(feature = "cargo-clippy", allow(type_complexity))]
+ struct BTreeMapVisitor<K, V>(PhantomData<fn() -> BTreeMap<K, V>>);
+
+ impl<'de, K, V> Visitor<'de> for BTreeMapVisitor<K, V>
+ where
+ K: Deserialize<'de> + Ord,
+ V: Deserialize<'de>,
+ {
+ type Value = BTreeMap<K, V>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a list of key-value pairs")
+ }
+
+ fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
+ where
+ A: SeqAccess<'de>,
+ {
+ let mut map = BTreeMap::default();
+ while let Some((key, value)) = seq.next_element()? {
+ map.insert(key, value);
+ }
+ Ok(map)
+ }
+ }
+}
+
+/// This serializes a list of tuples into a map and back
+///
+/// Normally, you want to use a [`HashMap`] or a [`BTreeMap`] when deserializing a map.
+/// However, sometimes this is not possible due to type contains, e.g., if the type implements neither [`Hash`] nor [`Ord`].
+/// Another use case is deserializing a map with duplicate keys.
+///
+/// The implementation is generic using the [`FromIterator`] and [`IntoIterator`] traits.
+/// Therefore, all of [`Vec`], [`VecDeque`](std::collections::VecDeque), and [`LinkedList`](std::collections::LinkedList) and anything which implements those are supported.
+///
+/// # Examples
+///
+/// `Wrapper` does not implement [`Hash`] nor [`Ord`], thus prohibiting the use [`HashMap`] or [`BTreeMap`].
+///
+/// ```
+/// # extern crate serde;
+/// # extern crate serde_derive;
+/// # extern crate serde_json;
+/// # extern crate serde_with;
+/// #
+/// # use serde_derive::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// #
+/// #[derive(Debug, Deserialize, Serialize, Default)]
+/// struct S {
+/// #[serde(with = "serde_with::rust::tuple_list_as_map")]
+/// s: Vec<(Wrapper<i32>, Wrapper<String>)>,
+/// }
+///
+/// #[derive(Clone, Debug, Serialize, Deserialize)]
+/// #[serde(transparent)]
+/// struct Wrapper<T>(T);
+///
+/// let from = r#"{
+/// "s": {
+/// "1": "Hi",
+/// "2": "Cake",
+/// "99": "Lie"
+/// }
+/// }"#;
+/// let mut expected = S::default();
+/// expected.s.push((Wrapper(1), Wrapper("Hi".into())));
+/// expected.s.push((Wrapper(2), Wrapper("Cake".into())));
+/// expected.s.push((Wrapper(99), Wrapper("Lie".into())));
+///
+/// let res: S = serde_json::from_str(from).unwrap();
+/// for ((exp_k, exp_v), (res_k, res_v)) in expected.s.iter().zip(&res.s) {
+/// assert_eq!(exp_k.0, res_k.0);
+/// assert_eq!(exp_v.0, res_v.0);
+/// }
+/// assert_eq!(from, serde_json::to_string_pretty(&expected).unwrap());
+/// ```
+///
+/// In this example, the serialized format contains duplicate keys, which is not supported with [`HashMap`] or [`BTreeMap`].
+///
+/// ```
+/// # extern crate serde;
+/// # extern crate serde_derive;
+/// # extern crate serde_json;
+/// # extern crate serde_with;
+/// #
+/// # use serde_derive::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// #
+/// #[derive(Debug, Deserialize, Serialize, PartialEq, Default)]
+/// struct S {
+/// #[serde(with = "serde_with::rust::tuple_list_as_map")]
+/// s: Vec<(i32, String)>,
+/// }
+///
+/// let from = r#"{
+/// "s": {
+/// "1": "Hi",
+/// "1": "Cake",
+/// "1": "Lie"
+/// }
+/// }"#;
+/// let mut expected = S::default();
+/// expected.s.push((1, "Hi".into()));
+/// expected.s.push((1, "Cake".into()));
+/// expected.s.push((1, "Lie".into()));
+///
+/// let res: S = serde_json::from_str(from).unwrap();
+/// assert_eq!(3, res.s.len());
+/// assert_eq!(expected, res);
+/// assert_eq!(from, serde_json::to_string_pretty(&expected).unwrap());
+/// ```
+pub mod tuple_list_as_map {
+ use super::{SerializeMap, *}; // Needed to remove the unused import warning in the parent scope
+
+ /// Serialize any iteration of tuples into a map.
+ pub fn serialize<'a, I, K, V, S>(iter: I, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ I: IntoIterator<Item = &'a (K, V)>,
+ I::IntoIter: ExactSizeIterator,
+ K: Serialize + 'a,
+ V: Serialize + 'a,
+ S: Serializer,
+ {
+ let iter = iter.into_iter();
+ let mut map = serializer.serialize_map(Some(iter.len()))?;
+ for (key, value) in iter {
+ map.serialize_entry(&key, &value)?;
+ }
+ map.end()
+ }
+
+ /// Deserialize a map into an iterator of tuples.
+ pub fn deserialize<'de, I, K, V, D>(deserializer: D) -> Result<I, D::Error>
+ where
+ I: FromIterator<(K, V)>,
+ K: Deserialize<'de>,
+ V: Deserialize<'de>,
+ D: Deserializer<'de>,
+ {
+ deserializer.deserialize_map(MapVisitor(PhantomData))
+ }
+
+ #[cfg_attr(feature = "cargo-clippy", allow(type_complexity))]
+ struct MapVisitor<I, K, V>(PhantomData<fn() -> (I, K, V)>);
+
+ impl<'de, I, K, V> Visitor<'de> for MapVisitor<I, K, V>
+ where
+ I: FromIterator<(K, V)>,
+ K: Deserialize<'de>,
+ V: Deserialize<'de>,
+ {
+ type Value = I;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a map")
+ }
+
+ fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
+ where
+ A: MapAccess<'de>,
+ {
+ let iter = MapIter(map, PhantomData);
+ iter.collect()
+ }
+ }
+
+ struct MapIter<'de, A, K, V>(A, PhantomData<(&'de (), A, K, V)>);
+
+ impl<'de, A, K, V> Iterator for MapIter<'de, A, K, V>
+ where
+ A: MapAccess<'de>,
+ K: Deserialize<'de>,
+ V: Deserialize<'de>,
+ {
+ type Item = Result<(K, V), A::Error>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ match self.0.next_entry() {
+ Ok(Some(x)) => Some(Ok(x)),
+ Ok(None) => None,
+ Err(err) => Some(Err(err)),
+ }
+ }
+ }
+}
+
+/// Deserialize from bytes or String
+///
+/// Any Rust [`String`] can be converted into bytes ([`Vec`]`<u8>`).
+/// Accepting both as formats while deserializing can be helpful while interacting with language
+/// which have a looser definition of string than Rust.
+///
+/// # Example
+/// ```rust
+/// # extern crate serde;
+/// # extern crate serde_derive;
+/// # extern crate serde_json;
+/// # extern crate serde_with;
+/// #
+/// # use serde_derive::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// #
+/// #[derive(Debug, Deserialize, Serialize, PartialEq, Default)]
+/// struct S {
+/// #[serde(deserialize_with = "serde_with::rust::bytes_or_string::deserialize")]
+/// bos: Vec<u8>,
+/// }
+///
+/// // Here we deserialize from a byte array ...
+/// let from = r#"{
+/// "bos": [
+/// 0,
+/// 1,
+/// 2,
+/// 3
+/// ]
+/// }"#;
+/// let expected = S {
+/// bos: vec![0, 1, 2, 3],
+/// };
+///
+/// let res: S = serde_json::from_str(from).unwrap();
+/// assert_eq!(expected, res);
+///
+/// // and serialization works too.
+/// assert_eq!(from, serde_json::to_string_pretty(&expected).unwrap());
+///
+/// // But we also support deserializing from String
+/// let from = r#"{
+/// "bos": "✨Works!"
+/// }"#;
+/// let expected = S {
+/// bos: "✨Works!".as_bytes().to_vec(),
+/// };
+///
+/// let res: S = serde_json::from_str(from).unwrap();
+/// assert_eq!(expected, res);
+/// ```
+pub mod bytes_or_string {
+ use super::*;
+
+ /// Deserialize a [`Vec`]`<u8>` from either bytes or string
+ pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ deserializer.deserialize_any(BytesOrStringVisitor)
+ }
+
+ struct BytesOrStringVisitor;
+
+ impl<'de> Visitor<'de> for BytesOrStringVisitor {
+ type Value = Vec<u8>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("a list of bytes or a string")
+ }
+
+ fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E> {
+ Ok(v.to_vec())
+ }
+
+ fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E> {
+ Ok(v)
+ }
+
+ fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> {
+ Ok(v.as_bytes().to_vec())
+ }
+
+ fn visit_string<E>(self, v: String) -> Result<Self::Value, E> {
+ Ok(v.into_bytes())
+ }
+
+ fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
+ where
+ A: SeqAccess<'de>,
+ {
+ let mut res = Vec::with_capacity(seq.size_hint().unwrap_or(0));
+ while let Some(value) = seq.next_element()? {
+ res.push(value);
+ }
+ Ok(res)
+ }
+ }
+}
+
+/// Deserialize value and return [`Default`] on error
+///
+/// The main use case is ignoring error while deserializing.
+/// Instead of erroring, it simply deserializes the [`Default`] variant of the type.
+/// It is not possible to find the error location, i.e., which field had a deserialization error, with this method.
+///
+/// # Examples
+///
+/// ```
+/// # extern crate serde;
+/// # extern crate serde_derive;
+/// # extern crate serde_json;
+/// # extern crate serde_with;
+/// #
+/// # use serde_derive::Deserialize;
+/// #
+/// #[derive(Deserialize)]
+/// struct A {
+/// #[serde(deserialize_with = "serde_with::rust::default_on_error::deserialize")]
+/// value: u32,
+/// }
+///
+/// let a: A = serde_json::from_str(r#"{"value": 123}"#).unwrap();
+/// assert_eq!(123, a.value);
+///
+/// // null is of invalid type
+/// let a: A = serde_json::from_str(r#"{"value": null}"#).unwrap();
+/// assert_eq!(0, a.value);
+///
+/// // String is of invalid type
+/// let a: A = serde_json::from_str(r#"{"value": "123"}"#).unwrap();
+/// assert_eq!(0, a.value);
+///
+/// // Missing entries still cause errors
+/// assert!(serde_json::from_str::<A>(r#"{ }"#).is_err());
+/// ```
+///
+/// Deserializing missing values can be supported by adding the `default` field attribute:
+///
+/// ```
+/// # extern crate serde;
+/// # extern crate serde_derive;
+/// # extern crate serde_json;
+/// # extern crate serde_with;
+/// #
+/// # use serde_derive::Deserialize;
+/// #
+/// #[derive(Deserialize)]
+/// struct B {
+/// #[serde(default, deserialize_with = "serde_with::rust::default_on_error::deserialize")]
+/// value: u32,
+/// }
+///
+///
+/// let b: B = serde_json::from_str(r#"{ }"#).unwrap();
+/// assert_eq!(0, b.value);
+/// ```
+pub mod default_on_error {
+ use super::*;
+
+ /// Deserialize T and return the [`Default`] value on error
+ pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
+ where
+ D: Deserializer<'de>,
+ T: Deserialize<'de> + Default,
+ {
+ T::deserialize(deserializer).or_else(|_| Ok(Default::default()))
+ }
+}
+
+/// Deserialize default value if encountering `null`.
+///
+/// One use case are JSON APIs in which the `null` value represents some default state.
+/// This adapter allows to turn the `null` directly into the [`Default`] value of the type.
+///
+/// # Examples
+///
+/// ```
+/// # extern crate serde;
+/// # extern crate serde_derive;
+/// # extern crate serde_json;
+/// # extern crate serde_with;
+/// #
+/// # use serde_derive::Deserialize;
+/// #
+/// #[derive(Deserialize)]
+/// struct A {
+/// #[serde(deserialize_with = "serde_with::rust::default_on_null::deserialize")]
+/// value: u32,
+/// }
+///
+/// let a: A = serde_json::from_str(r#"{"value": 123}"#).unwrap();
+/// assert_eq!(123, a.value);
+///
+/// let a: A = serde_json::from_str(r#"{"value": null}"#).unwrap();
+/// assert_eq!(0, a.value);
+///
+/// // String is invalid type
+/// assert!(serde_json::from_str::<A>(r#"{"value": "123"}"#).is_err());
+/// ```
+pub mod default_on_null {
+ use super::*;
+
+ /// Deserialize T and return the [`Default`] value if original value is `null`
+ pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
+ where
+ D: Deserializer<'de>,
+ T: Deserialize<'de> + Default,
+ {
+ Ok(Option::deserialize(deserializer)?.unwrap_or_default())
+ }
+}
diff --git a/third_party/rust/serde_with/src/with_prefix.rs b/third_party/rust/serde_with/src/with_prefix.rs
new file mode 100644
index 0000000000..776927d365
--- /dev/null
+++ b/third_party/rust/serde_with/src/with_prefix.rs
@@ -0,0 +1,607 @@
+use std::fmt;
+
+use serde::{
+ de::{self, DeserializeSeed, Deserializer, IgnoredAny, IntoDeserializer, MapAccess, Visitor},
+ forward_to_deserialize_any,
+ ser::{self, Impossible, Serialize, SerializeMap, SerializeStruct, Serializer},
+};
+
+/// Serialize with an added prefix on every field name and deserialize by
+/// trimming away the prefix.
+///
+/// **Note:** Use of this macro is incompatible with applying the [`deny_unknown_fields`] attribute
+/// on the container.
+/// While deserializing, it will always warn about unknown fields, even though they are processed
+/// by the `with_prefix` wrapper.
+/// More details can be found in [this issue][issue-with_prefix-deny_unknown_fields].
+///
+/// # Example
+///
+/// The [Challonge REST API] likes to use prefixes to group related fields. In
+/// simplified form, their JSON may resemble the following:
+///
+/// [Challonge REST API]: https://api.challonge.com/v1/documents/matches/show
+///
+/// ```json
+/// {
+/// "player1_name": "name1",
+/// "player1_votes": 1,
+/// "player2_name": "name2",
+/// "player2_votes": 2
+/// }
+/// ```
+///
+/// In Rust we would ideally like to model this data as a pair of `Player`
+/// structs, rather than repeating the fields of `Player` for each prefix.
+///
+/// ```rust
+/// struct Match {
+/// player1: Player,
+/// player2: Player,
+/// }
+///
+/// struct Player {
+/// name: String,
+/// votes: u64,
+/// }
+/// ```
+///
+/// This `with_prefix!` macro produces an adapter that adds a prefix onto field
+/// names during serialization and trims away the prefix during deserialization.
+/// An implementation of the Challonge API would use `with_prefix!` like this:
+///
+/// ```rust
+/// extern crate serde_derive;
+/// extern crate serde_json;
+/// extern crate serde_with;
+///
+/// use serde_derive::{Deserialize, Serialize};
+/// use serde_json::json;
+/// use serde_with::with_prefix;
+///
+/// #[derive(Serialize, Deserialize)]
+/// struct Match {
+/// #[serde(flatten, with = "prefix_player1")]
+/// player1: Player,
+/// #[serde(flatten, with = "prefix_player2")]
+/// player2: Player,
+/// }
+///
+/// #[derive(Serialize, Deserialize)]
+/// struct Player {
+/// name: String,
+/// votes: u64,
+/// }
+///
+/// with_prefix!(prefix_player1 "player1_");
+/// with_prefix!(prefix_player2 "player2_");
+/// #
+/// # const EXPECTED: &str = r#"{
+/// # "player1_name": "name1",
+/// # "player1_votes": 1,
+/// # "player2_name": "name2",
+/// # "player2_votes": 2
+/// # }"#;
+///
+/// fn main() {
+/// let m = Match {
+/// player1: Player {
+/// name: "name1".to_owned(),
+/// votes: 1,
+/// },
+/// player2: Player {
+/// name: "name2".to_owned(),
+/// votes: 2,
+/// },
+/// };
+///
+/// let j = serde_json::to_string_pretty(&m).unwrap();
+/// println!("{}", j);
+/// #
+/// # assert_eq!(j, EXPECTED);
+/// }
+/// ```
+///
+/// [`deny_unknown_fields`]: https://serde.rs/container-attrs.html#deny_unknown_fields
+/// [issue-with_prefix-deny_unknown_fields]: https://github.com/jonasbb/serde_with/issues/57
+#[macro_export]
+macro_rules! with_prefix {
+ ($module:ident $prefix:expr) => {
+ mod $module {
+ use $crate::{
+ serde::{Deserialize, Deserializer, Serialize, Serializer},
+ with_prefix::WithPrefix,
+ };
+
+ #[allow(dead_code)]
+ pub fn serialize<T, S>(object: &T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ T: Serialize,
+ S: Serializer,
+ {
+ object.serialize(WithPrefix {
+ delegate: serializer,
+ prefix: $prefix,
+ })
+ }
+
+ #[allow(dead_code)]
+ pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
+ where
+ T: Deserialize<'de>,
+ D: Deserializer<'de>,
+ {
+ T::deserialize(WithPrefix {
+ delegate: deserializer,
+ prefix: $prefix,
+ })
+ }
+ }
+ };
+}
+
+#[allow(missing_debug_implementations)]
+pub struct WithPrefix<'a, T> {
+ pub delegate: T,
+ pub prefix: &'a str,
+}
+
+impl<'a, T> Serialize for WithPrefix<'a, T>
+where
+ T: Serialize,
+{
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ self.delegate.serialize(WithPrefix {
+ delegate: serializer,
+ prefix: self.prefix,
+ })
+ }
+}
+
+impl<'a, S> Serializer for WithPrefix<'a, S>
+where
+ S: Serializer,
+{
+ type Ok = S::Ok;
+ type Error = S::Error;
+ type SerializeSeq = Impossible<Self::Ok, Self::Error>;
+ type SerializeTuple = Impossible<Self::Ok, Self::Error>;
+ type SerializeTupleStruct = Impossible<Self::Ok, Self::Error>;
+ type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
+ type SerializeMap = WithPrefix<'a, S::SerializeMap>;
+ type SerializeStruct = WithPrefix<'a, S::SerializeMap>;
+ type SerializeStructVariant = Impossible<Self::Ok, Self::Error>;
+
+ fn serialize_bool(self, _v: bool) -> Result<Self::Ok, Self::Error> {
+ Err(ser::Error::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_i8(self, _v: i8) -> Result<Self::Ok, Self::Error> {
+ Err(ser::Error::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_i16(self, _v: i16) -> Result<Self::Ok, Self::Error> {
+ Err(ser::Error::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_i32(self, _v: i32) -> Result<Self::Ok, Self::Error> {
+ Err(ser::Error::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_i64(self, _v: i64) -> Result<Self::Ok, Self::Error> {
+ Err(ser::Error::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_u8(self, _v: u8) -> Result<Self::Ok, Self::Error> {
+ Err(ser::Error::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_u16(self, _v: u16) -> Result<Self::Ok, Self::Error> {
+ Err(ser::Error::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_u32(self, _v: u32) -> Result<Self::Ok, Self::Error> {
+ Err(ser::Error::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_u64(self, _v: u64) -> Result<Self::Ok, Self::Error> {
+ Err(ser::Error::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_f32(self, _v: f32) -> Result<Self::Ok, Self::Error> {
+ Err(ser::Error::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_f64(self, _v: f64) -> Result<Self::Ok, Self::Error> {
+ Err(ser::Error::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_char(self, _v: char) -> Result<Self::Ok, Self::Error> {
+ Err(ser::Error::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> {
+ self.delegate
+ .collect_str(&format_args!("{}{}", self.prefix, v))
+ }
+
+ fn serialize_bytes(self, _v: &[u8]) -> Result<Self::Ok, Self::Error> {
+ Err(ser::Error::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
+ self.delegate.serialize_none()
+ }
+
+ fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
+ where
+ T: ?Sized + Serialize,
+ {
+ self.delegate.serialize_some(&WithPrefix {
+ delegate: value,
+ prefix: self.prefix,
+ })
+ }
+
+ fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
+ Err(ser::Error::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
+ Err(ser::Error::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_unit_variant(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ ) -> Result<Self::Ok, Self::Error> {
+ Err(ser::Error::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_newtype_struct<T>(
+ self,
+ _name: &'static str,
+ _value: &T,
+ ) -> Result<Self::Ok, Self::Error>
+ where
+ T: ?Sized + Serialize,
+ {
+ Err(ser::Error::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_newtype_variant<T>(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ _value: &T,
+ ) -> Result<Self::Ok, Self::Error>
+ where
+ T: ?Sized + Serialize,
+ {
+ Err(ser::Error::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
+ Err(ser::Error::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
+ Err(ser::Error::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_tuple_struct(
+ self,
+ _name: &'static str,
+ _len: usize,
+ ) -> Result<Self::SerializeTupleStruct, Self::Error> {
+ Err(ser::Error::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_tuple_variant(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ _len: usize,
+ ) -> Result<Self::SerializeTupleVariant, Self::Error> {
+ Err(ser::Error::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
+ Ok(WithPrefix {
+ delegate: self.delegate.serialize_map(len)?,
+ prefix: self.prefix,
+ })
+ }
+
+ fn serialize_struct(
+ self,
+ _name: &'static str,
+ len: usize,
+ ) -> Result<Self::SerializeStruct, Self::Error> {
+ self.serialize_map(Some(len))
+ }
+
+ fn serialize_struct_variant(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ _len: usize,
+ ) -> Result<Self::SerializeStructVariant, Self::Error> {
+ Err(ser::Error::custom("wrong type for with_prefix"))
+ }
+}
+
+impl<'a, S> SerializeMap for WithPrefix<'a, S>
+where
+ S: SerializeMap,
+{
+ type Ok = S::Ok;
+ type Error = S::Error;
+
+ fn serialize_key<T>(&mut self, key: &T) -> Result<(), Self::Error>
+ where
+ T: ?Sized + Serialize,
+ {
+ self.delegate.serialize_key(&WithPrefix {
+ delegate: key,
+ prefix: self.prefix,
+ })
+ }
+
+ fn serialize_value<T>(&mut self, value: &T) -> Result<(), Self::Error>
+ where
+ T: ?Sized + Serialize,
+ {
+ self.delegate.serialize_value(value)
+ }
+
+ fn serialize_entry<K, V>(&mut self, key: &K, value: &V) -> Result<(), Self::Error>
+ where
+ K: ?Sized + Serialize,
+ V: ?Sized + Serialize,
+ {
+ self.delegate.serialize_entry(
+ &WithPrefix {
+ delegate: key,
+ prefix: self.prefix,
+ },
+ value,
+ )
+ }
+
+ fn end(self) -> Result<Self::Ok, Self::Error> {
+ self.delegate.end()
+ }
+}
+
+impl<'a, S> SerializeStruct for WithPrefix<'a, S>
+where
+ S: SerializeMap,
+{
+ type Ok = S::Ok;
+ type Error = S::Error;
+
+ fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
+ where
+ T: ?Sized + Serialize,
+ {
+ self.delegate
+ .serialize_entry(&format!("{}{}", self.prefix, key), value)
+ }
+
+ fn end(self) -> Result<Self::Ok, Self::Error> {
+ self.delegate.end()
+ }
+}
+
+impl<'de, 'a, T> DeserializeSeed<'de> for WithPrefix<'a, T>
+where
+ T: DeserializeSeed<'de>,
+{
+ type Value = T::Value;
+
+ fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ self.delegate.deserialize(WithPrefix {
+ delegate: deserializer,
+ prefix: self.prefix,
+ })
+ }
+}
+
+impl<'de, 'a, D> Deserializer<'de> for WithPrefix<'a, D>
+where
+ D: Deserializer<'de>,
+{
+ type Error = D::Error;
+
+ fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.delegate.deserialize_map(WithPrefix {
+ delegate: visitor,
+ prefix: self.prefix,
+ })
+ }
+
+ fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.delegate.deserialize_any(WithPrefixOption {
+ first_key: None,
+ delegate: visitor,
+ prefix: self.prefix,
+ })
+ }
+
+ fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.delegate.deserialize_identifier(WithPrefix {
+ delegate: visitor,
+ prefix: self.prefix,
+ })
+ }
+
+ forward_to_deserialize_any! {
+ bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
+ bytes byte_buf unit unit_struct newtype_struct seq tuple tuple_struct
+ map struct enum ignored_any
+ }
+}
+
+impl<'de, 'a, V> Visitor<'de> for WithPrefix<'a, V>
+where
+ V: Visitor<'de>,
+{
+ type Value = V::Value;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ self.delegate.expecting(formatter)
+ }
+
+ fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
+ where
+ A: MapAccess<'de>,
+ {
+ self.delegate.visit_map(WithPrefix {
+ delegate: map,
+ prefix: self.prefix,
+ })
+ }
+}
+
+impl<'de, 'a, A> MapAccess<'de> for WithPrefix<'a, A>
+where
+ A: MapAccess<'de>,
+{
+ type Error = A::Error;
+
+ fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
+ where
+ K: DeserializeSeed<'de>,
+ {
+ while let Some(s) = self.delegate.next_key::<String>()? {
+ if s.starts_with(self.prefix) {
+ let without_prefix = s[self.prefix.len()..].into_deserializer();
+ return seed.deserialize(without_prefix).map(Some);
+ }
+ self.delegate.next_value::<IgnoredAny>()?;
+ }
+ Ok(None)
+ }
+
+ fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
+ where
+ V: DeserializeSeed<'de>,
+ {
+ self.delegate.next_value_seed(seed)
+ }
+}
+
+#[allow(missing_debug_implementations)]
+pub struct WithPrefixOption<'a, T> {
+ first_key: Option<String>,
+ delegate: T,
+ prefix: &'a str,
+}
+
+impl<'de, 'a, V> Visitor<'de> for WithPrefixOption<'a, V>
+where
+ V: Visitor<'de>,
+{
+ type Value = V::Value;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ self.delegate.expecting(formatter)
+ }
+
+ fn visit_unit<E>(self) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ self.delegate.visit_none()
+ }
+
+ fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
+ where
+ A: MapAccess<'de>,
+ {
+ while let Some(s) = map.next_key::<String>()? {
+ if s.starts_with(self.prefix) {
+ return self.delegate.visit_some(WithPrefixOption {
+ first_key: Some(s),
+ delegate: map,
+ prefix: self.prefix,
+ });
+ }
+ map.next_value::<IgnoredAny>()?;
+ }
+ self.delegate.visit_none()
+ }
+}
+
+impl<'de, 'a, A> Deserializer<'de> for WithPrefixOption<'a, A>
+where
+ A: MapAccess<'de>,
+{
+ type Error = A::Error;
+
+ fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_map(self)
+ }
+
+ forward_to_deserialize_any! {
+ bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
+ bytes byte_buf option unit unit_struct newtype_struct seq tuple
+ tuple_struct map struct enum identifier ignored_any
+ }
+}
+
+impl<'de, 'a, A> MapAccess<'de> for WithPrefixOption<'a, A>
+where
+ A: MapAccess<'de>,
+{
+ type Error = A::Error;
+
+ fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
+ where
+ K: DeserializeSeed<'de>,
+ {
+ if let Some(s) = self.first_key.take() {
+ let without_prefix = s[self.prefix.len()..].into_deserializer();
+ return seed.deserialize(without_prefix).map(Some);
+ }
+ while let Some(s) = self.delegate.next_key::<String>()? {
+ if s.starts_with(self.prefix) {
+ let without_prefix = s[self.prefix.len()..].into_deserializer();
+ return seed.deserialize(without_prefix).map(Some);
+ }
+ self.delegate.next_value::<IgnoredAny>()?;
+ }
+ Ok(None)
+ }
+
+ fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
+ where
+ V: DeserializeSeed<'de>,
+ {
+ self.delegate.next_value_seed(seed)
+ }
+}
diff --git a/third_party/rust/serde_with/tests/chrono.rs b/third_party/rust/serde_with/tests/chrono.rs
new file mode 100644
index 0000000000..e20106e62b
--- /dev/null
+++ b/third_party/rust/serde_with/tests/chrono.rs
@@ -0,0 +1,53 @@
+#![cfg(feature = "chrono")]
+
+extern crate chrono;
+extern crate pretty_assertions;
+extern crate serde;
+extern crate serde_derive;
+extern crate serde_json;
+extern crate serde_with;
+
+use chrono::{DateTime, NaiveDateTime, Utc};
+use pretty_assertions::assert_eq;
+use serde_derive::Deserialize;
+
+fn new_datetime(secs: i64, nsecs: u32) -> DateTime<Utc> {
+ DateTime::from_utc(NaiveDateTime::from_timestamp(secs, nsecs), Utc)
+}
+
+#[test]
+fn json_datetime_from_any_to_string_deserialization() {
+ #[derive(Debug, Deserialize)]
+ struct S {
+ #[serde(with = "serde_with::chrono::datetime_utc_ts_seconds_from_any")]
+ date: DateTime<Utc>,
+ }
+ let from = r#"[
+ { "date": 1478563200 },
+ { "date": 0 },
+ { "date": -86000 },
+ { "date": 1478563200.123 },
+ { "date": 0.000 },
+ { "date": -86000.999 },
+ { "date": "1478563200.123" },
+ { "date": "0.000" },
+ { "date": "-86000.999" }
+ ]"#;
+
+ let res: Vec<S> = serde_json::from_str(from).unwrap();
+
+ // just integers
+ assert_eq!(new_datetime(1_478_563_200, 0), res[0].date);
+ assert_eq!(new_datetime(0, 0), res[1].date);
+ assert_eq!(new_datetime(-86000, 0), res[2].date);
+
+ // floats, shows precision errors in subsecond part
+ assert_eq!(new_datetime(1_478_563_200, 122_999_906), res[3].date);
+ assert_eq!(new_datetime(0, 0), res[4].date);
+ assert_eq!(new_datetime(-86000, 998_999_999), res[5].date);
+
+ // string representation of floats
+ assert_eq!(new_datetime(1_478_563_200, 123_000_000), res[6].date);
+ assert_eq!(new_datetime(0, 0), res[7].date);
+ assert_eq!(new_datetime(-86000, 999_000_000), res[8].date);
+}
diff --git a/third_party/rust/serde_with/tests/rust.rs b/third_party/rust/serde_with/tests/rust.rs
new file mode 100644
index 0000000000..cd317c6f77
--- /dev/null
+++ b/third_party/rust/serde_with/tests/rust.rs
@@ -0,0 +1,573 @@
+extern crate fnv;
+extern crate pretty_assertions;
+extern crate serde;
+extern crate serde_derive;
+extern crate serde_json;
+extern crate serde_with;
+
+use fnv::FnvHashMap;
+use pretty_assertions::assert_eq;
+use serde_derive::{Deserialize, Serialize};
+use serde_json::error::Category;
+use serde_with::CommaSeparator;
+use std::collections::{BTreeMap, HashMap, LinkedList, VecDeque};
+
+#[test]
+fn string_collection() {
+ #[derive(Debug, Deserialize)]
+ struct S {
+ #[serde(with = "serde_with::rust::StringWithSeparator::<CommaSeparator>")]
+ s: Vec<String>,
+ }
+ let from = r#"[
+ { "s": "A,B,C,D" },
+ { "s": ",," },
+ { "s": "AVeryLongString" }
+ ]"#;
+
+ let res: Vec<S> = serde_json::from_str(from).unwrap();
+ assert_eq!(
+ vec![
+ "A".to_string(),
+ "B".to_string(),
+ "C".to_string(),
+ "D".to_string(),
+ ],
+ res[0].s
+ );
+ assert_eq!(
+ vec!["".to_string(), "".to_string(), "".to_string()],
+ res[1].s
+ );
+ assert_eq!(vec!["AVeryLongString".to_string()], res[2].s);
+}
+
+#[test]
+fn string_collection_non_existing() {
+ #[derive(Debug, Deserialize, Serialize)]
+ struct S {
+ #[serde(with = "serde_with::rust::StringWithSeparator::<CommaSeparator>")]
+ s: Vec<String>,
+ }
+ let from = r#"[
+ { "s": "" }
+ ]"#;
+
+ let res: Vec<S> = serde_json::from_str(from).unwrap();
+ assert_eq!(Vec::<String>::new(), res[0].s);
+
+ assert_eq!(r#"{"s":""}"#, serde_json::to_string(&res[0]).unwrap());
+}
+
+#[test]
+fn prohibit_duplicate_value_hashset() {
+ use std::{collections::HashSet, iter::FromIterator};
+ #[derive(Debug, Eq, PartialEq, Deserialize)]
+ struct Doc {
+ #[serde(with = "::serde_with::rust::sets_duplicate_value_is_error")]
+ set: HashSet<usize>,
+ }
+
+ let s = r#"{"set": [1, 2, 3, 4]}"#;
+ let v = Doc {
+ set: HashSet::from_iter(vec![1, 2, 3, 4]),
+ };
+ assert_eq!(v, serde_json::from_str(s).unwrap());
+
+ let s = r#"{"set": [1, 2, 3, 4, 1]}"#;
+ let res: Result<Doc, _> = serde_json::from_str(s);
+ assert!(res.is_err());
+}
+
+#[test]
+fn prohibit_duplicate_value_btreeset() {
+ use std::{collections::BTreeSet, iter::FromIterator};
+ #[derive(Debug, Eq, PartialEq, Deserialize)]
+ struct Doc {
+ #[serde(with = "::serde_with::rust::sets_duplicate_value_is_error")]
+ set: BTreeSet<usize>,
+ }
+
+ let s = r#"{"set": [1, 2, 3, 4]}"#;
+ let v = Doc {
+ set: BTreeSet::from_iter(vec![1, 2, 3, 4]),
+ };
+ assert_eq!(v, serde_json::from_str(s).unwrap());
+
+ let s = r#"{"set": [1, 2, 3, 4, 1]}"#;
+ let res: Result<Doc, _> = serde_json::from_str(s);
+ assert!(res.is_err());
+}
+
+#[test]
+fn prohibit_duplicate_value_hashmap() {
+ use std::collections::HashMap;
+ #[derive(Debug, Eq, PartialEq, Deserialize)]
+ struct Doc {
+ #[serde(with = "::serde_with::rust::maps_duplicate_key_is_error")]
+ map: HashMap<usize, usize>,
+ }
+
+ // Different value and key always works
+ let s = r#"{"map": {"1": 1, "2": 2, "3": 3}}"#;
+ let mut v = Doc {
+ map: HashMap::new(),
+ };
+ v.map.insert(1, 1);
+ v.map.insert(2, 2);
+ v.map.insert(3, 3);
+ assert_eq!(v, serde_json::from_str(s).unwrap());
+
+ // Same value for different keys is ok
+ let s = r#"{"map": {"1": 1, "2": 1, "3": 1}}"#;
+ let mut v = Doc {
+ map: HashMap::new(),
+ };
+ v.map.insert(1, 1);
+ v.map.insert(2, 1);
+ v.map.insert(3, 1);
+ assert_eq!(v, serde_json::from_str(s).unwrap());
+
+ // Duplicate keys are an error
+ let s = r#"{"map": {"1": 1, "2": 2, "1": 3}}"#;
+ let res: Result<Doc, _> = serde_json::from_str(s);
+ assert!(res.is_err());
+}
+
+#[test]
+fn prohibit_duplicate_value_btreemap() {
+ use std::collections::BTreeMap;
+ #[derive(Debug, Eq, PartialEq, Deserialize)]
+ struct Doc {
+ #[serde(with = "::serde_with::rust::maps_duplicate_key_is_error")]
+ map: BTreeMap<usize, usize>,
+ }
+
+ // Different value and key always works
+ let s = r#"{"map": {"1": 1, "2": 2, "3": 3}}"#;
+ let mut v = Doc {
+ map: BTreeMap::new(),
+ };
+ v.map.insert(1, 1);
+ v.map.insert(2, 2);
+ v.map.insert(3, 3);
+ assert_eq!(v, serde_json::from_str(s).unwrap());
+
+ // Same value for different keys is ok
+ let s = r#"{"map": {"1": 1, "2": 1, "3": 1}}"#;
+ let mut v = Doc {
+ map: BTreeMap::new(),
+ };
+ v.map.insert(1, 1);
+ v.map.insert(2, 1);
+ v.map.insert(3, 1);
+ assert_eq!(v, serde_json::from_str(s).unwrap());
+
+ // Duplicate keys are an error
+ let s = r#"{"map": {"1": 1, "2": 2, "1": 3}}"#;
+ let res: Result<Doc, _> = serde_json::from_str(s);
+ assert!(res.is_err());
+}
+
+#[test]
+fn duplicate_key_first_wins_hashmap() {
+ use std::collections::HashMap;
+ #[derive(Debug, Eq, PartialEq, Deserialize)]
+ struct Doc {
+ #[serde(with = "::serde_with::rust::maps_first_key_wins")]
+ map: HashMap<usize, usize>,
+ }
+
+ // Different value and key always works
+ let s = r#"{"map": {"1": 1, "2": 2, "3": 3}}"#;
+ let mut v = Doc {
+ map: HashMap::new(),
+ };
+ v.map.insert(1, 1);
+ v.map.insert(2, 2);
+ v.map.insert(3, 3);
+ assert_eq!(v, serde_json::from_str(s).unwrap());
+
+ // Same value for different keys is ok
+ let s = r#"{"map": {"1": 1, "2": 1, "3": 1}}"#;
+ let mut v = Doc {
+ map: HashMap::new(),
+ };
+ v.map.insert(1, 1);
+ v.map.insert(2, 1);
+ v.map.insert(3, 1);
+ assert_eq!(v, serde_json::from_str(s).unwrap());
+
+ // Duplicate keys, the first one is used
+ let s = r#"{"map": {"1": 1, "2": 2, "1": 3}}"#;
+ let mut v = Doc {
+ map: HashMap::new(),
+ };
+ v.map.insert(1, 1);
+ v.map.insert(2, 2);
+ assert_eq!(v, serde_json::from_str(s).unwrap());
+}
+
+#[test]
+fn duplicate_key_first_wins_btreemap() {
+ use std::collections::BTreeMap;
+ #[derive(Debug, Eq, PartialEq, Deserialize)]
+ struct Doc {
+ #[serde(with = "::serde_with::rust::maps_first_key_wins")]
+ map: BTreeMap<usize, usize>,
+ }
+
+ // Different value and key always works
+ let s = r#"{"map": {"1": 1, "2": 2, "3": 3}}"#;
+ let mut v = Doc {
+ map: BTreeMap::new(),
+ };
+ v.map.insert(1, 1);
+ v.map.insert(2, 2);
+ v.map.insert(3, 3);
+ assert_eq!(v, serde_json::from_str(s).unwrap());
+
+ // Same value for different keys is ok
+ let s = r#"{"map": {"1": 1, "2": 1, "3": 1}}"#;
+ let mut v = Doc {
+ map: BTreeMap::new(),
+ };
+ v.map.insert(1, 1);
+ v.map.insert(2, 1);
+ v.map.insert(3, 1);
+ assert_eq!(v, serde_json::from_str(s).unwrap());
+
+ // Duplicate keys, the first one is used
+ let s = r#"{"map": {"1": 1, "2": 2, "1": 3}}"#;
+ let mut v = Doc {
+ map: BTreeMap::new(),
+ };
+ v.map.insert(1, 1);
+ v.map.insert(2, 2);
+ assert_eq!(v, serde_json::from_str(s).unwrap());
+}
+
+#[test]
+fn test_hashmap_as_tuple_list() {
+ #[derive(Debug, Deserialize, Serialize, PartialEq, Default)]
+ struct S {
+ #[serde(with = "serde_with::rust::hashmap_as_tuple_list")]
+ s: HashMap<String, u8>,
+ }
+ let from = r#"{
+ "s": [
+ ["ABC", 1],
+ ["Hello", 0],
+ ["World", 20]
+ ]
+ }"#;
+ let mut expected = S::default();
+ expected.s.insert("ABC".to_string(), 1);
+ expected.s.insert("Hello".to_string(), 0);
+ expected.s.insert("World".to_string(), 20);
+
+ let res: S = serde_json::from_str(from).unwrap();
+ assert_eq!(expected, res);
+
+ let from = r#"{
+ "s": [
+ [
+ "Hello",
+ 0
+ ]
+ ]
+}"#;
+ let mut expected = S::default();
+ expected.s.insert("Hello".to_string(), 0);
+
+ let res: S = serde_json::from_str(from).unwrap();
+ assert_eq!(expected, res);
+ // We can only do this with a HashMap of size 1 as otherwise the iteration order is unspecified
+ assert_eq!(from, serde_json::to_string_pretty(&expected).unwrap());
+
+ let from = r#"{
+ "s": []
+}"#;
+ let expected = S::default();
+ let res: S = serde_json::from_str(from).unwrap();
+ assert!(res.s.is_empty());
+ assert_eq!(from, serde_json::to_string_pretty(&expected).unwrap());
+
+ // Test parse error
+ let from = r#"{
+ "s": [ [1] ]
+}"#;
+ let res: Result<S, _> = serde_json::from_str(from);
+ assert!(res.is_err());
+ let err = res.unwrap_err();
+ println!("{:?}", err);
+ assert!(err.is_data());
+}
+
+#[test]
+fn test_hashmap_as_tuple_list_fnv() {
+ #[derive(Debug, Deserialize, Serialize, PartialEq, Default)]
+ struct S {
+ #[serde(with = "serde_with::rust::hashmap_as_tuple_list")]
+ s: FnvHashMap<String, u8>,
+ }
+ let from = r#"{
+ "s": [
+ ["ABC", 1],
+ ["Hello", 0],
+ ["World", 20]
+ ]
+ }"#;
+ let mut expected = S::default();
+ expected.s.insert("ABC".to_string(), 1);
+ expected.s.insert("Hello".to_string(), 0);
+ expected.s.insert("World".to_string(), 20);
+
+ let res: S = serde_json::from_str(from).unwrap();
+ assert_eq!(expected, res);
+
+ let from = r#"{
+ "s": [
+ [
+ "Hello",
+ 0
+ ]
+ ]
+}"#;
+ let mut expected = S::default();
+ expected.s.insert("Hello".to_string(), 0);
+
+ let res: S = serde_json::from_str(from).unwrap();
+ assert_eq!(expected, res);
+ // We can only do this with a HashMap of size 1 as otherwise the iteration order is unspecified
+ assert_eq!(from, serde_json::to_string_pretty(&expected).unwrap());
+
+ let from = r#"{
+ "s": []
+}"#;
+ let expected = S::default();
+ let res: S = serde_json::from_str(from).unwrap();
+ assert!(res.s.is_empty());
+ assert_eq!(from, serde_json::to_string_pretty(&expected).unwrap());
+
+ // Test parse error
+ let from = r#"{
+ "s": [ [1] ]
+}"#;
+ let res: Result<S, _> = serde_json::from_str(from);
+ assert!(res.is_err());
+ let err = res.unwrap_err();
+ println!("{:?}", err);
+ assert!(err.is_data());
+}
+
+#[test]
+fn test_btreemap_as_tuple_list() {
+ #[derive(Debug, Deserialize, Serialize, PartialEq, Default)]
+ struct S {
+ #[serde(with = "serde_with::rust::btreemap_as_tuple_list")]
+ s: BTreeMap<String, u8>,
+ }
+ let from = r#"{
+ "s": [
+ [
+ "ABC",
+ 1
+ ],
+ [
+ "Hello",
+ 0
+ ],
+ [
+ "World",
+ 20
+ ]
+ ]
+}"#;
+ let mut expected = S::default();
+ expected.s.insert("ABC".to_string(), 1);
+ expected.s.insert("Hello".to_string(), 0);
+ expected.s.insert("World".to_string(), 20);
+
+ let res: S = serde_json::from_str(from).unwrap();
+ assert_eq!(expected, res);
+ assert_eq!(from, serde_json::to_string_pretty(&expected).unwrap());
+
+ let from = r#"{
+ "s": [
+ [
+ "Hello",
+ 0
+ ]
+ ]
+}"#;
+ let mut expected = S::default();
+ expected.s.insert("Hello".to_string(), 0);
+
+ let res: S = serde_json::from_str(from).unwrap();
+ assert_eq!(expected, res);
+ assert_eq!(from, serde_json::to_string_pretty(&expected).unwrap());
+
+ let from = r#"{
+ "s": []
+}"#;
+ let expected = S::default();
+ let res: S = serde_json::from_str(from).unwrap();
+ assert!(res.s.is_empty());
+ assert_eq!(from, serde_json::to_string_pretty(&expected).unwrap());
+
+ // Test parse error
+ let from = r#"{
+ "s": [ [1] ]
+}"#;
+ let res: Result<S, _> = serde_json::from_str(from);
+ assert!(res.is_err());
+ let err = res.unwrap_err();
+ println!("{:?}", err);
+ assert!(err.is_data());
+}
+
+#[test]
+fn tuple_list_as_map_vec() {
+ #[derive(Debug, Deserialize, Serialize, Default)]
+ struct S {
+ #[serde(with = "serde_with::rust::tuple_list_as_map")]
+ s: Vec<(Wrapper<i32>, Wrapper<String>)>,
+ }
+
+ #[derive(Clone, Debug, Serialize, Deserialize)]
+ #[serde(transparent)]
+ struct Wrapper<T>(T);
+
+ let from = r#"{
+ "s": {
+ "1": "Hi",
+ "2": "Cake",
+ "99": "Lie"
+ }
+}"#;
+ let mut expected = S::default();
+ expected.s.push((Wrapper(1), Wrapper("Hi".into())));
+ expected.s.push((Wrapper(2), Wrapper("Cake".into())));
+ expected.s.push((Wrapper(99), Wrapper("Lie".into())));
+
+ let res: S = serde_json::from_str(from).unwrap();
+ for ((exp_k, exp_v), (res_k, res_v)) in expected.s.iter().zip(&res.s) {
+ assert_eq!(exp_k.0, res_k.0);
+ assert_eq!(exp_v.0, res_v.0);
+ }
+ assert_eq!(from, serde_json::to_string_pretty(&expected).unwrap());
+
+ let from = r#"{
+ "s": {}
+}"#;
+ let expected = S::default();
+
+ let res: S = serde_json::from_str(from).unwrap();
+ assert!(res.s.is_empty());
+ assert_eq!(from, serde_json::to_string_pretty(&expected).unwrap());
+
+ let from = r#"{
+ "s": []
+}"#;
+ let res: Result<S, _> = serde_json::from_str(from);
+ let res = res.unwrap_err();
+ assert_eq!(Category::Data, res.classify());
+ assert_eq!(
+ "invalid type: sequence, expected a map at line 2 column 7",
+ res.to_string()
+ );
+
+ let from = r#"{
+ "s": null
+}"#;
+ let res: Result<S, _> = serde_json::from_str(from);
+ let res = res.unwrap_err();
+ assert_eq!(Category::Data, res.classify());
+ assert_eq!(
+ "invalid type: null, expected a map at line 2 column 11",
+ res.to_string()
+ );
+}
+
+#[test]
+fn tuple_list_as_map_linkedlist() {
+ #[derive(Debug, Deserialize, Serialize, Default)]
+ struct S {
+ #[serde(with = "serde_with::rust::tuple_list_as_map")]
+ s: LinkedList<(Wrapper<i32>, Wrapper<String>)>,
+ }
+
+ #[derive(Clone, Debug, Serialize, Deserialize)]
+ #[serde(transparent)]
+ struct Wrapper<T>(T);
+
+ let from = r#"{
+ "s": {
+ "1": "Hi",
+ "2": "Cake",
+ "99": "Lie"
+ }
+}"#;
+ let mut expected = S::default();
+ expected.s.push_back((Wrapper(1), Wrapper("Hi".into())));
+ expected.s.push_back((Wrapper(2), Wrapper("Cake".into())));
+ expected.s.push_back((Wrapper(99), Wrapper("Lie".into())));
+
+ let res: S = serde_json::from_str(from).unwrap();
+ for ((exp_k, exp_v), (res_k, res_v)) in expected.s.iter().zip(&res.s) {
+ assert_eq!(exp_k.0, res_k.0);
+ assert_eq!(exp_v.0, res_v.0);
+ }
+ assert_eq!(from, serde_json::to_string_pretty(&expected).unwrap());
+
+ let from = r#"{
+ "s": {}
+}"#;
+ let expected = S::default();
+
+ let res: S = serde_json::from_str(from).unwrap();
+ assert!(res.s.is_empty());
+ assert_eq!(from, serde_json::to_string_pretty(&expected).unwrap());
+}
+
+#[test]
+fn tuple_list_as_map_vecdeque() {
+ #[derive(Debug, Deserialize, Serialize, Default)]
+ struct S {
+ #[serde(with = "serde_with::rust::tuple_list_as_map")]
+ s: VecDeque<(Wrapper<i32>, Wrapper<String>)>,
+ }
+
+ #[derive(Clone, Debug, Serialize, Deserialize)]
+ #[serde(transparent)]
+ struct Wrapper<T>(T);
+
+ let from = r#"{
+ "s": {
+ "1": "Hi",
+ "2": "Cake",
+ "99": "Lie"
+ }
+}"#;
+ let mut expected = S::default();
+ expected.s.push_back((Wrapper(1), Wrapper("Hi".into())));
+ expected.s.push_back((Wrapper(2), Wrapper("Cake".into())));
+ expected.s.push_back((Wrapper(99), Wrapper("Lie".into())));
+
+ let res: S = serde_json::from_str(from).unwrap();
+ for ((exp_k, exp_v), (res_k, res_v)) in expected.s.iter().zip(&res.s) {
+ assert_eq!(exp_k.0, res_k.0);
+ assert_eq!(exp_v.0, res_v.0);
+ }
+ assert_eq!(from, serde_json::to_string_pretty(&expected).unwrap());
+
+ let from = r#"{
+ "s": {}
+}"#;
+ let expected = S::default();
+
+ let res: S = serde_json::from_str(from).unwrap();
+ assert!(res.s.is_empty());
+ assert_eq!(from, serde_json::to_string_pretty(&expected).unwrap());
+}
diff --git a/third_party/rust/serde_with/tests/version_numbers.rs b/third_party/rust/serde_with/tests/version_numbers.rs
new file mode 100644
index 0000000000..fa24ed060a
--- /dev/null
+++ b/third_party/rust/serde_with/tests/version_numbers.rs
@@ -0,0 +1,20 @@
+extern crate version_sync;
+
+use version_sync::{
+ assert_contains_regex, assert_html_root_url_updated, assert_markdown_deps_updated,
+};
+
+#[test]
+fn test_readme_deps() {
+ assert_markdown_deps_updated!("README.md");
+}
+
+#[test]
+fn test_readme_deps_in_lib() {
+ assert_contains_regex!("src/lib.rs", r#"^//! version = "{version}""#);
+}
+
+#[test]
+fn test_html_root_url() {
+ assert_html_root_url_updated!("src/lib.rs");
+}
diff --git a/third_party/rust/serde_with/tests/with_prefix.rs b/third_party/rust/serde_with/tests/with_prefix.rs
new file mode 100644
index 0000000000..b1113b7cee
--- /dev/null
+++ b/third_party/rust/serde_with/tests/with_prefix.rs
@@ -0,0 +1,130 @@
+extern crate pretty_assertions;
+extern crate serde;
+extern crate serde_derive;
+extern crate serde_json;
+extern crate serde_with;
+
+use pretty_assertions::assert_eq;
+use serde_derive::{Deserialize, Serialize};
+use serde_json::json;
+use serde_with::with_prefix;
+use std::collections::HashMap;
+
+#[test]
+fn test_flatten_with_prefix() {
+ #[derive(Serialize, Deserialize, PartialEq, Debug)]
+ struct Match {
+ #[serde(flatten, with = "prefix_player1")]
+ player1: Player,
+ #[serde(flatten, with = "prefix_player2")]
+ player2: Option<Player>,
+ #[serde(flatten, with = "prefix_player3")]
+ player3: Option<Player>,
+ #[serde(flatten, with = "prefix_tag")]
+ tags: HashMap<String, String>,
+ }
+
+ #[derive(Serialize, Deserialize, PartialEq, Debug)]
+ struct Player {
+ name: String,
+ votes: u64,
+ }
+
+ with_prefix!(prefix_player1 "player1_");
+ with_prefix!(prefix_player2 "player2_");
+ with_prefix!(prefix_player3 "player3_");
+ with_prefix!(prefix_tag "tag_");
+
+ let m = Match {
+ player1: Player {
+ name: "name1".to_owned(),
+ votes: 1,
+ },
+ player2: Some(Player {
+ name: "name2".to_owned(),
+ votes: 2,
+ }),
+ player3: None,
+ tags: {
+ let mut tags = HashMap::new();
+ tags.insert("t".to_owned(), "T".to_owned());
+ tags
+ },
+ };
+
+ let expected = json!({
+ "player1_name": "name1",
+ "player1_votes": 1,
+ "player2_name": "name2",
+ "player2_votes": 2,
+ "tag_t": "T"
+ });
+
+ let j = serde_json::to_string(&m).unwrap();
+ assert_eq!(j, expected.to_string());
+
+ assert_eq!(m, serde_json::from_str(&j).unwrap());
+}
+
+#[test]
+fn test_plain_with_prefix() {
+ #[derive(Serialize, Deserialize, PartialEq, Debug)]
+ struct Match {
+ #[serde(with = "prefix_player1")]
+ player1: Player,
+ #[serde(with = "prefix_player2")]
+ player2: Option<Player>,
+ #[serde(with = "prefix_player3")]
+ player3: Option<Player>,
+ #[serde(with = "prefix_tag")]
+ tags: HashMap<String, String>,
+ }
+
+ #[derive(Serialize, Deserialize, PartialEq, Debug)]
+ struct Player {
+ name: String,
+ votes: u64,
+ }
+
+ with_prefix!(prefix_player1 "player1_");
+ with_prefix!(prefix_player2 "player2_");
+ with_prefix!(prefix_player3 "player3_");
+ with_prefix!(prefix_tag "tag_");
+
+ let m = Match {
+ player1: Player {
+ name: "name1".to_owned(),
+ votes: 1,
+ },
+ player2: Some(Player {
+ name: "name2".to_owned(),
+ votes: 2,
+ }),
+ player3: None,
+ tags: {
+ let mut tags = HashMap::new();
+ tags.insert("t".to_owned(), "T".to_owned());
+ tags
+ },
+ };
+
+ let expected = json!({
+ "player1": {
+ "player1_name": "name1",
+ "player1_votes": 1,
+ },
+ "player2": {
+ "player2_name": "name2",
+ "player2_votes": 2,
+ },
+ "player3": null,
+ "tags": {
+ "tag_t": "T"
+ }
+ });
+
+ let j = serde_json::to_string(&m).unwrap();
+ assert_eq!(j, expected.to_string());
+
+ assert_eq!(m, serde_json::from_str(&j).unwrap());
+}