diff options
Diffstat (limited to 'third_party/rust/serde_with')
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()); +} |