summaryrefslogtreecommitdiffstats
path: root/third_party/rust/serde_with
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/rust/serde_with
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/serde_with')
-rw-r--r--third_party/rust/serde_with/.cargo-checksum.json1
-rw-r--r--third_party/rust/serde_with/CHANGELOG.md1028
-rw-r--r--third_party/rust/serde_with/Cargo.toml286
-rw-r--r--third_party/rust/serde_with/LICENSE-APACHE201
-rw-r--r--third_party/rust/serde_with/LICENSE-MIT25
-rw-r--r--third_party/rust/serde_with/README.md212
-rw-r--r--third_party/rust/serde_with/src/base64.rs232
-rw-r--r--third_party/rust/serde_with/src/chrono_0_4.rs655
-rw-r--r--third_party/rust/serde_with/src/content/de.rs1894
-rw-r--r--third_party/rust/serde_with/src/content/mod.rs8
-rw-r--r--third_party/rust/serde_with/src/content/ser.rs624
-rw-r--r--third_party/rust/serde_with/src/de/duplicates.rs223
-rw-r--r--third_party/rust/serde_with/src/de/impls.rs1937
-rw-r--r--third_party/rust/serde_with/src/de/mod.rs158
-rw-r--r--third_party/rust/serde_with/src/duplicate_key_impls/error_on_duplicate.rs127
-rw-r--r--third_party/rust/serde_with/src/duplicate_key_impls/first_value_wins.rs89
-rw-r--r--third_party/rust/serde_with/src/duplicate_key_impls/last_value_wins.rs68
-rw-r--r--third_party/rust/serde_with/src/duplicate_key_impls/mod.rs9
-rw-r--r--third_party/rust/serde_with/src/enum_map.rs921
-rw-r--r--third_party/rust/serde_with/src/flatten_maybe.rs88
-rw-r--r--third_party/rust/serde_with/src/formats.rs140
-rw-r--r--third_party/rust/serde_with/src/guide.md86
-rw-r--r--third_party/rust/serde_with/src/guide/feature_flags.md88
-rw-r--r--third_party/rust/serde_with/src/guide/serde_as.md344
-rw-r--r--third_party/rust/serde_with/src/guide/serde_as_transformations.md599
-rw-r--r--third_party/rust/serde_with/src/hex.rs143
-rw-r--r--third_party/rust/serde_with/src/json.rs121
-rw-r--r--third_party/rust/serde_with/src/key_value_map.rs1298
-rw-r--r--third_party/rust/serde_with/src/lib.rs2339
-rw-r--r--third_party/rust/serde_with/src/rust.rs712
-rw-r--r--third_party/rust/serde_with/src/ser/duplicates.rs70
-rw-r--r--third_party/rust/serde_with/src/ser/impls.rs919
-rw-r--r--third_party/rust/serde_with/src/ser/mod.rs173
-rw-r--r--third_party/rust/serde_with/src/serde_conv.rs150
-rw-r--r--third_party/rust/serde_with/src/time_0_3.rs625
-rw-r--r--third_party/rust/serde_with/src/utils.rs194
-rw-r--r--third_party/rust/serde_with/src/utils/duration.rs565
-rw-r--r--third_party/rust/serde_with/src/with_prefix.rs604
-rw-r--r--third_party/rust/serde_with/tests/base64.rs144
-rw-r--r--third_party/rust/serde_with/tests/chrono_0_4.rs742
-rw-r--r--third_party/rust/serde_with/tests/derives/deserialize_fromstr.rs96
-rw-r--r--third_party/rust/serde_with/tests/derives/lib.rs15
-rw-r--r--third_party/rust/serde_with/tests/derives/serialize_display.rs39
-rw-r--r--third_party/rust/serde_with/tests/hex.rs93
-rw-r--r--third_party/rust/serde_with/tests/indexmap_1.rs262
-rw-r--r--third_party/rust/serde_with/tests/json.rs62
-rw-r--r--third_party/rust/serde_with/tests/rust.rs386
-rw-r--r--third_party/rust/serde_with/tests/serde_as/collections.rs44
-rw-r--r--third_party/rust/serde_with/tests/serde_as/default_on.rs130
-rw-r--r--third_party/rust/serde_with/tests/serde_as/enum_map.rs458
-rw-r--r--third_party/rust/serde_with/tests/serde_as/frominto.rs187
-rw-r--r--third_party/rust/serde_with/tests/serde_as/key_value_map.rs350
-rw-r--r--third_party/rust/serde_with/tests/serde_as/lib.rs1181
-rw-r--r--third_party/rust/serde_with/tests/serde_as/map_tuple_list.rs687
-rw-r--r--third_party/rust/serde_with/tests/serde_as/pickfirst.rs149
-rw-r--r--third_party/rust/serde_with/tests/serde_as/serde_as_macro.rs307
-rw-r--r--third_party/rust/serde_with/tests/serde_as/serde_conv.rs52
-rw-r--r--third_party/rust/serde_with/tests/serde_as/time.rs521
-rw-r--r--third_party/rust/serde_with/tests/time_0_3.rs279
-rw-r--r--third_party/rust/serde_with/tests/utils.rs79
-rw-r--r--third_party/rust/serde_with/tests/version_numbers.rs79
-rw-r--r--third_party/rust/serde_with/tests/with_prefix.rs164
62 files changed, 24462 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..62b3a75a4d
--- /dev/null
+++ b/third_party/rust/serde_with/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CHANGELOG.md":"d159105b0cefc20ea831471706d6ea0f2ff1f4814e4dee3fc88105e1204e3233","Cargo.toml":"91247c49a41e6a0b1c4cd059855a30d4891ac34cc8e436b6282cecdfdf2d8e36","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7576269ea71f767b99297934c0b2367532690f8c4badc695edf8e04ab6a1e545","README.md":"e678bfd60449ac137d780b29fcae8d3ecb706f43e8060369f7269151a0844c1a","src/base64.rs":"84edf1f82f2b72345f73ef964e3468d1607c483e2a24f19e8be89baa89b26a99","src/chrono_0_4.rs":"cf527cec9a91db2a9709f7baa27ce7211846ff37a25df9bafde9cca3096e2399","src/content/de.rs":"c1c20148e8a486f8db8850d0ebd79372f2ba1823d79f691563c658e530bd2cbb","src/content/mod.rs":"c3f109d4e6bcf213c583fe52420468b7fcc151ca57b82adc4379e4ce129aba8a","src/content/ser.rs":"29788f9bb783dd34c8adcc90ab3109922e45db5b111a657eb102d4392402587a","src/de/duplicates.rs":"c287ab358d60b51f3d0d4df55bd76d687db904b75dc25ff5de1a3b3eada5a98e","src/de/impls.rs":"520ba8d08a132a942a6d15d00b6cc98407f0d88f7d9d58554d74b4dd49452877","src/de/mod.rs":"c0b965cebca8216bd21b53d1416bb8652379faa2a99ae8f09b033b54e0975f88","src/duplicate_key_impls/error_on_duplicate.rs":"f98fca69923ef4ff5365c9a66d8e443e627d791f79173eb25d8359d5fd52c377","src/duplicate_key_impls/first_value_wins.rs":"fd850646c453b78b9f428a0707e88013bf3b8a95bf9fe368ea9d827d9a9dcaaf","src/duplicate_key_impls/last_value_wins.rs":"b3448c3ced03ac947e83adba1557321277c314fbdda0898657d77d655915d4e6","src/duplicate_key_impls/mod.rs":"6b162013a3cbf6c09d2285fac14dc71930834e97065a2319aa56864838613449","src/enum_map.rs":"627817c31a002d5865d7c16d07eed29d06dc83e39ceff3c1e079e27d2f389476","src/flatten_maybe.rs":"1104ae7faa38264a8e74693a3d0256fcafc62d9bff5272647f6e99212603e531","src/formats.rs":"cc036d1e7cde06990f9d1dc68643157f61e07affa6647fd70990f143855d2398","src/guide.md":"6be6298f79acfedd9fffe74c050060da8a40f40b0968c14aae0b6c3766e8a897","src/guide/feature_flags.md":"404c9d5c0ec767cf6ddf1112b751b006834c43f48ed714498f8fcd6eaf59ede6","src/guide/serde_as.md":"73791716a8322fc45d87ab98d4a0510d18314cf798979d02bf6b4a81dab0b656","src/guide/serde_as_transformations.md":"4e8cdbe093e588e7c03c5b2e5b1cec056c9b913c06338595fd13bda12922b1af","src/hex.rs":"0826b3348234590237fa24017c239456cd6e32fff7f40a5a3e72405548112d54","src/json.rs":"fc57da67ccbc6a6a216f872fbe7310bc860eeeab0f56151c200627259c269c58","src/key_value_map.rs":"b0513f209e20400c03aa7c4eb4c43065fc38a78b6b2cc3648cf8c0ca6d9c497c","src/lib.rs":"a63b2dce749c638dbb0eafe1374b01fe6ce2e5895aea5c84703dd281d66cfce8","src/rust.rs":"584b98eb76f1df3490acdd51e5ba38121a90d3c46467698b37a2c8231a5ca649","src/ser/duplicates.rs":"9e3502e9dc1f3f6ddcbbbccd60fe67aebe49ab75f49f2b49c0e0710f1d0870bd","src/ser/impls.rs":"21fe868a9ed25514e73a0fa830eec4e5e224f24be901e31b7c0a2a9a1a7adb4a","src/ser/mod.rs":"9ba74dc54098e8a21650be4db8037b7fd992fc7ddc26595dab2a43e23d3409d7","src/serde_conv.rs":"6f15b08bef3559b08e2a77e1a900fd7d2162f3a373b1d063e2b92420b910d1fb","src/time_0_3.rs":"2e4104347f184006c9b4276da99d3004a88808df42f4927138229b372620c861","src/utils.rs":"841510c81be2ef2f54e03401ab6e56534945833ea1babc3f3e5652ce2b9e7a74","src/utils/duration.rs":"38a1e4e1a6e1ea4aaf51ab1ef5c5dc54c9966a070575e1df12d91d46acfd402f","src/with_prefix.rs":"c4352e6549cd82b42ff1468b10313de5e67324e4922dec6394128d00136ee956","tests/base64.rs":"609ac4b9663b53ba9c38428f2bb7cded8d9c85ff3981451ea191c3a6a0f2d7f3","tests/chrono_0_4.rs":"b5aecb6112a68537b3c709086fb6690da71924a10b49065b30e2203e29e45b6c","tests/derives/deserialize_fromstr.rs":"b23b236247b619eecc25053f64e527f44fd066d602027f4b1518b333110362e9","tests/derives/lib.rs":"abb2046d6798889dcef2cf40157f3182851ae87436d0f981adecd76051d74b5a","tests/derives/serialize_display.rs":"9ae9ad6c632202639e6e7ddeeaa6c5613593a9c2cc5275e175eb866ba727fb31","tests/hex.rs":"3d3198efed7d328962695e359eb5fc688531fb9c2befa270401109d04167d0ff","tests/indexmap_1.rs":"219d612476ab8eea591a0e22b31f4567ae54b94846ed3091808135a09f409b60","tests/json.rs":"bcfe07c8b67666be0c9780e75b596559d0881ef1b9dbd84f10175f745762227c","tests/rust.rs":"79bab729b6471909d99fadc4fa237c584db6c27e65d3ed80ccb233d55a4ba4fa","tests/serde_as/collections.rs":"e09c62f6ad84aa2493bfc20817edbe6216b35614e2b92f510536252a11041e7c","tests/serde_as/default_on.rs":"c2e7aad6f4c309305dc925b7c95e3cb2c10bf462fb5577448606416913400a56","tests/serde_as/enum_map.rs":"bd0de073c9f8210983ae8a68873d4036aa3c0b7d8add5e99bbfe5e73c7e56d6f","tests/serde_as/frominto.rs":"c7feb6d10a85c54a46ca619f7b7751c2d4a2ac2a936dfec64b8050267152cd96","tests/serde_as/key_value_map.rs":"327bd3f6d2f5b1fd6ba4b2e045867b82c8e7a2bfb61c42650dde69bf2911de27","tests/serde_as/lib.rs":"642a47ae63a95e56cfc11f6e78b297fc8ae33da3ac490f7f92169f2b3423171e","tests/serde_as/map_tuple_list.rs":"0664423354b096fa1e9c010edb408a6ccea6e5625bb447d11ffcb51ea4d5a8b9","tests/serde_as/pickfirst.rs":"3fb48dcbdfd2f6155275c047f38bcb87c208a18725058a3ff00c05675e1dc6e8","tests/serde_as/serde_as_macro.rs":"6cd8bc27fd0f806e5ee350a1ff7783f6b0ba75d075473de090b4f0bf2404cdb0","tests/serde_as/serde_conv.rs":"1d3546d46390e631fe380e8cf56a8ed45020958b82eb6396d33062e133237173","tests/serde_as/time.rs":"69cdd8db5432a0eafa2da08ca633872c160ce23302ae03dc2f397191b9de9477","tests/time_0_3.rs":"1a31406a0f6217f17135c434f7b5205e09757c49ccc3131cfe004149534ad829","tests/utils.rs":"f540ced55ae803fa98404812078ecc2c6aca10e9052f39a1b812bbde9dff5df5","tests/version_numbers.rs":"09a1085615d332e93d183e4a5fa9f08dcb317c37e2bdda728e62b598ed93fa4d","tests/with_prefix.rs":"cff484c442a3504342f793da451ce9c9d3aa4180781aebc965971bae34783ecc"},"package":"9f02d8aa6e3c385bf084924f660ce2a3a6bd333ba55b35e8590b321f35d88513"} \ 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..4ff8041ab7
--- /dev/null
+++ b/third_party/rust/serde_with/CHANGELOG.md
@@ -0,0 +1,1028 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+
+## [3.0.0] - 2023-05-01
+
+This breaking release should not impact most users.
+It only affects custom character sets used for base64 of which there are no instances of on GitHub.
+
+### Changed
+
+* Upgrade base64 to v0.21 (#543)
+ Thanks to @jeff-hiner for submitting the PR.
+
+ Remove support for custom character sets.
+ This is technically a breaking change.
+ A code search on GitHub revealed no instances of anyone using that, and `serde_with` ships with many predefined character sets.
+ The removal means that future base64 upgrade will no longer be breaking changes.
+
+## [2.3.3] - 2023-04-27
+
+### Changed
+
+* Update `syn` to v2 and `darling` to v0.20 (#578)
+ Update proc-macro dependencies.
+ This change should have no impact on users, but now uses the same dependency as `serde_derive`.
+
+## [2.3.2] - 2023-04-05
+
+### Changed
+
+* Improve the error message when deserializing `OneOrMany` or `PickFirst` fails.
+ It now includes the original error message for each of the individual variants.
+ This is possible by dropping untagged enums as the internal implementations, since they will likely never support this, as these old PRs show [serde#2376](https://github.com/serde-rs/serde/pull/2376) and [serde#1544](https://github.com/serde-rs/serde/pull/1544).
+
+ The new errors look like:
+
+ ```text
+ OneOrMany could not deserialize any variant:
+ One: invalid type: map, expected u32
+ Many: invalid type: map, expected a sequence
+ ```
+
+ ```text
+ PickFirst could not deserialize any variant:
+ First: invalid type: string "Abc", expected u32
+ Second: invalid digit found in string
+ ```
+
+### Fixed
+
+* Specify the correct minimum serde version as dependency. (#588)
+ Thanks to @nox for submitting a PR.
+
+## [2.3.1] - 2023-03-10
+
+### Fixed
+
+* Undo the changes to the trait bound for `Seq`. (#570, #571)
+ The new implementation caused issues with serialization formats that require the sequence length beforehand.
+ It also caused problems, that certain attributes which worked before no longer worked, due to mismatching number of references.
+
+ Thanks to @stefunctional for reporting and for @stephaneyfx for providing a test case.
+
+## [2.3.0] - 2023-03-09
+
+### Added
+
+* Add `serde_as` compatible versions for the existing duplicate key and value handling. (#534)
+ The new types `MapPreventDuplicates`, `MapFirstKeyWins`, `SetPreventDuplicates`, and `SetLastValueWins` can replace the existing modules `maps_duplicate_key_is_error`, `maps_first_key_wins`, `sets_duplicate_value_is_error`, and `sets_last_value_wins`.
+* Added a new `KeyValueMap` type using the map key as a struct field. (#341)
+ This conversion is useful for maps, where an ID value is the map key, but the ID should become part of a single struct.
+ The conversion allows this, by using a special field named `$key$`.
+
+ This conversion is possible for structs and maps, using the `$key$` field.
+ Tuples, tuple structs, and sequences are supported by turning the first value into the map key.
+
+ Each of the `SimpleStruct`s
+
+ ```rust
+ // Somewhere there is a collection:
+ // #[serde_as(as = "KeyValueMap<_>")]
+ // Vec<SimpleStruct>,
+
+ #[derive(Serialize, Deserialize)]
+ struct SimpleStruct {
+ b: bool,
+ // The field named `$key$` will become the map key
+ #[serde(rename = "$key$")]
+ id: String,
+ i: i32,
+ }
+ ```
+
+ will turn into a JSON snippet like this.
+
+ ```json
+ "id-0000": {
+ "b": false,
+ "i": 123
+ },
+ ```
+
+### Changed
+
+* Relax the trait bounds of `Seq` to allow for more custom types. (#565)
+ This extends the support beyond tuples.
+
+### Fixed
+
+* `EnumMap` passes the `human_readable` status of the `Serializer` to more places.
+* Support `alloc` on targets without `target_has_atomic = "ptr"`. (#560)
+ Thanks to @vembacher for reporting and fixing the issue.
+
+## [2.2.0] - 2023-01-09
+
+### Added
+
+* Add new `Map` and `Seq` types for converting between maps and tuple lists. (#527)
+
+ The behavior is not new, but already present using `BTreeMap`/`HashMap` or `Vec`.
+ However, the new types `Map` and `Seq` are also available on `no_std`, even without the `alloc` feature.
+
+### Changed
+
+* Pin the `serde_with_macros` dependency to the same version as the main crate.
+ This simplifies publishing and ensures that always a compatible version is picked.
+
+### Fixed
+
+* `serde_with::apply` had an issue matching types when invisible token groups where in use (#538)
+ The token groups can stem from macro_rules expansion, but should be treated mostly transparent.
+ The old code required a group to match a group, while now groups are silently removed when checking for type patterns.
+
+## [2.1.0] - 2022-11-16
+
+### Added
+
+* Add new `apply` attribute to simplify repetitive attributes over many fields.
+ Multiple rules and multiple attributes can be provided each.
+
+ ```rust
+ #[serde_with::apply(
+ Option => #[serde(default)] #[serde(skip_serializing_if = "Option::is_none")],
+ Option<bool> => #[serde(rename = "bool")],
+ )]
+ #[derive(serde::Serialize)]
+ struct Data {
+ a: Option<String>,
+ b: Option<u64>,
+ c: Option<String>,
+ d: Option<bool>,
+ }
+ ```
+
+ The `apply` attribute will expand into this, applying the attributs to the matching fields:
+
+ ```rust
+ #[derive(serde::Serialize)]
+ struct Data {
+ #[serde(default)]
+ #[serde(skip_serializing_if = "Option::is_none")]
+ a: Option<String>,
+ #[serde(default)]
+ #[serde(skip_serializing_if = "Option::is_none")]
+ b: Option<u64>,
+ #[serde(default)]
+ #[serde(skip_serializing_if = "Option::is_none")]
+ c: Option<String>,
+ #[serde(default)]
+ #[serde(skip_serializing_if = "Option::is_none")]
+ #[serde(rename = "bool")]
+ d: Option<bool>,
+ }
+ ```
+
+ The attribute supports field matching using many rules, such as `_` to apply to all fields and partial generics like `Option` to match any `Option` be it `Option<String>`, `Option<bool>`, or `Option<T>`.
+
+### Fixed
+
+* The derive macros `SerializeDisplay` and `DeserializeFromStr` now take better care not to use conflicting names for generic values. (#526)
+ All used generics now start with `__` to make conflicts with manually written code unlikely.
+
+ Thanks to @Elrendio for submitting a PR fixing the issue.
+
+## [2.0.1] - 2022-09-09
+
+### Added
+
+* `time` added support for the well-known `Iso8601` format.
+ This extends the existing support of `Rfc2822` and `Rfc3339`.
+
+### Changed
+
+* Warn if `serde_as` is used on an enum variant.
+ Attributes on enum variants were never supported.
+ But `#[serde(with = "...")]` can be added on variants, such that some confusion can occur when migration ([#499](https://github.com/jonasbb/serde_with/issues/499)).
+
+### Note
+
+A cargo bug ([cargo#10801](https://github.com/rust-lang/cargo/issues/10801)) means that upgrading from v1 to v2 may add unnecessary crates to the `Cargo.lock` file.
+A diff of the lock-file makes it seem that `serde_with` depends on new crates, even though these crates are unused and will not get compiled or linked.
+However, tools consuming `Cargo.lock` or `cargo metadata` might give wrong results.
+
+## [2.0.0] - 2022-07-17
+
+### Added
+
+* Make `JsonString<T>` smarter by allowing nesting `serde_as` definitions.
+ This allows applying custom serialization logic, before the value gets converted into a JSON string.
+
+ ```rust
+ // Rust
+ #[serde_as(as = "JsonString<Vec<(JsonString, _)>>")]
+ value: BTreeMap<[u8; 2], u32>,
+
+ // JSON
+ {"value":"[[\"[1,2]\",3],[\"[4,5]\",6]]"}
+ ```
+
+### Changed
+
+* Make `#[serde_as]` behave more intuitive on `Option<T>` fields.
+
+ The `#[serde_as]` macro now detects if a `#[serde_as(as = "Option<S>")]` is used on a field of type `Option<T>` and applies `#[serde(default)]` to the field.
+ This restores the ability to deserialize with missing fields and fixes a common annoyance (#183, #185, #311, #417).
+ This is a breaking change, since now deserialization will pass where it did not before and this might be undesired.
+
+ The `Option` field and transformation are detected by directly matching on the type name.
+ These variants are detected as `Option`.
+ * `Option`
+ * `std::option::Option`, with or without leading `::`
+ * `core::option::Option`, with or without leading `::`
+
+ If an existing `default` attribute is detected, the attribute is not applied again.
+ This behavior can be suppressed by using `#[serde_as(no_default)]` or `#[serde_as(as = "Option<S>", no_default)]`.
+* `NoneAsEmptyString` and `string_empty_as_none` use a different serialization bound (#388).
+
+ Both types used `AsRef<str>` as the serialization bound.
+ This is limiting for non-string types like `Option<i32>`.
+ The deserialization often was already more flexible, due to the `FromStr` bound.
+
+ For most std types this should have little impact, as the types implementing `AsRef<str>` mostly implement `Display`, too, such as `String`, `Cow<str>`, or `Rc<str>`.
+* Bump MSRV to 1.60. This is required for the optional dependency feature syntax in cargo.
+
+### Removed
+
+* Remove old module based conversions.
+
+ The newer `serde_as` based conversions are preferred.
+
+ * `seq_display_fromstr`: Use `DisplayFromStr` in combination with your container type:
+
+ ```rust
+ #[serde_as(as = "BTreeSet<DisplayFromStr>")]
+ addresses: BTreeSet<Ipv4Addr>,
+ #[serde_as(as = "Vec<DisplayFromStr>")]
+ bools: Vec<bool>,
+ ```
+
+ * `tuple_list_as_map`: Use `BTreeMap` on a `Vec` of tuples:
+
+ ```rust
+ #[serde_as(as = "BTreeMap<_, _>")] // HashMap will also work
+ s: Vec<(i32, String)>,
+ ```
+
+ * `map_as_tuple_list` can be replaced with `#[serde_as(as = "Vec<(_, _)>")]`.
+ * `display_fromstr` can be replaced with `#[serde_as(as = "DisplayFromStr")]`.
+ * `bytes_or_string` can be replaced with `#[serde_as(as = "BytesOrString")]`.
+ * `default_on_error` can be replaced with `#[serde_as(as = "DefaultOnError")]`.
+ * `default_on_null` can be replaced with `#[serde_as(as = "DefaultOnNull")]`.
+ * `string_empty_as_none` can be replaced with `#[serde_as(as = "NoneAsEmptyString")]`.
+ * `StringWithSeparator` can now only be used in `serde_as`.
+ The definition of the `Separator` trait and its implementations have been moved to the `formats` module.
+ * `json::nested` can be replaced with `#[serde_as(as = "json::JsonString")]`.
+
+* Remove previously deprecated modules.
+
+ * `sets_first_value_wins`
+ * `btreemap_as_tuple_list` and `hashmap_as_tuple_list` can be replaced with `#[serde_as(as = "Vec<(_, _)>")]`.
+
+### Note
+
+A cargo bug ([cargo#10801](https://github.com/rust-lang/cargo/issues/10801)) means that upgrading from v1 to v2 may add unnecessary crates to the `Cargo.lock` file.
+A diff of the lock-file makes it seem that `serde_with` depends on new crates, even though these crates are unused and will not get compiled or linked.
+
+## [2.0.0-rc.0] - 2022-06-29
+
+### Changed
+
+* Make `#[serde_as]` behave more intuitive on `Option<T>` fields.
+
+ The `#[serde_as]` macro now detects if a `#[serde_as(as = "Option<S>")]` is used on a field of type `Option<T>` and applies `#[serde(default)]` to the field.
+ This restores the ability to deserialize with missing fields and fixes a common annoyance (#183, #185, #311, #417).
+ This is a breaking change, since now deserialization will pass where it did not before and this might be undesired.
+
+ The `Option` field and transformation are detected by directly matching on the type name.
+ These variants are detected as `Option`.
+ * `Option`
+ * `std::option::Option`, with or without leading `::`
+ * `core::option::Option`, with or without leading `::`
+
+ If an existing `default` attribute is detected, the attribute is not applied again.
+ This behavior can be suppressed by using `#[serde_as(no_default)]` or `#[serde_as(as = "Option<S>", no_default)]`.
+* `NoneAsEmptyString` and `string_empty_as_none` use a different serialization bound (#388).
+
+ Both types used `AsRef<str>` as the serialization bound.
+ This is limiting for non-string types like `Option<i32>`.
+ The deserialization often was already more flexible, due to the `FromStr` bound.
+
+ For most std types this should have little impact, as the types implementing `AsRef<str>` mostly implement `Display`, too, such as `String`, `Cow<str>`, or `Rc<str>`.
+* Bump MSRV to 1.60. This is required for the optional dependency feature syntax in cargo.
+
+### Removed
+
+* Remove old module based conversions.
+
+ The newer `serde_as` based conversions are preferred.
+
+ * `seq_display_fromstr`: Use `DisplayFromStr` in combination with your container type:
+
+ ```rust
+ #[serde_as(as = "BTreeSet<DisplayFromStr>")]
+ addresses: BTreeSet<Ipv4Addr>,
+ #[serde_as(as = "Vec<DisplayFromStr>")]
+ bools: Vec<bool>,
+ ```
+
+ * `tuple_list_as_map`: Use `BTreeMap` on a `Vec` of tuples:
+
+ ```rust
+ #[serde_as(as = "BTreeMap<_, _>")] // HashMap will also work
+ s: Vec<(i32, String)>,
+ ```
+
+ * `map_as_tuple_list` can be replaced with `#[serde_as(as = "Vec<(_, _)>")]`.
+ * `display_fromstr` can be replaced with `#[serde_as(as = "DisplayFromStr")]`.
+ * `bytes_or_string` can be replaced with `#[serde_as(as = "BytesOrString")]`.
+ * `default_on_error` can be replaced with `#[serde_as(as = "DefaultOnError")]`.
+ * `default_on_null` can be replaced with `#[serde_as(as = "DefaultOnNull")]`.
+ * `string_empty_as_none` can be replaced with `#[serde_as(as = "NoneAsEmptyString")]`.
+ * `StringWithSeparator` can now only be used in `serde_as`.
+ The definition of the `Separator` trait and its implementations have been moved to the `formats` module.
+ * `json::nested` can be replaced with `#[serde_as(as = "json::JsonString")]`.
+
+* Remove previously deprecated modules.
+
+ * `sets_first_value_wins`
+ * `btreemap_as_tuple_list` and `hashmap_as_tuple_list` can be replaced with `#[serde_as(as = "Vec<(_, _)>")]`.
+
+## [1.14.0] - 2022-05-29
+
+### Added
+
+* Add support for `time` crate v0.3 #450
+
+ `time::Duration` can now be serialized with the `DurationSeconds` and related converters.
+
+ ```rust
+ // Rust
+ #[serde_as(as = "serde_with::DurationSeconds<u64>")]
+ value: Duration,
+
+ // JSON
+ "value": 86400,
+ ```
+
+ `time::OffsetDateTime` and `time::PrimitiveDateTime` can now be serialized with the `TimestampSeconds` and related converters.
+
+ ```rust
+ // Rust
+ #[serde_as(as = "serde_with::TimestampMicroSecondsWithFrac<String>")]
+ value: time::PrimitiveDateTime,
+
+ // JSON
+ "value": "1000000",
+ ```
+
+ `time::OffsetDateTime` can be serialized in string format in different well-known formats.
+ Two formats are supported, `time::format_description::well_known::Rfc2822` and `time::format_description::well_known::Rfc3339`.
+
+ ```rust
+ // Rust
+ #[serde_as(as = "time::format_description::well_known::Rfc2822")]
+ rfc_2822: OffsetDateTime,
+ #[serde_as(as = "Vec<time::format_description::well_known::Rfc3339>")]
+ rfc_3339: Vec<OffsetDateTime>,
+
+ // JSON
+ "rfc_2822": "Fri, 21 Nov 1997 09:55:06 -0600",
+ "rfc_3339": ["1997-11-21T09:55:06-06:00"],
+ ```
+
+* Deserialize `bool` from integers #456 462
+
+ Deserialize an integer and convert it into a `bool`.
+ `BoolFromInt<Strict>` (default) deserializes 0 to `false` and `1` to `true`, other numbers are errors.
+ `BoolFromInt<Flexible>` deserializes any non-zero as `true`.
+ Serialization only emits 0/1.
+
+ ```rust
+ // Rust
+ #[serde_as(as = "BoolFromInt")] // BoolFromInt<Strict>
+ b: bool,
+
+ // JSON
+ "b": 1,
+ ```
+
+### Changed
+
+* Bump MSRV to 1.53, since the new dependency `time` requires that version.
+
+### Fixed
+
+* Make the documentation clearer by stating that the `#[serde_as]` and `#[skip_serializing_none]` attributes must always be places before `#[derive]`.
+
+## [1.13.0] - 2022-04-23
+
+### Added
+
+* Added support for `indexmap::IndexMap` and `indexmap::IndexSet` types. #431, #436
+
+ Both types are now compatible with these functions: `maps_duplicate_key_is_error`, `maps_first_key_wins`, `sets_duplicate_value_is_error`, `sets_last_value_wins`.
+ `serde_as` integration is provided by implementing both `SerializeAs` and `DeserializeAs` for both types.
+ `IndexMap`s can also be serialized as a list of types via the `serde_as(as = "Vec<(_, _)>")` annotation.
+
+ All implementations are gated behind the `indexmap` feature.
+
+ Thanks to @jgrund for providing parts of the implementation.
+
+## [1.12.1] - 2022-04-07
+
+### Fixed
+
+* Depend on a newer `serde_with_macros` version to pull in some fixes.
+ * Account for generics when deriving implementations with `SerializeDisplay` and `DeserializeFromStr` #413
+ * Provide better error messages when parsing types fails #423
+
+## [1.12.0] - 2022-02-07
+
+### Added
+
+* Deserialize a `Vec` and skip all elements failing to deserialize #383
+
+ `VecSkipError` acts like a `Vec`, but elements which fail to deserialize, like the `"Yellow"` are ignored.
+
+ ```rust
+ #[derive(serde::Deserialize)]
+ enum Color {
+ Red,
+ Green,
+ Blue,
+ }
+ // JSON
+ "colors": ["Blue", "Yellow", "Green"],
+ // Rust
+ #[serde_as(as = "VecSkipError<_>")]
+ colors: Vec<Color>,
+ // => vec![Blue, Green]
+ ```
+
+ Thanks to @hdhoang for creating the PR.
+
+* Transform between maps and `Vec<Enum>` #375
+
+ The new `EnumMap` type converts `Vec` of enums into a single map.
+ The key is the enum variant name, and the value is the variant value.
+
+ ```rust
+ // Rust
+ VecEnumValues(vec![
+ EnumValue::Int(123),
+ EnumValue::String("Foo".to_string()),
+ EnumValue::Unit,
+ EnumValue::Tuple(1, "Bar".to_string()),
+ EnumValue::Struct {
+ a: 666,
+ b: "Baz".to_string(),
+ },
+ ]
+
+ // JSON
+ {
+ "Int": 123,
+ "String": "Foo",
+ "Unit": null,
+ "Tuple": [
+ 1,
+ "Bar",
+ ],
+ "Struct": {
+ "a": 666,
+ "b": "Baz",
+ }
+ }
+ ```
+
+### Changed
+
+* The `Timestamp*Seconds` and `Timestamp*SecondsWithFrac` types can now be used with `chrono::NaiveDateTime`. #389
+
+## [1.11.0] - 2021-10-18
+
+### Added
+
+* Serialize bytes as base64 encoded strings.
+ The character set and padding behavior can be configured.
+
+ ```rust
+ // Rust
+ #[serde_as(as = "serde_with::base64::Base64")]
+ value: Vec<u8>,
+ #[serde_as(as = "Base64<Bcrypt, Unpadded>")]
+ bcrypt_unpadded: Vec<u8>,
+
+ // JSON
+ "value": "SGVsbG8gV29ybGQ=",
+ "bcrypt_unpadded": "QETqZE6eT07wZEO",
+ ```
+
+* The minimal supported Rust version (MSRV) is now specified in the `Cargo.toml` via the `rust-version` field. The field is supported in Rust 1.56 and has no effect on versions before.
+
+ More details: https://doc.rust-lang.org/nightly/cargo/reference/manifest.html#the-rust-version-field
+
+### Fixed
+
+* Fixed RUSTSEC-2020-0071 in the `time` v0.1 dependency, but changing the feature flags of the `chrono` dependency. This should not change anything. Crates requiring the `oldtime` feature of `chrono` can enable it separately.
+* Allow `HashSet`s with custom hashers to be deserialized when used in combination with `serde_as`. #408
+
+## [1.10.0] - 2021-09-04
+
+### Added
+
+* Add `BorrowCow` which instructs serde to borrow data during deserialization of `Cow<'_, str>`, `Cow<'_, [u8]>`, or `Cow<'_, [u8; N]>`. (#347)
+ The implementation is for [serde#2072](https://github.com/serde-rs/serde/pull/2072#pullrequestreview-735511713) and [serde#2016](https://github.com/serde-rs/serde/issues/2016), about `#[serde(borrow)]` not working for `Option<Cow<'a, str>>`.
+
+ ```rust
+ #[serde_as]
+ #[derive(Deserialize, Serialize)]
+ struct Data<'a> {
+ #[serde_as(as = "Option<[BorrowCow; 1]>")]
+ nested: Option<[Cow<'a, str>; 1]>,
+ }
+ ```
+
+ The `#[serde(borrow)]` annotation is automatically added by the `#[serde_as]` attribute.
+
+### Changed
+
+* Bump MSRV to 1.46, since the dev-dependency `bitflags` requires that version now.
+* `flattened_maybe!` no longer requires the `serde_with` crate to be available with a specific name.
+ This allows renaming the crate or using `flattened_maybe!` through a re-export without any complications.
+
+## [1.9.4] - 2021-06-18
+
+### Fixed
+
+* `with_prefix!` now supports an optional visibility modifier. (#327, #328)
+ If not specified `pub(self)` is assumed.
+
+ ```rust
+ with_prefix!(prefix_active "active_"); // => mod {...}
+ with_prefix!(pub prefix_active "active_"); // => pub mod {...}
+ with_prefix!(pub(crate) prefix_active "active_"); // => pub(crate) mod {...}
+ with_prefix!(pub(in other_mod) prefix_active "active_"); // => pub(in other_mod) mod {...}
+ ```
+
+ Thanks to @elpiel for raising and fixing the issue.
+
+## [1.9.3] - 2021-06-14
+
+### Added
+
+* The `Bytes` type now supports borrowed and Cow arrays of fixed size (requires Rust 1.51+)
+
+ ```rust
+ #[serde_as(as = "Bytes")]
+ #[serde(borrow)]
+ borrowed_array: &'a [u8; 15],
+ #[serde_as(as = "Bytes")]
+ #[serde(borrow)]
+ cow_array: Cow<'a, [u8; 15]>,
+ ```
+
+ Note: For borrowed arrays the used Deserializer needs to support Serde's 0-copy deserialization.
+
+## [1.9.2] - 2021-06-07
+
+### Fixed
+
+* Suppress clippy warnings, which can occur while using `serde_conv` (#320)
+ Thanks to @mkroening for reporting and fixing the issue.
+
+## [1.9.1] - 2021-05-15
+
+### Changed
+
+* `NoneAsEmptyString`: Deserialize using `FromStr` instead of using `for<'a> From<&'a str>` (#316)
+ This will *not* change any behavior when applied to a field of type `Option<String>` as used in the documentation.
+ Thanks to @mkroening for finding and fixing the issue.
+
+## [1.9.0] - 2021-05-09
+
+### Added
+
+* Added `FromInto` and `TryFromInto` adapters, which enable serialization by converting into a proxy type.
+
+ ```rust
+ // Rust
+ #[serde_as(as = "FromInto<(u8, u8, u8)>")]
+ value: Rgb,
+
+ impl From<(u8, u8, u8)> for Rgb { ... }
+ impl From<Rgb> for (u8, u8, u8) { ... }
+
+ // JSON
+ "value": [128, 64, 32],
+ ```
+
+* New `serde_conv!` macro to create conversion types with reduced boilerplate.
+ The generated types can be used with `#[serde_as]` or serde's with-attribute.
+
+ ```rust
+ serde_with::serde_conv!(
+ RgbAsArray,
+ Rgb,
+ |rgb: &Rgb| [rgb.red, rgb.green, rgb.blue],
+ |value: [u8; 3]| -> Result<_, std::convert::Infallible> {
+ Ok(Rgb {
+ red: value[0],
+ green: value[1],
+ blue: value[2],
+ })
+ }
+ );
+ ```
+
+## [1.8.1] - 2021-04-19
+
+### Added
+
+* The `hex::Hex` type also works for u8-arrays on Rust 1.48.
+ Thanks to @TheAlgorythm for raising and fixing the issue.
+
+## [1.8.0] - 2021-03-30
+
+### Added
+
+* Added `PickFirst` adapter for `serde_as`. [#291]
+ It allows deserializing from multiple different forms.
+ Deserializing a number from either a number or string can be implemented like:
+
+ ```rust
+ #[serde_as(as = "PickFirst<(_, DisplayFromStr)>")]
+ value: u32,
+ ```
+
+* Implement `SerializeAs`/`DeserializeAs` for more wrapper types. [#288], [#293]
+ This now supports:
+ * `Arc`, `sync::Weak`
+ * `Rc`, `rc::Weak`
+ * `Cell`, `RefCell`
+ * `Mutex`, `RwLock`
+ * `Result`
+
+[#288]: https://github.com/jonasbb/serde_with/issues/288
+[#291]: https://github.com/jonasbb/serde_with/issues/291
+[#293]: https://github.com/jonasbb/serde_with/issues/293
+
+### Changed
+
+* Add a new `serde_with::rust::map_as_tuple_list` module as a replacement for `serde_with::rust::btreemap_as_tuple_list` and `serde_with::rust::hashmap_as_tuple_list`.
+ The new module uses `IntoIterator` and `FromIterator` as trait bound making it usable in more situations.
+ The old names continue to exist but are marked as deprecated.
+
+### Deprecated
+
+* Deprecated the module names `serde_with::rust::btreemap_as_tuple_list` and `serde_with::rust::hashmap_as_tuple_list`.
+ You can use `serde_with::rust::map_as_tuple_list` as a replacement.
+
+### Fixed
+
+* Implement `Timestamp*Seconds` and `Duration*Seconds` also for chrono types.
+ This closes [#194]. This was incompletely implemented in [#199].
+
+[#194]: https://github.com/jonasbb/serde_with/issues/194
+[#199]: https://github.com/jonasbb/serde_with/issues/199
+
+## [1.7.0] - 2021-03-24
+
+### Added
+
+* Add support for arrays of arbitrary size. ([#272])
+ This feature requires Rust 1.51+.
+
+ ```rust
+ // Rust
+ #[serde_as(as = "[[_; 64]; 33]")]
+ value: [[u8; 64]; 33],
+
+ // JSON
+ "value": [[0,0,0,0,0,...], [0,0,0,...], ...],
+ ```
+
+ Mapping of arrays was available before, but limited to arrays of length 32.
+ All conversion methods are available for the array elements.
+
+ This is similar to the existing [`serde-big-array`] crate with three important improvements:
+
+ 1. Support for the `serde_as` annotation.
+ 2. Supports non-copy elements (see [serde-big-array#6][serde-big-array-copy]).
+ 3. Supports arbitrary nestings of arrays (see [serde-big-array#7][serde-big-array-nested]).
+
+[#272]: https://github.com/jonasbb/serde_with/pull/272
+[`serde-big-array`]: https://crates.io/crates/serde-big-array
+[serde-big-array-copy]: https://github.com/est31/serde-big-array/issues/6
+[serde-big-array-nested]: https://github.com/est31/serde-big-array/issues/7
+
+* Arrays with tuple elements can now be deserialized from a map. ([#272])
+ This feature requires Rust 1.51+.
+
+ ```rust
+ // Rust
+ #[serde_as(as = "BTreeMap<_, _>")]
+ value: [(String, u16); 3],
+
+ // JSON
+ "value": {
+ "a": 1,
+ "b": 2,
+ "c": 3
+ },
+ ```
+
+* The `Bytes` type is heavily inspired by `serde_bytes` and ports it to the `serde_as` system. ([#277])
+
+ ```rust
+ #[serde_as(as = "Bytes")]
+ value: Vec<u8>,
+ ```
+
+ Compared to `serde_bytes` these improvements are available
+
+ 1. Integration with the `serde_as` annotation (see [serde-bytes#14][serde-bytes-complex]).
+ 2. Implementation for arrays of arbitrary size (Rust 1.51+) (see [serde-bytes#26][serde-bytes-arrays]).
+
+[#277]: https://github.com/jonasbb/serde_with/pull/277
+[serde-bytes-complex]: https://github.com/serde-rs/bytes/issues/14
+[serde-bytes-arrays]: https://github.com/serde-rs/bytes/issues/26
+
+* The `OneOrMany` type allows deserializing a `Vec` from either a single element or a sequence. ([#281])
+
+ ```rust
+ #[serde_as(as = "OneOrMany<_>")]
+ cities: Vec<String>,
+ ```
+
+ This allows deserializing from either `cities: "Berlin"` or `cities: ["Berlin", "Paris"]`.
+ The serialization can be configured to always emit a list with `PreferMany` or emit a single element with `PreferOne`.
+
+[#281]: https://github.com/jonasbb/serde_with/pull/281
+
+## [1.6.4] - 2021-02-16
+
+### Fixed
+
+* Fix compiling when having a struct field without the `serde_as` annotation by updating `serde_with_macros`.
+ This broke in 1.4.0 of `serde_with_macros`. [#267](https://github.com/jonasbb/serde_with/issues/267)
+
+## [1.6.3] - 2021-02-15
+
+### Changed
+
+* Bump macro crate dependency (`serde_with_macros`) to 1.4.0 to pull in those improvements.
+
+## [1.6.2] - 2021-01-30
+
+### Added
+
+* New function `serde_with::rust::deserialize_ignore_any`.
+ This function allows deserializing any data and returns the default value of the type.
+ This can be used in conjunction with `#[serde(other)]` to allow deserialization of unknown data carrying enum variants.
+
+ Thanks to @lovasoa for suggesting and implementing it.
+
+## [1.6.1] - 2021-01-24
+
+### Added
+
+* Add new types similar to `DurationSeconds` and `TimestampSeconds` but for base units of milliseconds, microseconds, and nanoseconds.
+ The `*WithFrac` variants also exist.
+* Add `SerializeAs` implementation for references.
+
+### Changed
+
+* Release `Sized` trait bound from `As`, `Same`, `SerializeAs`, and `SerializeAsWrap`.
+ Only the serialize part is relaxed.
+
+## [1.6.0] - 2020-11-22
+
+### Added
+
+* Add `DefaultOnNull` as the equivalent for `rust::default_on_null` but for the `serde_as` system.
+* Support specifying a path to the `serde_with` crate for the `serde_as` and derive macros.
+ This is useful when using crate renaming in Cargo.toml or while re-exporting the macros.
+
+ Many thanks to @tobz1000 for raising the issue and contributing fixes.
+
+### Changed
+
+* Bump minimum supported rust version to 1.40.0
+
+## [1.5.1] - 2020-10-07
+
+### Fixed
+
+* Depend on serde with the `derive` feature enabled.
+ The `derive` feature is required to deserialize untagged enums which are used in the `DefaultOnError` helpers.
+ This fixes compilation of `serde_with` in scenarios where no other crate enables the `derive` feature.
+
+## [1.5.0] - 2020-10-01
+
+### Added
+
+* The largest addition to this release is the addition of the `serde_as` de/serialization scheme.
+ It's goal is it to be a more flexible replacement to serde's with-annotation, by being more composable than before.
+ No longer is it a problem to add a custom de/serialization adapter is the type is within an `Option` or a `Vec`.
+
+ Thanks to `@markazmierczak` for the design of the trait without whom this wouldn't be possible.
+
+ More details about this new scheme can be found in the also new [user guide](https://docs.rs/serde_with/1.5.0/serde_with/guide/index.html)
+* This release also features a detailed user guide.
+ The guide focusses more on how to use this crate by providing examples.
+ For example, it includes a section about the available feature flags of this crate and how you can migrate to the shiny new `serde_as` scheme.
+* The crate now features de/serialization adaptors for the std and chrono's `Duration` types. #56 #104
+* Add a `hex` module, which allows formatting bytes (i.e. `Vec<u8>`) as a hexadecimal string.
+ The formatting supports different arguments how the formatting is happening.
+* Add two derive macros, `SerializeDisplay` and `DeserializeFromStr`, which implement the `Serialize`/`Deserialize` traits based on `Display` and `FromStr`.
+ This is in addition to the already existing methods like `DisplayFromStr`, which act locally, whereas the derive macros provide the traits expected by the rest of the ecosystem.
+
+ This is part of `serde_with_macros` v1.2.0.
+* Added some `serialize` functions to modules which previously had none.
+ This makes it easier to use the conversion when also deriving `Serialize`.
+ The functions simply pass through to the underlying `Serialize` implementation.
+ This affects `sets_duplicate_value_is_error`, `maps_duplicate_key_is_error`, `maps_first_key_wins`, `default_on_error`, and `default_on_null`.
+* Added `sets_last_value_wins` as a replacement for `sets_first_value_wins` which is deprecated now.
+ The default behavior of serde is to prefer the first value of a set so the opposite is taking the last value.
+* Added `#[serde_as]` compatible conversion methods for serializing durations and timestamps as numbers.
+ The four types `DurationSeconds`, `DurationSecondsWithFrac`, `TimestampSeconds`, `TimestampSecondsWithFrac` provide the serialization conversion with optional subsecond precision.
+ There is support for `std::time::Duration`, `chrono::Duration`, `std::time::SystemTime` and `chrono::DateTime`.
+ Timestamps are serialized as a duration since the UNIX epoch.
+ The serialization can be customized.
+ It supports multiple formats, such as `i64`, `f64`, or `String`, and the deserialization can be tweaked if it should be strict or lenient when accepting formats.
+
+### Changed
+
+* Convert the code to use 2018 edition.
+* @peterjoel improved the performance of `with_prefix!`. #101
+
+### Fixed
+
+* The `with_prefix!` macro, to add a string prefixes during serialization, now also works with unit variant enum types. #115 #116
+* The `serde_as` macro now supports serde attributes and no longer panic on unrecognized values in the attribute.
+ This is part of `serde_with_macros` v1.2.0.
+
+### Deprecated
+
+* Deprecate `sets_first_value_wins`.
+ The default behavior of serde is to take the first value, so this module is not necessary.
+
+## [1.5.0-alpha.2] - 2020-08-16
+
+### Added
+
+* Add a `hex` module, which allows formatting bytes (i.e. `Vec<u8>`) as a hexadecimal string.
+ The formatting supports different arguments how the formatting is happening.
+* Add two derive macros, `SerializeDisplay` and `DeserializeFromStr`, which implement the `Serialize`/`Deserialize` traits based on `Display` and `FromStr`.
+ This is in addition to the already existing methods like `DisplayFromStr`, which act locally, whereas the derive macros provide the traits expected by the rest of the ecosystem.
+
+ This is part of `serde_with_macros` v1.2.0-alpha.3.
+
+### Fixed
+
+* The `serde_as` macro now supports serde attributes and no longer panic on unrecognized values in the attribute.
+ This is part of `serde_with_macros` v1.2.0-alpha.2.
+
+## [1.5.0-alpha.1] - 2020-06-27
+
+### Added
+
+* The largest addition to this release is the addition of the `serde_as` de/serialization scheme.
+ It's goal is it to be a more flexible replacement to serde's with-annotation, by being more composable than before.
+ No longer is it a problem to add a custom de/serialization adapter is the type is within an `Option` or a `Vec`.
+
+ Thanks to `@markazmierczak` for the design of the trait without whom this wouldn't be possible.
+
+ More details about this new scheme can be found in the also new [user guide](https://docs.rs/serde_with/1.5.0-alpha.1/serde_with/guide/index.html)
+* This release also features a detailed user guide.
+ The guide focusses more on how to use this crate by providing examples.
+ For example, it includes a section about the available feature flags of this crate and how you can migrate to the shiny new `serde_as` scheme.
+* The crate now features de/serialization adaptors for the std and chrono's `Duration` types. #56 #104
+
+### Changed
+
+* Convert the code to use 2018 edition.
+* @peterjoel improved the performance of `with_prefix!`. #101
+
+### Fixed
+
+* The `with_prefix!` macro, to add a string prefixes during serialization, now also works with unit variant enum types. #115 #116
+
+## [1.4.0] - 2020-01-16
+
+### 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
+ * Supports 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] - 2019-04-09
+
+### Fixed
+
+* Use `serde_with_macros` with proper dependencies specified.
+
+## [1.3.0] - 2019-04-02
+
+### Added
+
+* Add `skip_serializing_none` attribute, which adds `#[serde(skip_serializing_if = "Option::is_none")]` for each Option in a struct.
+ This is helpful for APIs which have many optional fields.
+ The effect of can be negated by adding `serialize_always` on those fields, which should always be serialized.
+ Existing `skip_serializing_if` will never be modified and those fields keep their behavior.
+
+## [1.2.0] - 2019-03-04
+
+### 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] - 2019-02-18
+
+### Added
+
+* Serialize HashMap/BTreeMap as list of tuples
+
+## [1.0.0] - 2019-01-17
+
+### Added
+
+* No changes in this release.
+* Bumped version number to indicate the stability of the library.
+
+## [0.2.5] - 2018-11-29
+
+### Added
+
+* Helper which deserializes an empty string as `None` and otherwise uses `FromStr` and `AsRef<str>`.
+
+## [0.2.4] - 2018-11-24
+
+### Added
+
+* De/Serialize sequences by using `Display` and `FromStr` implementations on each element. Contributed by @katyo
+
+## [0.2.3] - 2018-11-08
+
+### 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] - 2018-08-05
+
+### Added
+
+* `unwrap_or_skip` allows to transparently serialize the inner part of a `Some(T)`
+* Add deserialization helper 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] - 2018-06-05
+
+### 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] - 2018-05-31
+
+### 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 deserializing "#foo,#bar"
+
+## [0.1.0] - 2017-08-17
+
+### 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..5531e79eaf
--- /dev/null
+++ b/third_party/rust/serde_with/Cargo.toml
@@ -0,0 +1,286 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2021"
+rust-version = "1.60"
+name = "serde_with"
+version = "3.0.0"
+authors = [
+ "Jonas Bushart",
+ "Marcin Kaźmierczak",
+]
+include = [
+ "src/**/*",
+ "tests/**/*",
+ "LICENSE-*",
+ "README.md",
+ "CHANGELOG.md",
+]
+description = "Custom de/serialization functions for Rust's serde"
+documentation = "https://docs.rs/serde_with/"
+readme = "README.md"
+keywords = [
+ "serde",
+ "utilities",
+ "serialization",
+ "deserialization",
+]
+categories = [
+ "encoding",
+ "no-std",
+]
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/jonasbb/serde_with"
+
+[package.metadata.docs.rs]
+all-features = true
+rustdoc-args = [
+ "--cfg=docsrs",
+ "-Zunstable-options",
+ "--generate-link-to-definition",
+]
+
+[package.metadata.release]
+tag = true
+tag-message = "{{crate_name}} v{{version}}"
+tag-name = "v{{version}}"
+
+[[package.metadata.release.pre-release-replacements]]
+file = "CHANGELOG.md"
+replace = """
+[Unreleased]
+
+## [{{version}}] - {{date}}"""
+search = '\[Unreleased\]'
+
+[[package.metadata.release.pre-release-replacements]]
+file = "src/lib.rs"
+replace = "https://docs.rs/serde_with/{{version}}/"
+search = 'https://docs\.rs/serde_with/[\d.]+/'
+
+[[package.metadata.release.pre-release-replacements]]
+file = "README.md"
+replace = "https://docs.rs/serde_with/{{version}}/"
+search = 'https://docs\.rs/serde_with/[\d.]+/'
+
+[[test]]
+name = "base64"
+path = "tests/base64.rs"
+required-features = [
+ "base64",
+ "macros",
+]
+
+[[test]]
+name = "chrono_0_4"
+path = "tests/chrono_0_4.rs"
+required-features = [
+ "chrono_0_4",
+ "macros",
+]
+
+[[test]]
+name = "hex"
+path = "tests/hex.rs"
+required-features = [
+ "hex",
+ "macros",
+]
+
+[[test]]
+name = "indexmap_1"
+path = "tests/indexmap_1.rs"
+required-features = [
+ "indexmap_1",
+ "macros",
+]
+
+[[test]]
+name = "json"
+path = "tests/json.rs"
+required-features = [
+ "json",
+ "macros",
+]
+
+[[test]]
+name = "serde_as"
+path = "tests/serde_as/lib.rs"
+required-features = ["macros"]
+
+[[test]]
+name = "time_0_3"
+path = "tests/time_0_3.rs"
+required-features = [
+ "macros",
+ "time_0_3",
+]
+
+[[test]]
+name = "derives"
+path = "tests/derives/lib.rs"
+required-features = ["macros"]
+
+[[test]]
+name = "with_prefix"
+path = "tests/with_prefix.rs"
+required-features = ["macros"]
+
+[[test]]
+name = "rust"
+path = "tests/rust.rs"
+required-features = ["alloc"]
+
+[dependencies.base64]
+version = "0.21.0"
+optional = true
+default-features = false
+
+[dependencies.chrono_0_4]
+version = "0.4.20"
+features = ["serde"]
+optional = true
+default-features = false
+package = "chrono"
+
+[dependencies.doc-comment]
+version = "0.3.3"
+optional = true
+
+[dependencies.hex]
+version = "0.4.3"
+optional = true
+default-features = false
+
+[dependencies.indexmap_1]
+version = "1.8"
+features = ["serde-1"]
+optional = true
+default-features = false
+package = "indexmap"
+
+[dependencies.serde]
+version = "1.0.157"
+features = ["derive"]
+default-features = false
+
+[dependencies.serde_json]
+version = "1.0.45"
+optional = true
+default-features = false
+
+[dependencies.serde_with_macros]
+version = "=3.0.0"
+optional = true
+
+[dependencies.time_0_3]
+version = "~0.3.11"
+optional = true
+default-features = false
+package = "time"
+
+[dev-dependencies.expect-test]
+version = "1.3.0"
+
+[dev-dependencies.fnv]
+version = "1.0.6"
+
+[dev-dependencies.glob]
+version = "0.3.0"
+
+[dev-dependencies.mime]
+version = "0.3.16"
+
+[dev-dependencies.pretty_assertions]
+version = "1.0.0"
+
+[dev-dependencies.regex]
+version = "1.8.1"
+features = ["std"]
+default-features = false
+
+[dev-dependencies.rmp-serde]
+version = "1.1.0"
+
+[dev-dependencies.ron]
+version = "0.8"
+
+[dev-dependencies.rustversion]
+version = "1.0.0"
+
+[dev-dependencies.serde-xml-rs]
+version = "0.6.0"
+
+[dev-dependencies.serde_json]
+version = "1.0.25"
+features = ["preserve_order"]
+
+[dev-dependencies.serde_test]
+version = "1.0.124"
+
+[dev-dependencies.serde_yaml]
+version = "0.9.2"
+
+[dev-dependencies.version-sync]
+version = "0.9.1"
+
+[features]
+alloc = [
+ "serde/alloc",
+ "base64?/alloc",
+ "chrono_0_4?/alloc",
+ "hex?/alloc",
+ "serde_json?/alloc",
+ "time_0_3?/alloc",
+]
+base64 = [
+ "dep:base64",
+ "alloc",
+]
+chrono = ["chrono_0_4"]
+chrono_0_4 = ["dep:chrono_0_4"]
+default = [
+ "std",
+ "macros",
+]
+guide = [
+ "dep:doc-comment",
+ "macros",
+ "std",
+]
+hex = [
+ "dep:hex",
+ "alloc",
+]
+indexmap = ["indexmap_1"]
+indexmap_1 = [
+ "dep:indexmap_1",
+ "alloc",
+]
+json = [
+ "dep:serde_json",
+ "alloc",
+]
+macros = ["dep:serde_with_macros"]
+std = [
+ "alloc",
+ "serde/std",
+ "chrono_0_4?/clock",
+ "chrono_0_4?/std",
+ "indexmap_1?/std",
+ "time_0_3?/serde-well-known",
+ "time_0_3?/std",
+]
+time_0_3 = ["dep:time_0_3"]
+
+[badges.maintenance]
+status = "actively-developed"
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..fd5c446f37
--- /dev/null
+++ b/third_party/rust/serde_with/README.md
@@ -0,0 +1,212 @@
+# Custom de/serialization functions for Rust's [serde](https://serde.rs)
+
+[![crates.io badge](https://img.shields.io/crates/v/serde_with.svg)](https://crates.io/crates/serde_with/)
+[![Build Status](https://github.com/jonasbb/serde_with/workflows/Rust%20CI/badge.svg)](https://github.com/jonasbb/serde_with)
+[![codecov](https://codecov.io/gh/jonasbb/serde_with/branch/master/graph/badge.svg)](https://codecov.io/gh/jonasbb/serde_with)
+[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/4322/badge)](https://bestpractices.coreinfrastructure.org/projects/4322)
+[![Rustexplorer](https://img.shields.io/badge/Try%20on-rustexplorer-lightgrey?logo=rust&logoColor=orange)](https://www.rustexplorer.com/b/py7ida)
+
+---
+
+This crate provides custom de/serialization helpers to use in combination with [serde's with-annotation][with-annotation] and with the improved [`serde_as`][as-annotation]-annotation.
+Some common use cases are:
+
+* De/Serializing a type using the `Display` and `FromStr` traits, e.g., for `u8`, `url::Url`, or `mime::Mime`.
+ Check [`DisplayFromStr`] for details.
+* Support for arrays larger than 32 elements or using const generics.
+ With `serde_as` large arrays are supported, even if they are nested in other types.
+ `[bool; 64]`, `Option<[u8; M]>`, and `Box<[[u8; 64]; N]>` are all supported, as [this examples shows](#large-and-const-generic-arrays).
+* Skip serializing all empty `Option` types with [`#[skip_serializing_none]`][skip_serializing_none].
+* Apply a prefix to each field name of a struct, without changing the de/serialize implementations of the struct using [`with_prefix!`][].
+* Deserialize a comma separated list like `#hash,#tags,#are,#great` into a `Vec<String>`.
+ Check the documentation for [`serde_with::StringWithSeparator::<CommaSeparator, T>`][StringWithSeparator].
+
+### Getting Help
+
+**Check out the [user guide][user guide] to find out more tips and tricks about this crate.**
+
+For further help using this crate you can [open a new discussion](https://github.com/jonasbb/serde_with/discussions/new) or ask on [users.rust-lang.org](https://users.rust-lang.org/).
+For bugs, please open a [new issue](https://github.com/jonasbb/serde_with/issues/new) on GitHub.
+
+## Use `serde_with` in your Project
+
+```bash
+# Add the current version to your Cargo.toml
+cargo add serde_with
+```
+
+The crate contains different features for integration with other common crates.
+Check the [feature flags][] section for information about all available features.
+
+## Examples
+
+Annotate your struct or enum to enable the custom de/serializer.
+The `#[serde_as]` attribute must be placed *before* the `#[derive]`.
+
+The `as` is analogous to the `with` attribute of serde.
+You mirror the type structure of the field you want to de/serialize.
+You can specify converters for the inner types of a field, e.g., `Vec<DisplayFromStr>`.
+The default de/serialization behavior can be restored by using `_` as a placeholder, e.g., `BTreeMap<_, DisplayFromStr>`.
+
+### `DisplayFromStr`
+
+[![Rustexplorer](https://img.shields.io/badge/Try%20on-rustexplorer-lightgrey?logo=rust&logoColor=orange)](https://www.rustexplorer.com/b/py7ida)
+```rust
+#[serde_as]
+#[derive(Deserialize, Serialize)]
+struct Foo {
+ // Serialize with Display, deserialize with FromStr
+ #[serde_as(as = "DisplayFromStr")]
+ bar: u8,
+}
+
+// This will serialize
+Foo {bar: 12}
+
+// into this JSON
+{"bar": "12"}
+```
+
+### Large and const-generic arrays
+
+serde does not support arrays with more than 32 elements or using const-generics.
+The `serde_as` attribute allows circumventing this restriction, even for nested types and nested arrays.
+
+On top of it, `[u8; N]` (aka, bytes) can use the specialized `"Bytes"` for efficiency much like the `serde_bytes` crate.
+
+[![Rustexplorer](https://img.shields.io/badge/Try%20on-rustexplorer-lightgrey?logo=rust&logoColor=orange)](https://www.rustexplorer.com/b/um0xyi)
+```rust
+#[serde_as]
+#[derive(Deserialize, Serialize)]
+struct Arrays<const N: usize, const M: usize> {
+ #[serde_as(as = "[_; N]")]
+ constgeneric: [bool; N],
+
+ #[serde_as(as = "Box<[[_; 64]; N]>")]
+ nested: Box<[[u8; 64]; N]>,
+
+ #[serde_as(as = "Option<[_; M]>")]
+ optional: Option<[u8; M]>,
+
+ #[serde_as(as = "Bytes")]
+ bytes: [u8; M],
+}
+
+// This allows us to serialize a struct like this
+let arrays: Arrays<100, 128> = Arrays {
+ constgeneric: [true; 100],
+ nested: Box::new([[111; 64]; 100]),
+ optional: Some([222; 128]),
+ bytes: [0x42; 128],
+};
+assert!(serde_json::to_string(&arrays).is_ok());
+```
+
+### `skip_serializing_none`
+
+This situation often occurs with JSON, but other formats also support optional fields.
+If many fields are optional, putting the annotations on the structs can become tedious.
+The `#[skip_serializing_none]` attribute must be placed *before* the `#[derive]`.
+
+[![Rustexplorer](https://img.shields.io/badge/Try%20on-rustexplorer-lightgrey?logo=rust&logoColor=orange)](https://www.rustexplorer.com/b/xr1tm0)
+```rust
+#[skip_serializing_none]
+#[derive(Deserialize, Serialize)]
+struct Foo {
+ a: Option<usize>,
+ b: Option<usize>,
+ c: Option<usize>,
+ d: Option<usize>,
+ e: Option<usize>,
+ f: Option<usize>,
+ g: Option<usize>,
+}
+
+// This will serialize
+Foo {a: None, b: None, c: None, d: Some(4), e: None, f: None, g: Some(7)}
+
+// into this JSON
+{"d": 4, "g": 7}
+```
+
+### Advanced `serde_as` usage
+
+This example is mainly supposed to highlight the flexibility of the `serde_as`-annotation compared to [serde's with-annotation][with-annotation].
+More details about `serde_as` can be found in the [user guide].
+
+```rust
+use std::time::Duration;
+
+#[serde_as]
+#[derive(Deserialize, Serialize)]
+enum Foo {
+ Durations(
+ // Serialize them into a list of number as seconds
+ #[serde_as(as = "Vec<DurationSeconds>")]
+ Vec<Duration>,
+ ),
+ Bytes {
+ // We can treat a Vec like a map with duplicates.
+ // JSON only allows string keys, so convert i32 to strings
+ // The bytes will be hex encoded
+ #[serde_as(as = "Map<DisplayFromStr, Hex>")]
+ bytes: Vec<(i32, Vec<u8>)>,
+ }
+}
+
+// This will serialize
+Foo::Durations(
+ vec![Duration::new(5, 0), Duration::new(3600, 0), Duration::new(0, 0)]
+)
+// into this JSON
+{
+ "Durations": [5, 3600, 0]
+}
+
+// and serializes
+Foo::Bytes {
+ bytes: vec![
+ (1, vec![0, 1, 2]),
+ (-100, vec![100, 200, 255]),
+ (1, vec![0, 111, 222]),
+ ],
+}
+// into this JSON
+{
+ "Bytes": {
+ "bytes": {
+ "1": "000102",
+ "-100": "64c8ff",
+ "1": "006fde"
+ }
+ }
+}
+```
+
+[`DisplayFromStr`]: https://docs.rs/serde_with/3.0.0/serde_with/struct.DisplayFromStr.html
+[`with_prefix!`]: https://docs.rs/serde_with/3.0.0/serde_with/macro.with_prefix.html
+[feature flags]: https://docs.rs/serde_with/3.0.0/serde_with/guide/feature_flags/index.html
+[skip_serializing_none]: https://docs.rs/serde_with/3.0.0/serde_with/attr.skip_serializing_none.html
+[StringWithSeparator]: https://docs.rs/serde_with/3.0.0/serde_with/struct.StringWithSeparator.html
+[user guide]: https://docs.rs/serde_with/3.0.0/serde_with/guide/index.html
+[with-annotation]: https://serde.rs/field-attrs.html#with
+[as-annotation]: https://docs.rs/serde_with/3.0.0/serde_with/guide/serde_as/index.html
+
+## License
+
+Licensed under either of
+
+* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
+* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
+
+at your option.
+
+## Contribution
+
+For detailed contribution instructions please read [`CONTRIBUTING.md`].
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in the work by you, as defined in the Apache-2.0 license, shall
+be dual licensed as above, without any additional terms or conditions.
+
+[`CONTRIBUTING.md`]: https://github.com/jonasbb/serde_with/blob/master/CONTRIBUTING.md
diff --git a/third_party/rust/serde_with/src/base64.rs b/third_party/rust/serde_with/src/base64.rs
new file mode 100644
index 0000000000..0e52e0c4b3
--- /dev/null
+++ b/third_party/rust/serde_with/src/base64.rs
@@ -0,0 +1,232 @@
+//! De/Serialization of base64 encoded bytes
+//!
+//! This modules is only available when using the `base64` feature of the crate.
+//!
+//! Please check the documentation on the [`Base64`] type for details.
+
+use crate::prelude::*;
+
+/// Serialize bytes with base64
+///
+/// The type serializes a sequence of bytes as a base64 string.
+/// It works on any type implementing `AsRef<[u8]>` for serialization and `TryFrom<Vec<u8>>` for deserialization.
+///
+/// The type allows customizing the character set and the padding behavior.
+/// The `ALPHABET` is a type implementing [`Alphabet`].
+/// `PADDING` specifies if serializing should emit padding.
+/// Deserialization always supports padded and unpadded formats.
+/// [`formats::Padded`] emits padding and [`formats::Unpadded`] leaves it off.
+///
+/// ```rust
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_with::serde_as;
+/// use serde_with::base64::{Base64, Bcrypt, BinHex, Standard};
+/// use serde_with::formats::{Padded, Unpadded};
+///
+/// #[serde_as]
+/// # #[derive(Debug, PartialEq, Eq)]
+/// #[derive(Serialize, Deserialize)]
+/// struct B64 {
+/// // The default is the same as Standard character set with padding
+/// #[serde_as(as = "Base64")]
+/// default: Vec<u8>,
+/// // Only change the character set, implies padding
+/// #[serde_as(as = "Base64<BinHex>")]
+/// charset_binhex: Vec<u8>,
+///
+/// #[serde_as(as = "Base64<Standard, Padded>")]
+/// explicit_padding: Vec<u8>,
+/// #[serde_as(as = "Base64<Bcrypt, Unpadded>")]
+/// no_padding: Vec<u8>,
+/// }
+///
+/// let b64 = B64 {
+/// default: b"Hello World".to_vec(),
+/// charset_binhex: b"Hello World".to_vec(),
+/// explicit_padding: b"Hello World".to_vec(),
+/// no_padding: b"Hello World".to_vec(),
+/// };
+/// let json = serde_json::json!({
+/// "default": "SGVsbG8gV29ybGQ=",
+/// "charset_binhex": "5'8VD'mI8epaD'3=",
+/// "explicit_padding": "SGVsbG8gV29ybGQ=",
+/// "no_padding": "QETqZE6eT07wZEO",
+/// });
+///
+/// // Test serialization and deserialization
+/// assert_eq!(json, serde_json::to_value(&b64).unwrap());
+/// assert_eq!(b64, serde_json::from_value(json).unwrap());
+/// # }
+/// ```
+
+// The padding might be better as `const PADDING: bool = true`
+// https://blog.rust-lang.org/inside-rust/2021/09/06/Splitting-const-generics.html#featureconst_generics_default/
+pub struct Base64<ALPHABET: Alphabet = Standard, PADDING: formats::Format = formats::Padded>(
+ PhantomData<(ALPHABET, PADDING)>,
+);
+
+impl<T, ALPHABET> SerializeAs<T> for Base64<ALPHABET, formats::Padded>
+where
+ T: AsRef<[u8]>,
+ ALPHABET: Alphabet,
+{
+ fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ use ::base64::Engine as _;
+
+ ::base64::engine::GeneralPurpose::new(
+ &ALPHABET::charset(),
+ ::base64::engine::general_purpose::PAD,
+ )
+ .encode(source)
+ .serialize(serializer)
+ }
+}
+
+impl<T, ALPHABET> SerializeAs<T> for Base64<ALPHABET, formats::Unpadded>
+where
+ T: AsRef<[u8]>,
+ ALPHABET: Alphabet,
+{
+ fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ use ::base64::Engine as _;
+
+ ::base64::engine::GeneralPurpose::new(
+ &ALPHABET::charset(),
+ ::base64::engine::general_purpose::NO_PAD,
+ )
+ .encode(source)
+ .serialize(serializer)
+ }
+}
+
+// Our decoders uniformly do not care about padding.
+const PAD_INDIFFERENT: ::base64::engine::GeneralPurposeConfig =
+ ::base64::engine::GeneralPurposeConfig::new()
+ .with_decode_padding_mode(::base64::engine::DecodePaddingMode::Indifferent);
+
+impl<'de, T, ALPHABET, FORMAT> DeserializeAs<'de, T> for Base64<ALPHABET, FORMAT>
+where
+ T: TryFrom<Vec<u8>>,
+ ALPHABET: Alphabet,
+ FORMAT: formats::Format,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct Helper<T, ALPHABET>(PhantomData<(T, ALPHABET)>);
+
+ impl<'de, T, ALPHABET> Visitor<'de> for Helper<T, ALPHABET>
+ where
+ T: TryFrom<Vec<u8>>,
+ ALPHABET: Alphabet,
+ {
+ type Value = T;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a base64 encoded string")
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ use ::base64::Engine as _;
+
+ let bytes =
+ ::base64::engine::GeneralPurpose::new(&ALPHABET::charset(), PAD_INDIFFERENT)
+ .decode(value)
+ .map_err(DeError::custom)?;
+
+ let length = bytes.len();
+ bytes.try_into().map_err(|_e: T::Error| {
+ DeError::custom(format_args!(
+ "Can't convert a Byte Vector of length {length} to the output type."
+ ))
+ })
+ }
+ }
+
+ deserializer.deserialize_str(Helper::<T, ALPHABET>(PhantomData))
+ }
+}
+
+mod sealed {
+ pub trait Sealed {}
+ impl Sealed for super::Standard {}
+ impl Sealed for super::UrlSafe {}
+ impl Sealed for super::Crypt {}
+ impl Sealed for super::Bcrypt {}
+ impl Sealed for super::ImapMutf7 {}
+ impl Sealed for super::BinHex {}
+}
+
+/// A base64 alphabet
+pub trait Alphabet: sealed::Sealed {
+ /// Return a specific alphabet.
+ fn charset() -> ::base64::alphabet::Alphabet;
+}
+/// The standard character set (uses `+` and `/`).
+///
+/// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-3).
+pub struct Standard;
+impl Alphabet for Standard {
+ fn charset() -> ::base64::alphabet::Alphabet {
+ ::base64::alphabet::STANDARD
+ }
+}
+
+/// The URL safe character set (uses `-` and `_`).
+///
+/// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-3).
+pub struct UrlSafe;
+impl Alphabet for UrlSafe {
+ fn charset() -> ::base64::alphabet::Alphabet {
+ ::base64::alphabet::URL_SAFE
+ }
+}
+
+/// The `crypt(3)` character set (uses `./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`).
+///
+/// Not standardized, but folk wisdom on the net asserts that this alphabet is what crypt uses.
+pub struct Crypt;
+impl Alphabet for Crypt {
+ fn charset() -> ::base64::alphabet::Alphabet {
+ ::base64::alphabet::CRYPT
+ }
+}
+
+/// The bcrypt character set (uses `./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`).
+pub struct Bcrypt;
+impl Alphabet for Bcrypt {
+ fn charset() -> ::base64::alphabet::Alphabet {
+ ::base64::alphabet::BCRYPT
+ }
+}
+
+/// The character set used in IMAP-modified UTF-7 (uses `+` and `,`).
+///
+/// See [RFC 3501](https://tools.ietf.org/html/rfc3501#section-5.1.3).
+pub struct ImapMutf7;
+impl Alphabet for ImapMutf7 {
+ fn charset() -> ::base64::alphabet::Alphabet {
+ ::base64::alphabet::IMAP_MUTF7
+ }
+}
+
+/// The character set used in BinHex 4.0 files.
+///
+/// See [BinHex 4.0 Definition](http://files.stairways.com/other/binhex-40-specs-info.txt).
+pub struct BinHex;
+impl Alphabet for BinHex {
+ fn charset() -> ::base64::alphabet::Alphabet {
+ ::base64::alphabet::BIN_HEX
+ }
+}
diff --git a/third_party/rust/serde_with/src/chrono_0_4.rs b/third_party/rust/serde_with/src/chrono_0_4.rs
new file mode 100644
index 0000000000..a5cf829ebe
--- /dev/null
+++ b/third_party/rust/serde_with/src/chrono_0_4.rs
@@ -0,0 +1,655 @@
+//! De/Serialization of [chrono] types
+//!
+//! This modules is only available if using the `chrono_0_4` feature of the crate.
+//!
+//! [chrono]: https://docs.rs/chrono/
+
+use crate::{
+ formats::{Flexible, Format, Strict, Strictness},
+ prelude::*,
+};
+#[cfg(feature = "std")]
+use ::chrono_0_4::Local;
+use ::chrono_0_4::{DateTime, Duration, NaiveDateTime, TimeZone, Utc};
+
+/// Create a [`DateTime`] for the Unix Epoch using the [`Utc`] timezone
+fn unix_epoch_utc() -> DateTime<Utc> {
+ DateTime::<Utc>::from_utc(unix_epoch_naive(), Utc)
+}
+
+/// Create a [`DateTime`] for the Unix Epoch using the [`Local`] timezone
+#[cfg(feature = "std")]
+fn unix_epoch_local() -> DateTime<Local> {
+ unix_epoch_utc().with_timezone(&Local)
+}
+
+/// Create a [`NaiveDateTime`] for the Unix Epoch
+fn unix_epoch_naive() -> NaiveDateTime {
+ NaiveDateTime::from_timestamp_opt(0, 0).unwrap()
+}
+
+/// 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
+///
+/// ```
+/// # use chrono_0_4::{DateTime, Utc};
+/// # use serde::Deserialize;
+/// #
+/// #[derive(Debug, Deserialize)]
+/// struct S {
+/// #[serde(with = "serde_with::chrono_0_4::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());
+/// ```
+// Requires float operations from std
+#[cfg(feature = "std")]
+pub mod datetime_utc_ts_seconds_from_any {
+ use super::*;
+
+ /// 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 fmt::Formatter<'_>) -> fmt::Result {
+ formatter
+ .write_str("an integer, float, or string with optional subsecond precision.")
+ }
+
+ fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ let ndt = NaiveDateTime::from_timestamp_opt(value, 0);
+ if let Some(ndt) = ndt {
+ Ok(DateTime::<Utc>::from_utc(ndt, Utc))
+ } else {
+ Err(DeError::custom(format_args!(
+ "a timestamp which can be represented in a DateTime but received '{value}'"
+ )))
+ }
+ }
+
+ fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ let ndt = NaiveDateTime::from_timestamp_opt(value as i64, 0);
+ if let Some(ndt) = ndt {
+ Ok(DateTime::<Utc>::from_utc(ndt, Utc))
+ } else {
+ Err(DeError::custom(format_args!(
+ "a timestamp which can be represented in a DateTime but received '{value}'"
+ )))
+ }
+ }
+
+ fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ 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(DeError::custom(format_args!(
+ "a timestamp which can be represented in a DateTime but received '{value}'"
+ )))
+ }
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ let parts: Vec<_> = value.split('.').collect();
+
+ match *parts.as_slice() {
+ [seconds] => {
+ if let Ok(seconds) = seconds.parse() {
+ let ndt = NaiveDateTime::from_timestamp_opt(seconds, 0);
+ if let Some(ndt) = ndt {
+ Ok(DateTime::<Utc>::from_utc(ndt, Utc))
+ } else {
+ Err(DeError::custom(format_args!(
+ "a timestamp which can be represented in a DateTime but received '{value}'"
+ )))
+ }
+ } else {
+ Err(DeError::invalid_value(Unexpected::Str(value), &self))
+ }
+ }
+ [seconds, subseconds] => {
+ if let Ok(seconds) = seconds.parse() {
+ let subseclen = subseconds.chars().count() as u32;
+ if subseclen > 9 {
+ return Err(DeError::custom(format_args!(
+ "DateTimes only support nanosecond precision but '{value}' has more than 9 digits."
+ )));
+ }
+
+ if let Ok(mut subseconds) = subseconds.parse() {
+ // 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(DeError::custom(format_args!(
+ "a timestamp which can be represented in a DateTime but received '{value}'"
+ )))
+ }
+ } else {
+ Err(DeError::invalid_value(Unexpected::Str(value), &self))
+ }
+ } else {
+ Err(DeError::invalid_value(Unexpected::Str(value), &self))
+ }
+ }
+
+ _ => Err(DeError::invalid_value(Unexpected::Str(value), &self)),
+ }
+ }
+ }
+
+ deserializer.deserialize_any(Helper)
+ }
+}
+
+impl SerializeAs<NaiveDateTime> for DateTime<Utc> {
+ fn serialize_as<S>(source: &NaiveDateTime, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ let datetime = DateTime::<Utc>::from_utc(*source, Utc);
+ datetime.serialize(serializer)
+ }
+}
+
+impl<'de> DeserializeAs<'de, NaiveDateTime> for DateTime<Utc> {
+ fn deserialize_as<D>(deserializer: D) -> Result<NaiveDateTime, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ DateTime::<Utc>::deserialize(deserializer).map(|datetime| datetime.naive_utc())
+ }
+}
+
+/// Convert a [`chrono_0_4::Duration`] into a [`DurationSigned`]
+fn duration_into_duration_signed(dur: &Duration) -> DurationSigned {
+ match dur.to_std() {
+ Ok(dur) => DurationSigned::with_duration(Sign::Positive, dur),
+ Err(_) => {
+ if let Ok(dur) = (-*dur).to_std() {
+ DurationSigned::with_duration(Sign::Negative, dur)
+ } else {
+ panic!("A chrono Duration should be convertible to a DurationSigned")
+ }
+ }
+ }
+}
+
+/// Convert a [`DurationSigned`] into a [`chrono_0_4::Duration`]
+fn duration_from_duration_signed<'de, D>(dur: DurationSigned) -> Result<Duration, D::Error>
+where
+ D: Deserializer<'de>,
+{
+ let mut chrono_dur = match Duration::from_std(dur.duration) {
+ Ok(dur) => dur,
+ Err(msg) => {
+ return Err(DeError::custom(format_args!(
+ "Duration is outside of the representable range: {msg}"
+ )))
+ }
+ };
+ if dur.sign.is_negative() {
+ chrono_dur = -chrono_dur;
+ }
+ Ok(chrono_dur)
+}
+
+macro_rules! use_duration_signed_ser {
+ (
+ $main_trait:ident $internal_trait:ident =>
+ {
+ $ty:ty; $converter:ident =>
+ $({
+ $format:ty, $strictness:ty =>
+ $($tbound:ident: $bound:ident $(,)?)*
+ })*
+ }
+ ) => {
+ $(
+ impl<$($tbound ,)*> SerializeAs<$ty> for $main_trait<$format, $strictness>
+ where
+ $($tbound: $bound,)*
+ {
+ fn serialize_as<S>(source: &$ty, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ let dur: DurationSigned = $converter(source);
+ $internal_trait::<$format, $strictness>::serialize_as(
+ &dur,
+ serializer,
+ )
+ }
+ }
+ )*
+ };
+ (
+ $( $main_trait:ident $internal_trait:ident, )+ => $rest:tt
+ ) => {
+ $( use_duration_signed_ser!($main_trait $internal_trait => $rest); )+
+ };
+}
+
+fn datetime_to_duration<TZ>(source: &DateTime<TZ>) -> DurationSigned
+where
+ TZ: TimeZone,
+{
+ duration_into_duration_signed(&source.clone().signed_duration_since(unix_epoch_utc()))
+}
+
+fn naive_datetime_to_duration(source: &NaiveDateTime) -> DurationSigned {
+ duration_into_duration_signed(&source.signed_duration_since(unix_epoch_naive()))
+}
+
+use_duration_signed_ser!(
+ DurationSeconds DurationSeconds,
+ DurationMilliSeconds DurationMilliSeconds,
+ DurationMicroSeconds DurationMicroSeconds,
+ DurationNanoSeconds DurationNanoSeconds,
+ => {
+ Duration; duration_into_duration_signed =>
+ {i64, STRICTNESS => STRICTNESS: Strictness}
+ {f64, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+#[cfg(feature = "alloc")]
+use_duration_signed_ser!(
+ DurationSeconds DurationSeconds,
+ DurationMilliSeconds DurationMilliSeconds,
+ DurationMicroSeconds DurationMicroSeconds,
+ DurationNanoSeconds DurationNanoSeconds,
+ => {
+ Duration; duration_into_duration_signed =>
+ {String, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+use_duration_signed_ser!(
+ TimestampSeconds DurationSeconds,
+ TimestampMilliSeconds DurationMilliSeconds,
+ TimestampMicroSeconds DurationMicroSeconds,
+ TimestampNanoSeconds DurationNanoSeconds,
+ => {
+ DateTime<TZ>; datetime_to_duration =>
+ {i64, STRICTNESS => TZ: TimeZone, STRICTNESS: Strictness}
+ {f64, STRICTNESS => TZ: TimeZone, STRICTNESS: Strictness}
+ }
+);
+#[cfg(feature = "alloc")]
+use_duration_signed_ser!(
+ TimestampSeconds DurationSeconds,
+ TimestampMilliSeconds DurationMilliSeconds,
+ TimestampMicroSeconds DurationMicroSeconds,
+ TimestampNanoSeconds DurationNanoSeconds,
+ => {
+ DateTime<TZ>; datetime_to_duration =>
+ {String, STRICTNESS => TZ: TimeZone, STRICTNESS: Strictness}
+ }
+);
+use_duration_signed_ser!(
+ TimestampSeconds DurationSeconds,
+ TimestampMilliSeconds DurationMilliSeconds,
+ TimestampMicroSeconds DurationMicroSeconds,
+ TimestampNanoSeconds DurationNanoSeconds,
+ => {
+ NaiveDateTime; naive_datetime_to_duration =>
+ {i64, STRICTNESS => STRICTNESS: Strictness}
+ {f64, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+#[cfg(feature = "alloc")]
+use_duration_signed_ser!(
+ TimestampSeconds DurationSeconds,
+ TimestampMilliSeconds DurationMilliSeconds,
+ TimestampMicroSeconds DurationMicroSeconds,
+ TimestampNanoSeconds DurationNanoSeconds,
+ => {
+ NaiveDateTime; naive_datetime_to_duration =>
+ {String, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+
+// Duration/Timestamp WITH FRACTIONS
+use_duration_signed_ser!(
+ DurationSecondsWithFrac DurationSecondsWithFrac,
+ DurationMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ DurationMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ DurationNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ Duration; duration_into_duration_signed =>
+ {f64, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+#[cfg(feature = "alloc")]
+use_duration_signed_ser!(
+ DurationSecondsWithFrac DurationSecondsWithFrac,
+ DurationMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ DurationMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ DurationNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ Duration; duration_into_duration_signed =>
+ {String, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+use_duration_signed_ser!(
+ TimestampSecondsWithFrac DurationSecondsWithFrac,
+ TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ DateTime<TZ>; datetime_to_duration =>
+ {f64, STRICTNESS => TZ: TimeZone, STRICTNESS: Strictness}
+ }
+);
+#[cfg(feature = "alloc")]
+use_duration_signed_ser!(
+ TimestampSecondsWithFrac DurationSecondsWithFrac,
+ TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ DateTime<TZ>; datetime_to_duration =>
+ {String, STRICTNESS => TZ: TimeZone, STRICTNESS: Strictness}
+ }
+);
+use_duration_signed_ser!(
+ TimestampSecondsWithFrac DurationSecondsWithFrac,
+ TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ NaiveDateTime; naive_datetime_to_duration =>
+ {f64, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+#[cfg(feature = "alloc")]
+use_duration_signed_ser!(
+ TimestampSecondsWithFrac DurationSecondsWithFrac,
+ TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ NaiveDateTime; naive_datetime_to_duration =>
+ {String, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+
+macro_rules! use_duration_signed_de {
+ (
+ $main_trait:ident $internal_trait:ident =>
+ {
+ $ty:ty; $converter:ident =>
+ $({
+ $format:ty, $strictness:ty =>
+ $($tbound:ident: $bound:ident)*
+ })*
+ }
+ ) =>{
+ $(
+ impl<'de, $($tbound,)*> DeserializeAs<'de, $ty> for $main_trait<$format, $strictness>
+ where
+ $($tbound: $bound,)*
+ {
+ fn deserialize_as<D>(deserializer: D) -> Result<$ty, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let dur: DurationSigned = $internal_trait::<$format, $strictness>::deserialize_as(deserializer)?;
+ $converter::<D>(dur)
+ }
+ }
+ )*
+ };
+ (
+ $( $main_trait:ident $internal_trait:ident, )+ => $rest:tt
+ ) => {
+ $( use_duration_signed_de!($main_trait $internal_trait => $rest); )+
+ };
+}
+
+fn duration_to_datetime_utc<'de, D>(dur: DurationSigned) -> Result<DateTime<Utc>, D::Error>
+where
+ D: Deserializer<'de>,
+{
+ Ok(unix_epoch_utc() + duration_from_duration_signed::<D>(dur)?)
+}
+
+#[cfg(feature = "std")]
+fn duration_to_datetime_local<'de, D>(dur: DurationSigned) -> Result<DateTime<Local>, D::Error>
+where
+ D: Deserializer<'de>,
+{
+ Ok(unix_epoch_local() + duration_from_duration_signed::<D>(dur)?)
+}
+
+fn duration_to_naive_datetime<'de, D>(dur: DurationSigned) -> Result<NaiveDateTime, D::Error>
+where
+ D: Deserializer<'de>,
+{
+ Ok(unix_epoch_naive() + duration_from_duration_signed::<D>(dur)?)
+}
+
+// No subsecond precision
+use_duration_signed_de!(
+ DurationSeconds DurationSeconds,
+ DurationMilliSeconds DurationMilliSeconds,
+ DurationMicroSeconds DurationMicroSeconds,
+ DurationNanoSeconds DurationNanoSeconds,
+ => {
+ Duration; duration_from_duration_signed =>
+ {i64, Strict =>}
+ {FORMAT, Flexible => FORMAT: Format}
+ }
+);
+#[cfg(feature = "alloc")]
+use_duration_signed_de!(
+ DurationSeconds DurationSeconds,
+ DurationMilliSeconds DurationMilliSeconds,
+ DurationMicroSeconds DurationMicroSeconds,
+ DurationNanoSeconds DurationNanoSeconds,
+ => {
+ Duration; duration_from_duration_signed =>
+ {String, Strict =>}
+ }
+);
+#[cfg(feature = "std")]
+use_duration_signed_de!(
+ DurationSeconds DurationSeconds,
+ DurationMilliSeconds DurationMilliSeconds,
+ DurationMicroSeconds DurationMicroSeconds,
+ DurationNanoSeconds DurationNanoSeconds,
+ => {
+ Duration; duration_from_duration_signed =>
+ {f64, Strict =>}
+ }
+);
+use_duration_signed_de!(
+ TimestampSeconds DurationSeconds,
+ TimestampMilliSeconds DurationMilliSeconds,
+ TimestampMicroSeconds DurationMicroSeconds,
+ TimestampNanoSeconds DurationNanoSeconds,
+ => {
+ DateTime<Utc>; duration_to_datetime_utc =>
+ {i64, Strict =>}
+ {FORMAT, Flexible => FORMAT: Format}
+ }
+);
+#[cfg(feature = "alloc")]
+use_duration_signed_de!(
+ TimestampSeconds DurationSeconds,
+ TimestampMilliSeconds DurationMilliSeconds,
+ TimestampMicroSeconds DurationMicroSeconds,
+ TimestampNanoSeconds DurationNanoSeconds,
+ => {
+ DateTime<Utc>; duration_to_datetime_utc =>
+ {String, Strict =>}
+ }
+);
+#[cfg(feature = "std")]
+use_duration_signed_de!(
+ TimestampSeconds DurationSeconds,
+ TimestampMilliSeconds DurationMilliSeconds,
+ TimestampMicroSeconds DurationMicroSeconds,
+ TimestampNanoSeconds DurationNanoSeconds,
+ => {
+ DateTime<Utc>; duration_to_datetime_utc =>
+ {f64, Strict =>}
+ }
+);
+#[cfg(feature = "std")]
+use_duration_signed_de!(
+ TimestampSeconds DurationSeconds,
+ TimestampMilliSeconds DurationMilliSeconds,
+ TimestampMicroSeconds DurationMicroSeconds,
+ TimestampNanoSeconds DurationNanoSeconds,
+ => {
+ DateTime<Local>; duration_to_datetime_local =>
+ {i64, Strict =>}
+ {f64, Strict =>}
+ {String, Strict =>}
+ {FORMAT, Flexible => FORMAT: Format}
+ }
+);
+use_duration_signed_de!(
+ TimestampSeconds DurationSeconds,
+ TimestampMilliSeconds DurationMilliSeconds,
+ TimestampMicroSeconds DurationMicroSeconds,
+ TimestampNanoSeconds DurationNanoSeconds,
+ => {
+ NaiveDateTime; duration_to_naive_datetime =>
+ {i64, Strict =>}
+ {FORMAT, Flexible => FORMAT: Format}
+ }
+);
+#[cfg(feature = "alloc")]
+use_duration_signed_de!(
+ TimestampSeconds DurationSeconds,
+ TimestampMilliSeconds DurationMilliSeconds,
+ TimestampMicroSeconds DurationMicroSeconds,
+ TimestampNanoSeconds DurationNanoSeconds,
+ => {
+ NaiveDateTime; duration_to_naive_datetime =>
+ {String, Strict =>}
+ }
+);
+#[cfg(feature = "std")]
+use_duration_signed_de!(
+ TimestampSeconds DurationSeconds,
+ TimestampMilliSeconds DurationMilliSeconds,
+ TimestampMicroSeconds DurationMicroSeconds,
+ TimestampNanoSeconds DurationNanoSeconds,
+ => {
+ NaiveDateTime; duration_to_naive_datetime =>
+ {f64, Strict =>}
+ }
+);
+
+// Duration/Timestamp WITH FRACTIONS
+use_duration_signed_de!(
+ DurationSecondsWithFrac DurationSecondsWithFrac,
+ DurationMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ DurationMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ DurationNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ Duration; duration_from_duration_signed =>
+ {f64, Strict =>}
+ {FORMAT, Flexible => FORMAT: Format}
+ }
+);
+#[cfg(feature = "alloc")]
+use_duration_signed_de!(
+ DurationSecondsWithFrac DurationSecondsWithFrac,
+ DurationMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ DurationMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ DurationNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ Duration; duration_from_duration_signed =>
+ {String, Strict =>}
+ }
+);
+use_duration_signed_de!(
+ TimestampSecondsWithFrac DurationSecondsWithFrac,
+ TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ DateTime<Utc>; duration_to_datetime_utc =>
+ {f64, Strict =>}
+ {FORMAT, Flexible => FORMAT: Format}
+ }
+);
+#[cfg(feature = "alloc")]
+use_duration_signed_de!(
+ TimestampSecondsWithFrac DurationSecondsWithFrac,
+ TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ DateTime<Utc>; duration_to_datetime_utc =>
+ {String, Strict =>}
+ }
+);
+#[cfg(feature = "std")]
+use_duration_signed_de!(
+ TimestampSecondsWithFrac DurationSecondsWithFrac,
+ TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ DateTime<Local>; duration_to_datetime_local =>
+ {f64, Strict =>}
+ {String, Strict =>}
+ {FORMAT, Flexible => FORMAT: Format}
+ }
+);
+use_duration_signed_de!(
+ TimestampSecondsWithFrac DurationSecondsWithFrac,
+ TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ NaiveDateTime; duration_to_naive_datetime =>
+ {f64, Strict =>}
+ {FORMAT, Flexible => FORMAT: Format}
+ }
+);
+#[cfg(feature = "alloc")]
+use_duration_signed_de!(
+ TimestampSecondsWithFrac DurationSecondsWithFrac,
+ TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ NaiveDateTime; duration_to_naive_datetime =>
+ {String, Strict =>}
+ }
+);
diff --git a/third_party/rust/serde_with/src/content/de.rs b/third_party/rust/serde_with/src/content/de.rs
new file mode 100644
index 0000000000..98e8a5301c
--- /dev/null
+++ b/third_party/rust/serde_with/src/content/de.rs
@@ -0,0 +1,1894 @@
+//! Buffer for deserializing data.
+//!
+//! This is a copy and improvement of the `serde` private type:
+//! <https://github.com/serde-rs/serde/blob/f85c4f2fa99c7f3b103e6e2580e75eb9313b00d0/serde/src/private/de.rs#L195>
+//! The code is very stable in the `serde` crate, so no maintainability problem is expected.
+//!
+//! Since the type is private we copy the type here.
+//! `serde` is licensed as MIT+Apache2, the same as this crate.
+//!
+//! This version carries improvements compared to `serde`'s version.
+//! The types support 128-bit integers, which is supported for all targets in Rust 1.40+.
+//! A value for `is_human_readable` is passed through all types, to preserve the information.
+//!
+//! In the future this can hopefully be replaced by a public type in `serde` itself.
+//! <https://github.com/serde-rs/serde/pull/2348>
+
+use crate::{
+ prelude::*,
+ utils::{size_hint_cautious, size_hint_from_bounds},
+};
+
+/// Used from generated code to buffer the contents of the Deserializer when
+/// deserializing untagged enums and internally tagged enums.
+///
+/// Not public API. Use serde-value instead.
+#[derive(Debug, Clone)]
+pub(crate) enum Content<'de> {
+ Bool(bool),
+
+ U8(u8),
+ U16(u16),
+ U32(u32),
+ U64(u64),
+ U128(u128),
+
+ I8(i8),
+ I16(i16),
+ I32(i32),
+ I64(i64),
+ I128(i128),
+
+ F32(f32),
+ F64(f64),
+
+ Char(char),
+ String(String),
+ Str(&'de str),
+ ByteBuf(Vec<u8>),
+ Bytes(&'de [u8]),
+
+ None,
+ Some(Box<Content<'de>>),
+
+ Unit,
+ Newtype(Box<Content<'de>>),
+ Seq(Vec<Content<'de>>),
+ Map(Vec<(Content<'de>, Content<'de>)>),
+}
+
+impl<'de> Content<'de> {
+ #[cold]
+ fn unexpected(&self) -> Unexpected<'_> {
+ match *self {
+ Content::Bool(b) => Unexpected::Bool(b),
+ Content::U8(n) => Unexpected::Unsigned(n as u64),
+ Content::U16(n) => Unexpected::Unsigned(n as u64),
+ Content::U32(n) => Unexpected::Unsigned(n as u64),
+ Content::U64(n) => Unexpected::Unsigned(n),
+ Content::U128(_) => Unexpected::Other("u128"),
+ Content::I8(n) => Unexpected::Signed(n as i64),
+ Content::I16(n) => Unexpected::Signed(n as i64),
+ Content::I32(n) => Unexpected::Signed(n as i64),
+ Content::I64(n) => Unexpected::Signed(n),
+ Content::I128(_) => Unexpected::Other("i128"),
+ Content::F32(f) => Unexpected::Float(f as f64),
+ Content::F64(f) => Unexpected::Float(f),
+ Content::Char(c) => Unexpected::Char(c),
+ Content::String(ref s) => Unexpected::Str(s),
+ Content::Str(s) => Unexpected::Str(s),
+ Content::ByteBuf(ref b) => Unexpected::Bytes(b),
+ Content::Bytes(b) => Unexpected::Bytes(b),
+ Content::None | Content::Some(_) => Unexpected::Option,
+ Content::Unit => Unexpected::Unit,
+ Content::Newtype(_) => Unexpected::NewtypeStruct,
+ Content::Seq(_) => Unexpected::Seq,
+ Content::Map(_) => Unexpected::Map,
+ }
+ }
+}
+
+impl<'de> Deserialize<'de> for Content<'de> {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ // Untagged and internally tagged enums are only supported in
+ // self-describing formats.
+ let visitor = ContentVisitor { value: PhantomData };
+ deserializer.deserialize_any(visitor)
+ }
+}
+
+struct ContentVisitor<'de> {
+ value: PhantomData<Content<'de>>,
+}
+
+impl<'de> Visitor<'de> for ContentVisitor<'de> {
+ type Value = Content<'de>;
+
+ fn expecting(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.write_str("any value")
+ }
+
+ fn visit_bool<F>(self, value: bool) -> Result<Self::Value, F>
+ where
+ F: DeError,
+ {
+ Ok(Content::Bool(value))
+ }
+
+ fn visit_i8<F>(self, value: i8) -> Result<Self::Value, F>
+ where
+ F: DeError,
+ {
+ Ok(Content::I8(value))
+ }
+
+ fn visit_i16<F>(self, value: i16) -> Result<Self::Value, F>
+ where
+ F: DeError,
+ {
+ Ok(Content::I16(value))
+ }
+
+ fn visit_i32<F>(self, value: i32) -> Result<Self::Value, F>
+ where
+ F: DeError,
+ {
+ Ok(Content::I32(value))
+ }
+
+ fn visit_i64<F>(self, value: i64) -> Result<Self::Value, F>
+ where
+ F: DeError,
+ {
+ Ok(Content::I64(value))
+ }
+
+ fn visit_i128<F>(self, value: i128) -> Result<Self::Value, F>
+ where
+ F: DeError,
+ {
+ Ok(Content::I128(value))
+ }
+
+ fn visit_u8<F>(self, value: u8) -> Result<Self::Value, F>
+ where
+ F: DeError,
+ {
+ Ok(Content::U8(value))
+ }
+
+ fn visit_u16<F>(self, value: u16) -> Result<Self::Value, F>
+ where
+ F: DeError,
+ {
+ Ok(Content::U16(value))
+ }
+
+ fn visit_u32<F>(self, value: u32) -> Result<Self::Value, F>
+ where
+ F: DeError,
+ {
+ Ok(Content::U32(value))
+ }
+
+ fn visit_u64<F>(self, value: u64) -> Result<Self::Value, F>
+ where
+ F: DeError,
+ {
+ Ok(Content::U64(value))
+ }
+
+ fn visit_u128<F>(self, value: u128) -> Result<Self::Value, F>
+ where
+ F: DeError,
+ {
+ Ok(Content::U128(value))
+ }
+
+ fn visit_f32<F>(self, value: f32) -> Result<Self::Value, F>
+ where
+ F: DeError,
+ {
+ Ok(Content::F32(value))
+ }
+
+ fn visit_f64<F>(self, value: f64) -> Result<Self::Value, F>
+ where
+ F: DeError,
+ {
+ Ok(Content::F64(value))
+ }
+
+ fn visit_char<F>(self, value: char) -> Result<Self::Value, F>
+ where
+ F: DeError,
+ {
+ Ok(Content::Char(value))
+ }
+
+ fn visit_str<F>(self, value: &str) -> Result<Self::Value, F>
+ where
+ F: DeError,
+ {
+ Ok(Content::String(value.into()))
+ }
+
+ fn visit_borrowed_str<F>(self, value: &'de str) -> Result<Self::Value, F>
+ where
+ F: DeError,
+ {
+ Ok(Content::Str(value))
+ }
+
+ fn visit_string<F>(self, value: String) -> Result<Self::Value, F>
+ where
+ F: DeError,
+ {
+ Ok(Content::String(value))
+ }
+
+ fn visit_bytes<F>(self, value: &[u8]) -> Result<Self::Value, F>
+ where
+ F: DeError,
+ {
+ Ok(Content::ByteBuf(value.into()))
+ }
+
+ fn visit_borrowed_bytes<F>(self, value: &'de [u8]) -> Result<Self::Value, F>
+ where
+ F: DeError,
+ {
+ Ok(Content::Bytes(value))
+ }
+
+ fn visit_byte_buf<F>(self, value: Vec<u8>) -> Result<Self::Value, F>
+ where
+ F: DeError,
+ {
+ Ok(Content::ByteBuf(value))
+ }
+
+ fn visit_unit<F>(self) -> Result<Self::Value, F>
+ where
+ F: DeError,
+ {
+ Ok(Content::Unit)
+ }
+
+ fn visit_none<F>(self) -> Result<Self::Value, F>
+ where
+ F: DeError,
+ {
+ Ok(Content::None)
+ }
+
+ fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ Deserialize::deserialize(deserializer).map(|v| Content::Some(Box::new(v)))
+ }
+
+ fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ Deserialize::deserialize(deserializer).map(|v| Content::Newtype(Box::new(v)))
+ }
+
+ fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
+ where
+ V: SeqAccess<'de>,
+ {
+ let mut vec = Vec::with_capacity(size_hint_cautious(visitor.size_hint()));
+ while let Some(e) = visitor.next_element()? {
+ vec.push(e);
+ }
+ Ok(Content::Seq(vec))
+ }
+
+ fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
+ where
+ V: MapAccess<'de>,
+ {
+ let mut vec = Vec::with_capacity(size_hint_cautious(visitor.size_hint()));
+ while let Some(kv) = visitor.next_entry()? {
+ vec.push(kv);
+ }
+ Ok(Content::Map(vec))
+ }
+
+ fn visit_enum<V>(self, _visitor: V) -> Result<Self::Value, V::Error>
+ where
+ V: EnumAccess<'de>,
+ {
+ Err(DeError::custom(
+ "untagged and internally tagged enums do not support enum input",
+ ))
+ }
+}
+
+pub(crate) struct ContentDeserializer<'de, E> {
+ is_human_readable: bool,
+ content: Content<'de>,
+ err: PhantomData<E>,
+}
+
+impl<'de, E> ContentDeserializer<'de, E>
+where
+ E: DeError,
+{
+ #[cold]
+ fn invalid_type(self, exp: &dyn Expected) -> E {
+ DeError::invalid_type(self.content.unexpected(), exp)
+ }
+
+ fn deserialize_integer<V>(self, visitor: V) -> Result<V::Value, E>
+ where
+ V: Visitor<'de>,
+ {
+ match self.content {
+ Content::U8(v) => visitor.visit_u8(v),
+ Content::U16(v) => visitor.visit_u16(v),
+ Content::U32(v) => visitor.visit_u32(v),
+ Content::U64(v) => visitor.visit_u64(v),
+ Content::U128(v) => visitor.visit_u128(v),
+ Content::I8(v) => visitor.visit_i8(v),
+ Content::I16(v) => visitor.visit_i16(v),
+ Content::I32(v) => visitor.visit_i32(v),
+ Content::I64(v) => visitor.visit_i64(v),
+ Content::I128(v) => visitor.visit_i128(v),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+
+ fn deserialize_float<V>(self, visitor: V) -> Result<V::Value, E>
+ where
+ V: Visitor<'de>,
+ {
+ match self.content {
+ Content::F32(v) => visitor.visit_f32(v),
+ Content::F64(v) => visitor.visit_f64(v),
+ Content::U8(v) => visitor.visit_u8(v),
+ Content::U16(v) => visitor.visit_u16(v),
+ Content::U32(v) => visitor.visit_u32(v),
+ Content::U64(v) => visitor.visit_u64(v),
+ Content::U128(v) => visitor.visit_u128(v),
+ Content::I8(v) => visitor.visit_i8(v),
+ Content::I16(v) => visitor.visit_i16(v),
+ Content::I32(v) => visitor.visit_i32(v),
+ Content::I64(v) => visitor.visit_i64(v),
+ Content::I128(v) => visitor.visit_i128(v),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+}
+
+fn visit_content_seq<'de, V, E>(
+ content: Vec<Content<'de>>,
+ visitor: V,
+ is_human_readable: bool,
+) -> Result<V::Value, E>
+where
+ V: Visitor<'de>,
+ E: DeError,
+{
+ let seq = content
+ .into_iter()
+ .map(|x| ContentDeserializer::new(x, is_human_readable));
+ let mut seq_visitor = serde::de::value::SeqDeserializer::new(seq);
+ let value = visitor.visit_seq(&mut seq_visitor)?;
+ seq_visitor.end()?;
+ Ok(value)
+}
+
+fn visit_content_map<'de, V, E>(
+ content: Vec<(Content<'de>, Content<'de>)>,
+ visitor: V,
+ is_human_readable: bool,
+) -> Result<V::Value, E>
+where
+ V: Visitor<'de>,
+ E: DeError,
+{
+ let map = content.into_iter().map(|(k, v)| {
+ (
+ ContentDeserializer::new(k, is_human_readable),
+ ContentDeserializer::new(v, is_human_readable),
+ )
+ });
+ let mut map_visitor = serde::de::value::MapDeserializer::new(map);
+ let value = visitor.visit_map(&mut map_visitor)?;
+ map_visitor.end()?;
+ Ok(value)
+}
+
+/// Used when deserializing an internally tagged enum because the content
+/// will be used exactly once.
+impl<'de, E> Deserializer<'de> for ContentDeserializer<'de, E>
+where
+ E: DeError,
+{
+ type Error = E;
+
+ #[inline]
+ fn is_human_readable(&self) -> bool {
+ self.is_human_readable
+ }
+
+ fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match self.content {
+ Content::Bool(v) => visitor.visit_bool(v),
+ Content::U8(v) => visitor.visit_u8(v),
+ Content::U16(v) => visitor.visit_u16(v),
+ Content::U32(v) => visitor.visit_u32(v),
+ Content::U64(v) => visitor.visit_u64(v),
+ Content::U128(v) => visitor.visit_u128(v),
+ Content::I8(v) => visitor.visit_i8(v),
+ Content::I16(v) => visitor.visit_i16(v),
+ Content::I32(v) => visitor.visit_i32(v),
+ Content::I64(v) => visitor.visit_i64(v),
+ Content::I128(v) => visitor.visit_i128(v),
+ Content::F32(v) => visitor.visit_f32(v),
+ Content::F64(v) => visitor.visit_f64(v),
+ Content::Char(v) => visitor.visit_char(v),
+ Content::String(v) => visitor.visit_string(v),
+ Content::Str(v) => visitor.visit_borrowed_str(v),
+ Content::ByteBuf(v) => visitor.visit_byte_buf(v),
+ Content::Bytes(v) => visitor.visit_borrowed_bytes(v),
+ Content::Unit => visitor.visit_unit(),
+ Content::None => visitor.visit_none(),
+ Content::Some(v) => {
+ visitor.visit_some(ContentDeserializer::new(*v, self.is_human_readable))
+ }
+ Content::Newtype(v) => {
+ visitor.visit_newtype_struct(ContentDeserializer::new(*v, self.is_human_readable))
+ }
+ Content::Seq(v) => visit_content_seq(v, visitor, self.is_human_readable),
+ Content::Map(v) => visit_content_map(v, visitor, self.is_human_readable),
+ }
+ }
+
+ fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match self.content {
+ Content::Bool(v) => visitor.visit_bool(v),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+
+ fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_integer(visitor)
+ }
+
+ fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_integer(visitor)
+ }
+
+ fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_integer(visitor)
+ }
+
+ fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_integer(visitor)
+ }
+
+ fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_integer(visitor)
+ }
+
+ fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_integer(visitor)
+ }
+
+ fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_integer(visitor)
+ }
+
+ fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_integer(visitor)
+ }
+
+ fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_integer(visitor)
+ }
+
+ fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_integer(visitor)
+ }
+
+ fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_float(visitor)
+ }
+
+ fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_float(visitor)
+ }
+
+ fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match self.content {
+ Content::Char(v) => visitor.visit_char(v),
+ Content::String(v) => visitor.visit_string(v),
+ Content::Str(v) => visitor.visit_borrowed_str(v),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+
+ fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_string(visitor)
+ }
+
+ fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match self.content {
+ Content::String(v) => visitor.visit_string(v),
+ Content::Str(v) => visitor.visit_borrowed_str(v),
+ Content::ByteBuf(v) => visitor.visit_byte_buf(v),
+ Content::Bytes(v) => visitor.visit_borrowed_bytes(v),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+
+ fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_byte_buf(visitor)
+ }
+
+ fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match self.content {
+ Content::String(v) => visitor.visit_string(v),
+ Content::Str(v) => visitor.visit_borrowed_str(v),
+ Content::ByteBuf(v) => visitor.visit_byte_buf(v),
+ Content::Bytes(v) => visitor.visit_borrowed_bytes(v),
+ Content::Seq(v) => visit_content_seq(v, visitor, self.is_human_readable),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+
+ fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match self.content {
+ Content::None => visitor.visit_none(),
+ Content::Some(v) => {
+ visitor.visit_some(ContentDeserializer::new(*v, self.is_human_readable))
+ }
+ Content::Unit => visitor.visit_unit(),
+ _ => visitor.visit_some(self),
+ }
+ }
+
+ fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match self.content {
+ Content::Unit => visitor.visit_unit(),
+
+ // Allow deserializing newtype variant containing unit.
+ //
+ // #[derive(Deserialize)]
+ // #[serde(tag = "result")]
+ // enum Response<T> {
+ // Success(T),
+ // }
+ //
+ // We want {"result":"Success"} to deserialize into Response<()>.
+ Content::Map(ref v) if v.is_empty() => visitor.visit_unit(),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+
+ fn deserialize_unit_struct<V>(
+ self,
+ _name: &'static str,
+ visitor: V,
+ ) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match self.content {
+ // As a special case, allow deserializing untagged newtype
+ // variant containing unit struct.
+ //
+ // #[derive(Deserialize)]
+ // struct Info;
+ //
+ // #[derive(Deserialize)]
+ // #[serde(tag = "topic")]
+ // enum Message {
+ // Info(Info),
+ // }
+ //
+ // We want {"topic":"Info"} to deserialize even though
+ // ordinarily unit structs do not deserialize from empty map/seq.
+ Content::Map(ref v) if v.is_empty() => visitor.visit_unit(),
+ Content::Seq(ref v) if v.is_empty() => visitor.visit_unit(),
+ _ => self.deserialize_any(visitor),
+ }
+ }
+
+ fn deserialize_newtype_struct<V>(self, _name: &str, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match self.content {
+ Content::Newtype(v) => {
+ visitor.visit_newtype_struct(ContentDeserializer::new(*v, self.is_human_readable))
+ }
+ _ => visitor.visit_newtype_struct(self),
+ }
+ }
+
+ fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match self.content {
+ Content::Seq(v) => visit_content_seq(v, visitor, self.is_human_readable),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+
+ fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_seq(visitor)
+ }
+
+ fn deserialize_tuple_struct<V>(
+ self,
+ _name: &'static str,
+ _len: usize,
+ visitor: V,
+ ) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_seq(visitor)
+ }
+
+ fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match self.content {
+ Content::Map(v) => visit_content_map(v, visitor, self.is_human_readable),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+
+ fn deserialize_struct<V>(
+ self,
+ _name: &'static str,
+ _fields: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match self.content {
+ Content::Seq(v) => visit_content_seq(v, visitor, self.is_human_readable),
+ Content::Map(v) => visit_content_map(v, visitor, self.is_human_readable),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+
+ fn deserialize_enum<V>(
+ self,
+ _name: &str,
+ _variants: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ let (variant, value) = match self.content {
+ Content::Map(value) => {
+ let mut iter = value.into_iter();
+ let (variant, value) = match iter.next() {
+ Some(v) => v,
+ None => {
+ return Err(DeError::invalid_value(
+ Unexpected::Map,
+ &"map with a single key",
+ ));
+ }
+ };
+ // enums are encoded in json as maps with a single key:value pair
+ if iter.next().is_some() {
+ return Err(DeError::invalid_value(
+ Unexpected::Map,
+ &"map with a single key",
+ ));
+ }
+ (variant, Some(value))
+ }
+ s @ Content::String(_) | s @ Content::Str(_) => (s, None),
+ other => {
+ return Err(DeError::invalid_type(other.unexpected(), &"string or map"));
+ }
+ };
+
+ visitor.visit_enum(EnumDeserializer::new(
+ variant,
+ value,
+ self.is_human_readable,
+ ))
+ }
+
+ fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match self.content {
+ Content::String(v) => visitor.visit_string(v),
+ Content::Str(v) => visitor.visit_borrowed_str(v),
+ Content::ByteBuf(v) => visitor.visit_byte_buf(v),
+ Content::Bytes(v) => visitor.visit_borrowed_bytes(v),
+ Content::U8(v) => visitor.visit_u8(v),
+ Content::U64(v) => visitor.visit_u64(v),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+
+ fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ drop(self);
+ visitor.visit_unit()
+ }
+}
+
+impl<'de, E> ContentDeserializer<'de, E> {
+ /// private API, don't use
+ pub(crate) fn new(content: Content<'de>, is_human_readable: bool) -> Self {
+ ContentDeserializer {
+ is_human_readable,
+ content,
+ err: PhantomData,
+ }
+ }
+}
+
+struct EnumDeserializer<'de, E>
+where
+ E: DeError,
+{
+ is_human_readable: bool,
+ variant: Content<'de>,
+ value: Option<Content<'de>>,
+ err: PhantomData<E>,
+}
+
+impl<'de, E> EnumDeserializer<'de, E>
+where
+ E: DeError,
+{
+ pub fn new(
+ variant: Content<'de>,
+ value: Option<Content<'de>>,
+ is_human_readable: bool,
+ ) -> EnumDeserializer<'de, E> {
+ EnumDeserializer {
+ is_human_readable,
+ variant,
+ value,
+ err: PhantomData,
+ }
+ }
+}
+
+impl<'de, E> EnumAccess<'de> for EnumDeserializer<'de, E>
+where
+ E: DeError,
+{
+ type Error = E;
+ type Variant = VariantDeserializer<'de, Self::Error>;
+
+ fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), E>
+ where
+ V: DeserializeSeed<'de>,
+ {
+ let visitor = VariantDeserializer {
+ is_human_readable: self.is_human_readable,
+ value: self.value,
+ err: PhantomData,
+ };
+ seed.deserialize(ContentDeserializer::new(
+ self.variant,
+ self.is_human_readable,
+ ))
+ .map(|v| (v, visitor))
+ }
+}
+
+pub struct VariantDeserializer<'de, E>
+where
+ E: DeError,
+{
+ is_human_readable: bool,
+ value: Option<Content<'de>>,
+ err: PhantomData<E>,
+}
+
+impl<'de, E> VariantAccess<'de> for VariantDeserializer<'de, E>
+where
+ E: DeError,
+{
+ type Error = E;
+
+ fn unit_variant(self) -> Result<(), E> {
+ match self.value {
+ Some(value) => {
+ Deserialize::deserialize(ContentDeserializer::new(value, self.is_human_readable))
+ }
+ None => Ok(()),
+ }
+ }
+
+ fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, E>
+ where
+ T: DeserializeSeed<'de>,
+ {
+ match self.value {
+ Some(value) => {
+ seed.deserialize(ContentDeserializer::new(value, self.is_human_readable))
+ }
+ None => Err(DeError::invalid_type(
+ Unexpected::UnitVariant,
+ &"newtype variant",
+ )),
+ }
+ }
+
+ fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match self.value {
+ Some(Content::Seq(v)) => Deserializer::deserialize_any(
+ SeqDeserializer::new(v, self.is_human_readable),
+ visitor,
+ ),
+ Some(other) => Err(DeError::invalid_type(other.unexpected(), &"tuple variant")),
+ None => Err(DeError::invalid_type(
+ Unexpected::UnitVariant,
+ &"tuple variant",
+ )),
+ }
+ }
+
+ fn struct_variant<V>(
+ self,
+ _fields: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match self.value {
+ Some(Content::Map(v)) => Deserializer::deserialize_any(
+ MapDeserializer::new(v, self.is_human_readable),
+ visitor,
+ ),
+ Some(Content::Seq(v)) => Deserializer::deserialize_any(
+ SeqDeserializer::new(v, self.is_human_readable),
+ visitor,
+ ),
+ Some(other) => Err(DeError::invalid_type(other.unexpected(), &"struct variant")),
+ None => Err(DeError::invalid_type(
+ Unexpected::UnitVariant,
+ &"struct variant",
+ )),
+ }
+ }
+}
+
+struct SeqDeserializer<'de, E>
+where
+ E: DeError,
+{
+ is_human_readable: bool,
+ iter: <Vec<Content<'de>> as IntoIterator>::IntoIter,
+ err: PhantomData<E>,
+}
+
+impl<'de, E> SeqDeserializer<'de, E>
+where
+ E: DeError,
+{
+ fn new(vec: Vec<Content<'de>>, is_human_readable: bool) -> Self {
+ SeqDeserializer {
+ is_human_readable,
+ iter: vec.into_iter(),
+ err: PhantomData,
+ }
+ }
+}
+
+impl<'de, E> Deserializer<'de> for SeqDeserializer<'de, E>
+where
+ E: DeError,
+{
+ type Error = E;
+
+ #[inline]
+ fn is_human_readable(&self) -> bool {
+ self.is_human_readable
+ }
+
+ #[inline]
+ fn deserialize_any<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ let len = self.iter.len();
+ if len == 0 {
+ visitor.visit_unit()
+ } else {
+ let ret = visitor.visit_seq(&mut self)?;
+ let remaining = self.iter.len();
+ if remaining == 0 {
+ Ok(ret)
+ } else {
+ Err(DeError::invalid_length(len, &"fewer elements in array"))
+ }
+ }
+ }
+
+ forward_to_deserialize_any! {
+ bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
+ bytes byte_buf option unit unit_struct newtype_struct seq tuple
+ tuple_struct map struct enum identifier ignored_any
+ }
+}
+
+impl<'de, E> SeqAccess<'de> for SeqDeserializer<'de, E>
+where
+ E: DeError,
+{
+ type Error = E;
+
+ fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
+ where
+ T: DeserializeSeed<'de>,
+ {
+ match self.iter.next() {
+ Some(value) => seed
+ .deserialize(ContentDeserializer::new(value, self.is_human_readable))
+ .map(Some),
+ None => Ok(None),
+ }
+ }
+
+ fn size_hint(&self) -> Option<usize> {
+ size_hint_from_bounds(&self.iter)
+ }
+}
+
+struct MapDeserializer<'de, E>
+where
+ E: DeError,
+{
+ is_human_readable: bool,
+ iter: <Vec<(Content<'de>, Content<'de>)> as IntoIterator>::IntoIter,
+ value: Option<Content<'de>>,
+ err: PhantomData<E>,
+}
+
+impl<'de, E> MapDeserializer<'de, E>
+where
+ E: DeError,
+{
+ fn new(map: Vec<(Content<'de>, Content<'de>)>, is_human_readable: bool) -> Self {
+ MapDeserializer {
+ is_human_readable,
+ iter: map.into_iter(),
+ value: None,
+ err: PhantomData,
+ }
+ }
+}
+
+impl<'de, E> MapAccess<'de> for MapDeserializer<'de, E>
+where
+ E: DeError,
+{
+ type Error = E;
+
+ fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
+ where
+ T: DeserializeSeed<'de>,
+ {
+ match self.iter.next() {
+ Some((key, value)) => {
+ self.value = Some(value);
+ seed.deserialize(ContentDeserializer::new(key, self.is_human_readable))
+ .map(Some)
+ }
+ None => Ok(None),
+ }
+ }
+
+ fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error>
+ where
+ T: DeserializeSeed<'de>,
+ {
+ match self.value.take() {
+ Some(value) => {
+ seed.deserialize(ContentDeserializer::new(value, self.is_human_readable))
+ }
+ None => Err(DeError::custom("value is missing")),
+ }
+ }
+
+ fn size_hint(&self) -> Option<usize> {
+ size_hint_from_bounds(&self.iter)
+ }
+}
+
+impl<'de, E> Deserializer<'de> for MapDeserializer<'de, E>
+where
+ E: DeError,
+{
+ type Error = E;
+
+ #[inline]
+ fn is_human_readable(&self) -> bool {
+ self.is_human_readable
+ }
+
+ #[inline]
+ 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
+ }
+}
+
+/// Not public API.
+pub struct ContentRefDeserializer<'a, 'de, E> {
+ is_human_readable: bool,
+ content: &'a Content<'de>,
+ err: PhantomData<E>,
+}
+
+impl<'a, 'de, E> ContentRefDeserializer<'a, 'de, E>
+where
+ E: DeError,
+{
+ #[cold]
+ fn invalid_type(self, exp: &dyn Expected) -> E {
+ DeError::invalid_type(self.content.unexpected(), exp)
+ }
+
+ fn deserialize_integer<V>(self, visitor: V) -> Result<V::Value, E>
+ where
+ V: Visitor<'de>,
+ {
+ match *self.content {
+ Content::U8(v) => visitor.visit_u8(v),
+ Content::U16(v) => visitor.visit_u16(v),
+ Content::U32(v) => visitor.visit_u32(v),
+ Content::U64(v) => visitor.visit_u64(v),
+ Content::U128(v) => visitor.visit_u128(v),
+ Content::I8(v) => visitor.visit_i8(v),
+ Content::I16(v) => visitor.visit_i16(v),
+ Content::I32(v) => visitor.visit_i32(v),
+ Content::I64(v) => visitor.visit_i64(v),
+ Content::I128(v) => visitor.visit_i128(v),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+
+ fn deserialize_float<V>(self, visitor: V) -> Result<V::Value, E>
+ where
+ V: Visitor<'de>,
+ {
+ match *self.content {
+ Content::F32(v) => visitor.visit_f32(v),
+ Content::F64(v) => visitor.visit_f64(v),
+ Content::U8(v) => visitor.visit_u8(v),
+ Content::U16(v) => visitor.visit_u16(v),
+ Content::U32(v) => visitor.visit_u32(v),
+ Content::U64(v) => visitor.visit_u64(v),
+ Content::U128(v) => visitor.visit_u128(v),
+ Content::I8(v) => visitor.visit_i8(v),
+ Content::I16(v) => visitor.visit_i16(v),
+ Content::I32(v) => visitor.visit_i32(v),
+ Content::I64(v) => visitor.visit_i64(v),
+ Content::I128(v) => visitor.visit_i128(v),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+}
+
+fn visit_content_seq_ref<'a, 'de, V, E>(
+ content: &'a [Content<'de>],
+ visitor: V,
+ is_human_readable: bool,
+) -> Result<V::Value, E>
+where
+ V: Visitor<'de>,
+ E: DeError,
+{
+ let seq = content
+ .iter()
+ .map(|x| ContentRefDeserializer::new(x, is_human_readable));
+ let mut seq_visitor = serde::de::value::SeqDeserializer::new(seq);
+ let value = visitor.visit_seq(&mut seq_visitor)?;
+ seq_visitor.end()?;
+ Ok(value)
+}
+
+fn visit_content_map_ref<'a, 'de, V, E>(
+ content: &'a [(Content<'de>, Content<'de>)],
+ visitor: V,
+ is_human_readable: bool,
+) -> Result<V::Value, E>
+where
+ V: Visitor<'de>,
+ E: DeError,
+{
+ let map = content.iter().map(|(k, v)| {
+ (
+ ContentRefDeserializer::new(k, is_human_readable),
+ ContentRefDeserializer::new(v, is_human_readable),
+ )
+ });
+ let mut map_visitor = serde::de::value::MapDeserializer::new(map);
+ let value = visitor.visit_map(&mut map_visitor)?;
+ map_visitor.end()?;
+ Ok(value)
+}
+
+/// Used when deserializing an untagged enum because the content may need
+/// to be used more than once.
+impl<'de, 'a, E> Deserializer<'de> for ContentRefDeserializer<'a, 'de, E>
+where
+ E: DeError,
+{
+ type Error = E;
+
+ #[inline]
+ fn is_human_readable(&self) -> bool {
+ self.is_human_readable
+ }
+
+ fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, E>
+ where
+ V: Visitor<'de>,
+ {
+ match *self.content {
+ Content::Bool(v) => visitor.visit_bool(v),
+ Content::U8(v) => visitor.visit_u8(v),
+ Content::U16(v) => visitor.visit_u16(v),
+ Content::U32(v) => visitor.visit_u32(v),
+ Content::U64(v) => visitor.visit_u64(v),
+ Content::U128(v) => visitor.visit_u128(v),
+ Content::I8(v) => visitor.visit_i8(v),
+ Content::I16(v) => visitor.visit_i16(v),
+ Content::I32(v) => visitor.visit_i32(v),
+ Content::I64(v) => visitor.visit_i64(v),
+ Content::I128(v) => visitor.visit_i128(v),
+ Content::F32(v) => visitor.visit_f32(v),
+ Content::F64(v) => visitor.visit_f64(v),
+ Content::Char(v) => visitor.visit_char(v),
+ Content::String(ref v) => visitor.visit_str(v),
+ Content::Str(v) => visitor.visit_borrowed_str(v),
+ Content::ByteBuf(ref v) => visitor.visit_bytes(v),
+ Content::Bytes(v) => visitor.visit_borrowed_bytes(v),
+ Content::Unit => visitor.visit_unit(),
+ Content::None => visitor.visit_none(),
+ Content::Some(ref v) => {
+ visitor.visit_some(ContentRefDeserializer::new(v, self.is_human_readable))
+ }
+ Content::Newtype(ref v) => {
+ visitor.visit_newtype_struct(ContentRefDeserializer::new(v, self.is_human_readable))
+ }
+ Content::Seq(ref v) => visit_content_seq_ref(v, visitor, self.is_human_readable),
+ Content::Map(ref v) => visit_content_map_ref(v, visitor, self.is_human_readable),
+ }
+ }
+
+ fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match *self.content {
+ Content::Bool(v) => visitor.visit_bool(v),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+
+ fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_integer(visitor)
+ }
+
+ fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_integer(visitor)
+ }
+
+ fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_integer(visitor)
+ }
+
+ fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_integer(visitor)
+ }
+
+ fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_integer(visitor)
+ }
+
+ fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_integer(visitor)
+ }
+
+ fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_integer(visitor)
+ }
+
+ fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_integer(visitor)
+ }
+
+ fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_integer(visitor)
+ }
+
+ fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_integer(visitor)
+ }
+
+ fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_float(visitor)
+ }
+
+ fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_float(visitor)
+ }
+
+ fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match *self.content {
+ Content::Char(v) => visitor.visit_char(v),
+ Content::String(ref v) => visitor.visit_str(v),
+ Content::Str(v) => visitor.visit_borrowed_str(v),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+
+ fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match *self.content {
+ Content::String(ref v) => visitor.visit_str(v),
+ Content::Str(v) => visitor.visit_borrowed_str(v),
+ Content::ByteBuf(ref v) => visitor.visit_bytes(v),
+ Content::Bytes(v) => visitor.visit_borrowed_bytes(v),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+
+ fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_str(visitor)
+ }
+
+ fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match *self.content {
+ Content::String(ref v) => visitor.visit_str(v),
+ Content::Str(v) => visitor.visit_borrowed_str(v),
+ Content::ByteBuf(ref v) => visitor.visit_bytes(v),
+ Content::Bytes(v) => visitor.visit_borrowed_bytes(v),
+ Content::Seq(ref v) => visit_content_seq_ref(v, visitor, self.is_human_readable),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+
+ fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_bytes(visitor)
+ }
+
+ fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, E>
+ where
+ V: Visitor<'de>,
+ {
+ match *self.content {
+ Content::None => visitor.visit_none(),
+ Content::Some(ref v) => {
+ visitor.visit_some(ContentRefDeserializer::new(v, self.is_human_readable))
+ }
+ Content::Unit => visitor.visit_unit(),
+ _ => visitor.visit_some(self),
+ }
+ }
+
+ fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match *self.content {
+ Content::Unit => visitor.visit_unit(),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+
+ fn deserialize_unit_struct<V>(
+ self,
+ _name: &'static str,
+ visitor: V,
+ ) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_unit(visitor)
+ }
+
+ fn deserialize_newtype_struct<V>(self, _name: &str, visitor: V) -> Result<V::Value, E>
+ where
+ V: Visitor<'de>,
+ {
+ match *self.content {
+ Content::Newtype(ref v) => {
+ visitor.visit_newtype_struct(ContentRefDeserializer::new(v, self.is_human_readable))
+ }
+ _ => visitor.visit_newtype_struct(self),
+ }
+ }
+
+ fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match *self.content {
+ Content::Seq(ref v) => visit_content_seq_ref(v, visitor, self.is_human_readable),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+
+ fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_seq(visitor)
+ }
+
+ fn deserialize_tuple_struct<V>(
+ self,
+ _name: &'static str,
+ _len: usize,
+ visitor: V,
+ ) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_seq(visitor)
+ }
+
+ fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match *self.content {
+ Content::Map(ref v) => visit_content_map_ref(v, visitor, self.is_human_readable),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+
+ fn deserialize_struct<V>(
+ self,
+ _name: &'static str,
+ _fields: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match *self.content {
+ Content::Seq(ref v) => visit_content_seq_ref(v, visitor, self.is_human_readable),
+ Content::Map(ref v) => visit_content_map_ref(v, visitor, self.is_human_readable),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+
+ fn deserialize_enum<V>(
+ self,
+ _name: &str,
+ _variants: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ let (variant, value) = match *self.content {
+ Content::Map(ref value) => {
+ let mut iter = value.iter();
+ let (variant, value) = match iter.next() {
+ Some(v) => v,
+ None => {
+ return Err(DeError::invalid_value(
+ Unexpected::Map,
+ &"map with a single key",
+ ));
+ }
+ };
+ // enums are encoded in json as maps with a single key:value pair
+ if iter.next().is_some() {
+ return Err(DeError::invalid_value(
+ Unexpected::Map,
+ &"map with a single key",
+ ));
+ }
+ (variant, Some(value))
+ }
+ ref s @ Content::String(_) | ref s @ Content::Str(_) => (s, None),
+ ref other => {
+ return Err(DeError::invalid_type(other.unexpected(), &"string or map"));
+ }
+ };
+
+ visitor.visit_enum(EnumRefDeserializer {
+ is_human_readable: self.is_human_readable,
+ variant,
+ value,
+ err: PhantomData,
+ })
+ }
+
+ fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match *self.content {
+ Content::String(ref v) => visitor.visit_str(v),
+ Content::Str(v) => visitor.visit_borrowed_str(v),
+ Content::ByteBuf(ref v) => visitor.visit_bytes(v),
+ Content::Bytes(v) => visitor.visit_borrowed_bytes(v),
+ Content::U8(v) => visitor.visit_u8(v),
+ Content::U64(v) => visitor.visit_u64(v),
+ _ => Err(self.invalid_type(&visitor)),
+ }
+ }
+
+ fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_unit()
+ }
+}
+
+impl<'a, 'de, E> ContentRefDeserializer<'a, 'de, E> {
+ /// private API, don't use
+ pub(crate) fn new(content: &'a Content<'de>, is_human_readable: bool) -> Self {
+ ContentRefDeserializer {
+ is_human_readable,
+ content,
+ err: PhantomData,
+ }
+ }
+}
+
+struct EnumRefDeserializer<'a, 'de, E>
+where
+ E: DeError,
+{
+ is_human_readable: bool,
+ variant: &'a Content<'de>,
+ value: Option<&'a Content<'de>>,
+ err: PhantomData<E>,
+}
+
+impl<'de, 'a, E> EnumAccess<'de> for EnumRefDeserializer<'a, 'de, E>
+where
+ E: DeError,
+{
+ type Error = E;
+ type Variant = VariantRefDeserializer<'a, 'de, Self::Error>;
+
+ fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
+ where
+ V: DeserializeSeed<'de>,
+ {
+ let visitor = VariantRefDeserializer {
+ is_human_readable: self.is_human_readable,
+ value: self.value,
+ err: PhantomData,
+ };
+ seed.deserialize(ContentRefDeserializer::new(
+ self.variant,
+ self.is_human_readable,
+ ))
+ .map(|v| (v, visitor))
+ }
+}
+
+struct VariantRefDeserializer<'a, 'de, E>
+where
+ E: DeError,
+{
+ is_human_readable: bool,
+ value: Option<&'a Content<'de>>,
+ err: PhantomData<E>,
+}
+
+impl<'de, 'a, E> VariantAccess<'de> for VariantRefDeserializer<'a, 'de, E>
+where
+ E: DeError,
+{
+ type Error = E;
+
+ fn unit_variant(self) -> Result<(), E> {
+ match self.value {
+ Some(value) => {
+ Deserialize::deserialize(ContentRefDeserializer::new(value, self.is_human_readable))
+ }
+ None => Ok(()),
+ }
+ }
+
+ fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, E>
+ where
+ T: DeserializeSeed<'de>,
+ {
+ match self.value {
+ Some(value) => {
+ seed.deserialize(ContentRefDeserializer::new(value, self.is_human_readable))
+ }
+ None => Err(DeError::invalid_type(
+ Unexpected::UnitVariant,
+ &"newtype variant",
+ )),
+ }
+ }
+
+ fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match self.value {
+ Some(Content::Seq(v)) => Deserializer::deserialize_any(
+ SeqRefDeserializer::new(v, self.is_human_readable),
+ visitor,
+ ),
+ Some(other) => Err(DeError::invalid_type(other.unexpected(), &"tuple variant")),
+ None => Err(DeError::invalid_type(
+ Unexpected::UnitVariant,
+ &"tuple variant",
+ )),
+ }
+ }
+
+ fn struct_variant<V>(
+ self,
+ _fields: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ match self.value {
+ Some(Content::Map(v)) => Deserializer::deserialize_any(
+ MapRefDeserializer::new(v, self.is_human_readable),
+ visitor,
+ ),
+ Some(Content::Seq(v)) => Deserializer::deserialize_any(
+ SeqRefDeserializer::new(v, self.is_human_readable),
+ visitor,
+ ),
+ Some(other) => Err(DeError::invalid_type(other.unexpected(), &"struct variant")),
+ None => Err(DeError::invalid_type(
+ Unexpected::UnitVariant,
+ &"struct variant",
+ )),
+ }
+ }
+}
+
+struct SeqRefDeserializer<'a, 'de, E>
+where
+ E: DeError,
+{
+ is_human_readable: bool,
+ iter: <&'a [Content<'de>] as IntoIterator>::IntoIter,
+ err: PhantomData<E>,
+}
+
+impl<'a, 'de, E> SeqRefDeserializer<'a, 'de, E>
+where
+ E: DeError,
+{
+ fn new(slice: &'a [Content<'de>], is_human_readable: bool) -> Self {
+ SeqRefDeserializer {
+ is_human_readable,
+ iter: slice.iter(),
+ err: PhantomData,
+ }
+ }
+}
+
+impl<'de, 'a, E> Deserializer<'de> for SeqRefDeserializer<'a, 'de, E>
+where
+ E: DeError,
+{
+ type Error = E;
+
+ #[inline]
+ fn is_human_readable(&self) -> bool {
+ self.is_human_readable
+ }
+
+ #[inline]
+ fn deserialize_any<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ let len = self.iter.len();
+ if len == 0 {
+ visitor.visit_unit()
+ } else {
+ let ret = visitor.visit_seq(&mut self)?;
+ let remaining = self.iter.len();
+ if remaining == 0 {
+ Ok(ret)
+ } else {
+ Err(DeError::invalid_length(len, &"fewer elements in array"))
+ }
+ }
+ }
+
+ forward_to_deserialize_any! {
+ bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
+ bytes byte_buf option unit unit_struct newtype_struct seq tuple
+ tuple_struct map struct enum identifier ignored_any
+ }
+}
+
+impl<'de, 'a, E> SeqAccess<'de> for SeqRefDeserializer<'a, 'de, E>
+where
+ E: DeError,
+{
+ type Error = E;
+
+ fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
+ where
+ T: DeserializeSeed<'de>,
+ {
+ match self.iter.next() {
+ Some(value) => seed
+ .deserialize(ContentRefDeserializer::new(value, self.is_human_readable))
+ .map(Some),
+ None => Ok(None),
+ }
+ }
+
+ fn size_hint(&self) -> Option<usize> {
+ size_hint_from_bounds(&self.iter)
+ }
+}
+
+struct MapRefDeserializer<'a, 'de, E>
+where
+ E: DeError,
+{
+ is_human_readable: bool,
+ iter: <&'a [(Content<'de>, Content<'de>)] as IntoIterator>::IntoIter,
+ value: Option<&'a Content<'de>>,
+ err: PhantomData<E>,
+}
+
+impl<'a, 'de, E> MapRefDeserializer<'a, 'de, E>
+where
+ E: DeError,
+{
+ fn new(map: &'a [(Content<'de>, Content<'de>)], is_human_readable: bool) -> Self {
+ MapRefDeserializer {
+ is_human_readable,
+ iter: map.iter(),
+ value: None,
+ err: PhantomData,
+ }
+ }
+}
+
+impl<'de, 'a, E> MapAccess<'de> for MapRefDeserializer<'a, 'de, E>
+where
+ E: DeError,
+{
+ type Error = E;
+
+ fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
+ where
+ T: DeserializeSeed<'de>,
+ {
+ match self.iter.next() {
+ Some((key, value)) => {
+ self.value = Some(value);
+ seed.deserialize(ContentRefDeserializer::new(key, self.is_human_readable))
+ .map(Some)
+ }
+ None => Ok(None),
+ }
+ }
+
+ fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error>
+ where
+ T: DeserializeSeed<'de>,
+ {
+ match self.value.take() {
+ Some(value) => {
+ seed.deserialize(ContentRefDeserializer::new(value, self.is_human_readable))
+ }
+ None => Err(DeError::custom("value is missing")),
+ }
+ }
+
+ fn size_hint(&self) -> Option<usize> {
+ size_hint_from_bounds(&self.iter)
+ }
+}
+
+impl<'de, 'a, E> Deserializer<'de> for MapRefDeserializer<'a, 'de, E>
+where
+ E: DeError,
+{
+ type Error = E;
+
+ #[inline]
+ fn is_human_readable(&self) -> bool {
+ self.is_human_readable
+ }
+
+ #[inline]
+ 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, E> IntoDeserializer<'de, E> for ContentDeserializer<'de, E>
+where
+ E: DeError,
+{
+ type Deserializer = Self;
+
+ fn into_deserializer(self) -> Self {
+ self
+ }
+}
+
+impl<'de, 'a, E> IntoDeserializer<'de, E> for ContentRefDeserializer<'a, 'de, E>
+where
+ E: DeError,
+{
+ type Deserializer = Self;
+
+ fn into_deserializer(self) -> Self {
+ self
+ }
+}
diff --git a/third_party/rust/serde_with/src/content/mod.rs b/third_party/rust/serde_with/src/content/mod.rs
new file mode 100644
index 0000000000..f513cb7fff
--- /dev/null
+++ b/third_party/rust/serde_with/src/content/mod.rs
@@ -0,0 +1,8 @@
+//! Import of the unstable private `Content` type from `serde`.
+//!
+//! <https://github.com/serde-rs/serde/blob/55a7cedd737278a9d75a2efd038c6f38b8c38bd6/serde/src/private/ser.rs#L338-L997>
+
+#![cfg(not(tarpaulin_include))]
+
+pub(crate) mod de;
+pub(crate) mod ser;
diff --git a/third_party/rust/serde_with/src/content/ser.rs b/third_party/rust/serde_with/src/content/ser.rs
new file mode 100644
index 0000000000..c7570545a0
--- /dev/null
+++ b/third_party/rust/serde_with/src/content/ser.rs
@@ -0,0 +1,624 @@
+//! Buffer for serializing data.
+//!
+//! This is a copy and improvement of the `serde` private type:
+//! <https://github.com/serde-rs/serde/blob/55a7cedd737278a9d75a2efd038c6f38b8c38bd6/serde/src/private/ser.rs#L338-L997>
+//! The code is very stable in the `serde` crate, so no maintainability problem is expected.
+//!
+//! Since the type is private we copy the type here.
+//! `serde` is licensed as MIT+Apache2, the same as this crate.
+//!
+//! This version carries improvements compared to `serde`'s version.
+//! The types support 128-bit integers, which is supported for all targets in Rust 1.40+.
+//! The [`ContentSerializer`] can also be configured to human readable or compact representation.
+
+use crate::prelude::*;
+
+pub(crate) enum Content {
+ Bool(bool),
+
+ U8(u8),
+ U16(u16),
+ U32(u32),
+ U64(u64),
+ U128(u128),
+
+ I8(i8),
+ I16(i16),
+ I32(i32),
+ I64(i64),
+ I128(i128),
+
+ F32(f32),
+ F64(f64),
+
+ Char(char),
+ String(String),
+ Bytes(Vec<u8>),
+
+ None,
+ Some(Box<Content>),
+
+ Unit,
+ UnitStruct(&'static str),
+ UnitVariant(&'static str, u32, &'static str),
+ NewtypeStruct(&'static str, Box<Content>),
+ NewtypeVariant(&'static str, u32, &'static str, Box<Content>),
+
+ Seq(Vec<Content>),
+ Tuple(Vec<Content>),
+ TupleStruct(&'static str, Vec<Content>),
+ TupleVariant(&'static str, u32, &'static str, Vec<Content>),
+ Map(Vec<(Content, Content)>),
+ Struct(&'static str, Vec<(&'static str, Content)>),
+ StructVariant(
+ &'static str,
+ u32,
+ &'static str,
+ Vec<(&'static str, Content)>,
+ ),
+}
+
+impl Content {
+ pub(crate) fn as_str(&self) -> Option<&str> {
+ match self {
+ Self::String(ref x) => Some(x),
+ Self::Bytes(x) => core::str::from_utf8(x).ok(),
+ _ => None,
+ }
+ }
+}
+
+impl Serialize for Content {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ match *self {
+ Content::Bool(b) => serializer.serialize_bool(b),
+ Content::U8(u) => serializer.serialize_u8(u),
+ Content::U16(u) => serializer.serialize_u16(u),
+ Content::U32(u) => serializer.serialize_u32(u),
+ Content::U64(u) => serializer.serialize_u64(u),
+ Content::U128(u) => serializer.serialize_u128(u),
+ Content::I8(i) => serializer.serialize_i8(i),
+ Content::I16(i) => serializer.serialize_i16(i),
+ Content::I32(i) => serializer.serialize_i32(i),
+ Content::I64(i) => serializer.serialize_i64(i),
+ Content::I128(i) => serializer.serialize_i128(i),
+ Content::F32(f) => serializer.serialize_f32(f),
+ Content::F64(f) => serializer.serialize_f64(f),
+ Content::Char(c) => serializer.serialize_char(c),
+ Content::String(ref s) => serializer.serialize_str(s),
+ Content::Bytes(ref b) => serializer.serialize_bytes(b),
+ Content::None => serializer.serialize_none(),
+ Content::Some(ref c) => serializer.serialize_some(&**c),
+ Content::Unit => serializer.serialize_unit(),
+ Content::UnitStruct(n) => serializer.serialize_unit_struct(n),
+ Content::UnitVariant(n, i, v) => serializer.serialize_unit_variant(n, i, v),
+ Content::NewtypeStruct(n, ref c) => serializer.serialize_newtype_struct(n, &**c),
+ Content::NewtypeVariant(n, i, v, ref c) => {
+ serializer.serialize_newtype_variant(n, i, v, &**c)
+ }
+ Content::Seq(ref elements) => elements.serialize(serializer),
+ Content::Tuple(ref elements) => {
+ let mut tuple = serializer.serialize_tuple(elements.len())?;
+ for e in elements {
+ tuple.serialize_element(e)?;
+ }
+ tuple.end()
+ }
+ Content::TupleStruct(n, ref fields) => {
+ let mut ts = serializer.serialize_tuple_struct(n, fields.len())?;
+ for f in fields {
+ ts.serialize_field(f)?;
+ }
+ ts.end()
+ }
+ Content::TupleVariant(n, i, v, ref fields) => {
+ let mut tv = serializer.serialize_tuple_variant(n, i, v, fields.len())?;
+ for f in fields {
+ tv.serialize_field(f)?;
+ }
+ tv.end()
+ }
+ Content::Map(ref entries) => {
+ let mut map = serializer.serialize_map(Some(entries.len()))?;
+ for (k, v) in entries {
+ map.serialize_entry(k, v)?;
+ }
+ map.end()
+ }
+ Content::Struct(n, ref fields) => {
+ let mut s = serializer.serialize_struct(n, fields.len())?;
+ for (k, v) in fields {
+ s.serialize_field(k, v)?;
+ }
+ s.end()
+ }
+ Content::StructVariant(n, i, v, ref fields) => {
+ let mut sv = serializer.serialize_struct_variant(n, i, v, fields.len())?;
+ for (k, v) in fields {
+ sv.serialize_field(k, v)?;
+ }
+ sv.end()
+ }
+ }
+ }
+}
+
+pub(crate) struct ContentSerializer<E> {
+ is_human_readable: bool,
+ error: PhantomData<E>,
+}
+
+impl<E> ContentSerializer<E> {
+ pub(crate) fn new(is_human_readable: bool) -> Self {
+ ContentSerializer {
+ is_human_readable,
+ error: PhantomData,
+ }
+ }
+}
+
+impl<E> Default for ContentSerializer<E> {
+ fn default() -> Self {
+ Self::new(true)
+ }
+}
+
+impl<E> Serializer for ContentSerializer<E>
+where
+ E: SerError,
+{
+ type Ok = Content;
+ type Error = E;
+
+ type SerializeSeq = SeqSerialize<E>;
+ type SerializeTuple = TupleSerialize<E>;
+ type SerializeTupleStruct = TupleStructSerialize<E>;
+ type SerializeTupleVariant = TupleVariantSerialize<E>;
+ type SerializeMap = MapSerialize<E>;
+ type SerializeStruct = StructSerialize<E>;
+ type SerializeStructVariant = StructVariantSerialize<E>;
+
+ fn is_human_readable(&self) -> bool {
+ self.is_human_readable
+ }
+
+ fn serialize_bool(self, v: bool) -> Result<Content, E> {
+ Ok(Content::Bool(v))
+ }
+
+ fn serialize_i8(self, v: i8) -> Result<Content, E> {
+ Ok(Content::I8(v))
+ }
+
+ fn serialize_i16(self, v: i16) -> Result<Content, E> {
+ Ok(Content::I16(v))
+ }
+
+ fn serialize_i32(self, v: i32) -> Result<Content, E> {
+ Ok(Content::I32(v))
+ }
+
+ fn serialize_i64(self, v: i64) -> Result<Content, E> {
+ Ok(Content::I64(v))
+ }
+
+ fn serialize_i128(self, v: i128) -> Result<Content, E> {
+ Ok(Content::I128(v))
+ }
+
+ fn serialize_u8(self, v: u8) -> Result<Content, E> {
+ Ok(Content::U8(v))
+ }
+
+ fn serialize_u16(self, v: u16) -> Result<Content, E> {
+ Ok(Content::U16(v))
+ }
+
+ fn serialize_u32(self, v: u32) -> Result<Content, E> {
+ Ok(Content::U32(v))
+ }
+
+ fn serialize_u64(self, v: u64) -> Result<Content, E> {
+ Ok(Content::U64(v))
+ }
+
+ fn serialize_u128(self, v: u128) -> Result<Content, E> {
+ Ok(Content::U128(v))
+ }
+
+ fn serialize_f32(self, v: f32) -> Result<Content, E> {
+ Ok(Content::F32(v))
+ }
+
+ fn serialize_f64(self, v: f64) -> Result<Content, E> {
+ Ok(Content::F64(v))
+ }
+
+ fn serialize_char(self, v: char) -> Result<Content, E> {
+ Ok(Content::Char(v))
+ }
+
+ fn serialize_str(self, value: &str) -> Result<Content, E> {
+ Ok(Content::String(value.to_owned()))
+ }
+
+ fn serialize_bytes(self, value: &[u8]) -> Result<Content, E> {
+ Ok(Content::Bytes(value.to_owned()))
+ }
+
+ fn serialize_none(self) -> Result<Content, E> {
+ Ok(Content::None)
+ }
+
+ fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Content, E>
+ where
+ T: Serialize,
+ {
+ Ok(Content::Some(Box::new(value.serialize(self)?)))
+ }
+
+ fn serialize_unit(self) -> Result<Content, E> {
+ Ok(Content::Unit)
+ }
+
+ fn serialize_unit_struct(self, name: &'static str) -> Result<Content, E> {
+ Ok(Content::UnitStruct(name))
+ }
+
+ fn serialize_unit_variant(
+ self,
+ name: &'static str,
+ variant_index: u32,
+ variant: &'static str,
+ ) -> Result<Content, E> {
+ Ok(Content::UnitVariant(name, variant_index, variant))
+ }
+
+ fn serialize_newtype_struct<T: ?Sized>(
+ self,
+ name: &'static str,
+ value: &T,
+ ) -> Result<Content, E>
+ where
+ T: Serialize,
+ {
+ Ok(Content::NewtypeStruct(
+ name,
+ Box::new(value.serialize(self)?),
+ ))
+ }
+
+ fn serialize_newtype_variant<T: ?Sized>(
+ self,
+ name: &'static str,
+ variant_index: u32,
+ variant: &'static str,
+ value: &T,
+ ) -> Result<Content, E>
+ where
+ T: Serialize,
+ {
+ Ok(Content::NewtypeVariant(
+ name,
+ variant_index,
+ variant,
+ Box::new(value.serialize(self)?),
+ ))
+ }
+
+ fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, E> {
+ Ok(SeqSerialize {
+ is_human_readable: self.is_human_readable,
+ elements: Vec::with_capacity(len.unwrap_or(0)),
+ error: PhantomData,
+ })
+ }
+
+ fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, E> {
+ Ok(TupleSerialize {
+ is_human_readable: self.is_human_readable,
+ elements: Vec::with_capacity(len),
+ error: PhantomData,
+ })
+ }
+
+ fn serialize_tuple_struct(
+ self,
+ name: &'static str,
+ len: usize,
+ ) -> Result<Self::SerializeTupleStruct, E> {
+ Ok(TupleStructSerialize {
+ is_human_readable: self.is_human_readable,
+ name,
+ fields: Vec::with_capacity(len),
+ error: PhantomData,
+ })
+ }
+
+ fn serialize_tuple_variant(
+ self,
+ name: &'static str,
+ variant_index: u32,
+ variant: &'static str,
+ len: usize,
+ ) -> Result<Self::SerializeTupleVariant, E> {
+ Ok(TupleVariantSerialize {
+ is_human_readable: self.is_human_readable,
+ name,
+ variant_index,
+ variant,
+ fields: Vec::with_capacity(len),
+ error: PhantomData,
+ })
+ }
+
+ fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, E> {
+ Ok(MapSerialize {
+ is_human_readable: self.is_human_readable,
+ entries: Vec::with_capacity(len.unwrap_or(0)),
+ key: None,
+ error: PhantomData,
+ })
+ }
+
+ fn serialize_struct(self, name: &'static str, len: usize) -> Result<Self::SerializeStruct, E> {
+ Ok(StructSerialize {
+ is_human_readable: self.is_human_readable,
+ name,
+ fields: Vec::with_capacity(len),
+ error: PhantomData,
+ })
+ }
+
+ fn serialize_struct_variant(
+ self,
+ name: &'static str,
+ variant_index: u32,
+ variant: &'static str,
+ len: usize,
+ ) -> Result<Self::SerializeStructVariant, E> {
+ Ok(StructVariantSerialize {
+ is_human_readable: self.is_human_readable,
+ name,
+ variant_index,
+ variant,
+ fields: Vec::with_capacity(len),
+ error: PhantomData,
+ })
+ }
+}
+
+pub(crate) struct SeqSerialize<E> {
+ is_human_readable: bool,
+ elements: Vec<Content>,
+ error: PhantomData<E>,
+}
+
+impl<E> SerializeSeq for SeqSerialize<E>
+where
+ E: SerError,
+{
+ type Ok = Content;
+ type Error = E;
+
+ fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), E>
+ where
+ T: Serialize,
+ {
+ let value = value.serialize(ContentSerializer::<E>::new(self.is_human_readable))?;
+ self.elements.push(value);
+ Ok(())
+ }
+
+ fn end(self) -> Result<Content, E> {
+ Ok(Content::Seq(self.elements))
+ }
+}
+
+pub(crate) struct TupleSerialize<E> {
+ is_human_readable: bool,
+ elements: Vec<Content>,
+ error: PhantomData<E>,
+}
+
+impl<E> SerializeTuple for TupleSerialize<E>
+where
+ E: SerError,
+{
+ type Ok = Content;
+ type Error = E;
+
+ fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), E>
+ where
+ T: Serialize,
+ {
+ let value = value.serialize(ContentSerializer::<E>::new(self.is_human_readable))?;
+ self.elements.push(value);
+ Ok(())
+ }
+
+ fn end(self) -> Result<Content, E> {
+ Ok(Content::Tuple(self.elements))
+ }
+}
+
+pub(crate) struct TupleStructSerialize<E> {
+ is_human_readable: bool,
+ name: &'static str,
+ fields: Vec<Content>,
+ error: PhantomData<E>,
+}
+
+impl<E> SerializeTupleStruct for TupleStructSerialize<E>
+where
+ E: SerError,
+{
+ type Ok = Content;
+ type Error = E;
+
+ fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), E>
+ where
+ T: Serialize,
+ {
+ let value = value.serialize(ContentSerializer::<E>::new(self.is_human_readable))?;
+ self.fields.push(value);
+ Ok(())
+ }
+
+ fn end(self) -> Result<Content, E> {
+ Ok(Content::TupleStruct(self.name, self.fields))
+ }
+}
+
+pub(crate) struct TupleVariantSerialize<E> {
+ is_human_readable: bool,
+ name: &'static str,
+ variant_index: u32,
+ variant: &'static str,
+ fields: Vec<Content>,
+ error: PhantomData<E>,
+}
+
+impl<E> SerializeTupleVariant for TupleVariantSerialize<E>
+where
+ E: SerError,
+{
+ type Ok = Content;
+ type Error = E;
+
+ fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), E>
+ where
+ T: Serialize,
+ {
+ let value = value.serialize(ContentSerializer::<E>::new(self.is_human_readable))?;
+ self.fields.push(value);
+ Ok(())
+ }
+
+ fn end(self) -> Result<Content, E> {
+ Ok(Content::TupleVariant(
+ self.name,
+ self.variant_index,
+ self.variant,
+ self.fields,
+ ))
+ }
+}
+
+pub(crate) struct MapSerialize<E> {
+ is_human_readable: bool,
+ entries: Vec<(Content, Content)>,
+ key: Option<Content>,
+ error: PhantomData<E>,
+}
+
+impl<E> SerializeMap for MapSerialize<E>
+where
+ E: SerError,
+{
+ type Ok = Content;
+ type Error = E;
+
+ fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), E>
+ where
+ T: Serialize,
+ {
+ let key = key.serialize(ContentSerializer::<E>::new(self.is_human_readable))?;
+ self.key = Some(key);
+ Ok(())
+ }
+
+ fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), E>
+ where
+ T: Serialize,
+ {
+ let key = self
+ .key
+ .take()
+ .expect("serialize_value called before serialize_key");
+ let value = value.serialize(ContentSerializer::<E>::new(self.is_human_readable))?;
+ self.entries.push((key, value));
+ Ok(())
+ }
+
+ fn end(self) -> Result<Content, E> {
+ Ok(Content::Map(self.entries))
+ }
+
+ fn serialize_entry<K: ?Sized, V: ?Sized>(&mut self, key: &K, value: &V) -> Result<(), E>
+ where
+ K: Serialize,
+ V: Serialize,
+ {
+ let key = key.serialize(ContentSerializer::<E>::new(self.is_human_readable))?;
+ let value = value.serialize(ContentSerializer::<E>::new(self.is_human_readable))?;
+ self.entries.push((key, value));
+ Ok(())
+ }
+}
+
+pub(crate) struct StructSerialize<E> {
+ is_human_readable: bool,
+ name: &'static str,
+ fields: Vec<(&'static str, Content)>,
+ error: PhantomData<E>,
+}
+
+impl<E> SerializeStruct for StructSerialize<E>
+where
+ E: SerError,
+{
+ type Ok = Content;
+ type Error = E;
+
+ fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), E>
+ where
+ T: Serialize,
+ {
+ let value = value.serialize(ContentSerializer::<E>::new(self.is_human_readable))?;
+ self.fields.push((key, value));
+ Ok(())
+ }
+
+ fn end(self) -> Result<Content, E> {
+ Ok(Content::Struct(self.name, self.fields))
+ }
+}
+
+pub(crate) struct StructVariantSerialize<E> {
+ is_human_readable: bool,
+ name: &'static str,
+ variant_index: u32,
+ variant: &'static str,
+ fields: Vec<(&'static str, Content)>,
+ error: PhantomData<E>,
+}
+
+impl<E> SerializeStructVariant for StructVariantSerialize<E>
+where
+ E: SerError,
+{
+ type Ok = Content;
+ type Error = E;
+
+ fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), E>
+ where
+ T: Serialize,
+ {
+ let value = value.serialize(ContentSerializer::<E>::new(self.is_human_readable))?;
+ self.fields.push((key, value));
+ Ok(())
+ }
+
+ fn end(self) -> Result<Content, E> {
+ Ok(Content::StructVariant(
+ self.name,
+ self.variant_index,
+ self.variant,
+ self.fields,
+ ))
+ }
+}
diff --git a/third_party/rust/serde_with/src/de/duplicates.rs b/third_party/rust/serde_with/src/de/duplicates.rs
new file mode 100644
index 0000000000..a03dfba2f5
--- /dev/null
+++ b/third_party/rust/serde_with/src/de/duplicates.rs
@@ -0,0 +1,223 @@
+use super::impls::{foreach_map_create, foreach_set_create};
+use crate::{
+ duplicate_key_impls::{
+ DuplicateInsertsFirstWinsMap, DuplicateInsertsLastWinsSet, PreventDuplicateInsertsMap,
+ PreventDuplicateInsertsSet,
+ },
+ prelude::*,
+ MapFirstKeyWins, MapPreventDuplicates, SetLastValueWins, SetPreventDuplicates,
+};
+#[cfg(feature = "indexmap_1")]
+use indexmap_1::{IndexMap, IndexSet};
+
+struct SetPreventDuplicatesVisitor<SET, T, TAs>(PhantomData<(SET, T, TAs)>);
+
+impl<'de, SET, T, TAs> Visitor<'de> for SetPreventDuplicatesVisitor<SET, T, TAs>
+where
+ SET: PreventDuplicateInsertsSet<T>,
+ TAs: DeserializeAs<'de, T>,
+{
+ type Value = SET;
+
+ 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::<DeserializeAsWrap<T, TAs>>()? {
+ if !values.insert(value.into_inner()) {
+ return Err(DeError::custom("invalid entry: found duplicate value"));
+ };
+ }
+
+ Ok(values)
+ }
+}
+
+struct SetLastValueWinsVisitor<SET, T, TAs>(PhantomData<(SET, T, TAs)>);
+
+impl<'de, SET, T, TAs> Visitor<'de> for SetLastValueWinsVisitor<SET, T, TAs>
+where
+ SET: DuplicateInsertsLastWinsSet<T>,
+ TAs: DeserializeAs<'de, T>,
+{
+ type Value = SET;
+
+ 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::<DeserializeAsWrap<T, TAs>>()? {
+ values.replace(value.into_inner());
+ }
+
+ Ok(values)
+ }
+}
+
+#[cfg(feature = "alloc")]
+macro_rules! set_impl {
+ (
+ $ty:ident < T $(: $tbound1:ident $(+ $tbound2:ident)*)* $(, $typaram:ident : $bound1:ident $(+ $bound2:ident)* )* >,
+ $with_capacity:expr,
+ $append:ident
+ ) => {
+ impl<'de, T, TAs $(, $typaram)*> DeserializeAs<'de, $ty<T $(, $typaram)*>> for SetPreventDuplicates<TAs>
+ where
+ TAs: DeserializeAs<'de, T>,
+ $(T: $tbound1 $(+ $tbound2)*,)*
+ $($typaram: $bound1 $(+ $bound2)*),*
+ {
+ fn deserialize_as<D>(deserializer: D) -> Result<$ty<T $(, $typaram)*>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ deserializer.deserialize_seq(SetPreventDuplicatesVisitor::<$ty<T $(, $typaram)*>, T, TAs>(
+ PhantomData,
+ ))
+ }
+ }
+
+ impl<'de, T, TAs $(, $typaram)*> DeserializeAs<'de, $ty<T $(, $typaram)*>> for SetLastValueWins<TAs>
+ where
+ TAs: DeserializeAs<'de, T>,
+ $(T: $tbound1 $(+ $tbound2)*,)*
+ $($typaram: $bound1 $(+ $bound2)*),*
+ {
+ fn deserialize_as<D>(deserializer: D) -> Result<$ty<T $(, $typaram)*>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ deserializer
+ .deserialize_seq(SetLastValueWinsVisitor::<$ty<T $(, $typaram)*>, T, TAs>(PhantomData))
+ }
+ }
+ }
+}
+foreach_set_create!(set_impl);
+
+struct MapPreventDuplicatesVisitor<MAP, K, KAs, V, VAs>(PhantomData<(MAP, K, KAs, V, VAs)>);
+
+impl<'de, MAP, K, KAs, V, VAs> Visitor<'de> for MapPreventDuplicatesVisitor<MAP, K, KAs, V, VAs>
+where
+ MAP: PreventDuplicateInsertsMap<K, V>,
+ KAs: DeserializeAs<'de, K>,
+ VAs: DeserializeAs<'de, V>,
+{
+ type Value = MAP;
+
+ 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::<DeserializeAsWrap<K, KAs>, DeserializeAsWrap<V, VAs>>()?
+ {
+ if !values.insert(key.into_inner(), value.into_inner()) {
+ return Err(DeError::custom("invalid entry: found duplicate key"));
+ };
+ }
+
+ Ok(values)
+ }
+}
+
+struct MapFirstKeyWinsVisitor<MAP, K, KAs, V, VAs>(PhantomData<(MAP, K, KAs, V, VAs)>);
+
+impl<'de, MAP, K, KAs, V, VAs> Visitor<'de> for MapFirstKeyWinsVisitor<MAP, K, KAs, V, VAs>
+where
+ MAP: DuplicateInsertsFirstWinsMap<K, V>,
+ KAs: DeserializeAs<'de, K>,
+ VAs: DeserializeAs<'de, V>,
+{
+ type Value = MAP;
+
+ 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::<DeserializeAsWrap<K, KAs>, DeserializeAsWrap<V, VAs>>()?
+ {
+ values.insert(key.into_inner(), value.into_inner());
+ }
+
+ Ok(values)
+ }
+}
+
+#[cfg(feature = "alloc")]
+macro_rules! map_impl {
+ (
+ $ty:ident < K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound1:ident $(+ $bound2:ident)*)* >,
+ $with_capacity:expr
+ ) => {
+ impl<'de, K, V, KAs, VAs $(, $typaram)*> DeserializeAs<'de, $ty<K, V $(, $typaram)*>>
+ for MapPreventDuplicates<KAs, VAs>
+ where
+ KAs: DeserializeAs<'de, K>,
+ VAs: DeserializeAs<'de, V>,
+ $(K: $kbound1 $(+ $kbound2)*,)*
+ $($typaram: $bound1 $(+ $bound2)*),*
+ {
+ fn deserialize_as<D>(deserializer: D) -> Result<$ty<K, V $(, $typaram)*>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ deserializer.deserialize_map(MapPreventDuplicatesVisitor::<
+ $ty<K, V $(, $typaram)*>,
+ K,
+ KAs,
+ V,
+ VAs,
+ >(PhantomData))
+ }
+ }
+
+ impl<'de, K, V, KAs, VAs $(, $typaram)*> DeserializeAs<'de, $ty<K, V $(, $typaram)*>>
+ for MapFirstKeyWins<KAs, VAs>
+ where
+ KAs: DeserializeAs<'de, K>,
+ VAs: DeserializeAs<'de, V>,
+ $(K: $kbound1 $(+ $kbound2)*,)*
+ $($typaram: $bound1 $(+ $bound2)*),*
+ {
+ fn deserialize_as<D>(deserializer: D) -> Result<$ty<K, V $(, $typaram)*>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ deserializer.deserialize_map(MapFirstKeyWinsVisitor::<$ty<K, V $(, $typaram)*>, K, KAs, V, VAs>(
+ PhantomData,
+ ))
+ }
+ }
+ };
+}
+foreach_map_create!(map_impl);
diff --git a/third_party/rust/serde_with/src/de/impls.rs b/third_party/rust/serde_with/src/de/impls.rs
new file mode 100644
index 0000000000..066ad57490
--- /dev/null
+++ b/third_party/rust/serde_with/src/de/impls.rs
@@ -0,0 +1,1937 @@
+use crate::{formats::*, prelude::*};
+#[cfg(feature = "indexmap_1")]
+use indexmap_1::{IndexMap, IndexSet};
+
+///////////////////////////////////////////////////////////////////////////////
+// Helper macro used internally
+
+#[cfg(feature = "alloc")]
+type BoxedSlice<T> = Box<[T]>;
+
+macro_rules! foreach_map {
+ ($m:ident) => {
+ #[cfg(feature = "alloc")]
+ $m!(BTreeMap<K: Ord, V>);
+ #[cfg(feature = "std")]
+ $m!(HashMap<K: Eq + Hash, V, H: Sized>);
+ #[cfg(all(feature = "std", feature = "indexmap_1"))]
+ $m!(IndexMap<K: Eq + Hash, V, H: Sized>);
+ };
+}
+pub(crate) use foreach_map;
+
+macro_rules! foreach_map_create {
+ ($m:ident) => {
+ #[cfg(feature = "alloc")]
+ $m!(BTreeMap<K: Ord, V>,
+ (|_size| BTreeMap::new()));
+ #[cfg(feature = "std")]
+ $m!(HashMap<K: Eq + Hash, V, S: BuildHasher + Default>,
+ (|size| HashMap::with_capacity_and_hasher(size, Default::default())));
+ #[cfg(feature = "indexmap_1")]
+ $m!(IndexMap<K: Eq + Hash, V, S: BuildHasher + Default>,
+ (|size| IndexMap::with_capacity_and_hasher(size, Default::default())));
+ }
+}
+pub(crate) use foreach_map_create;
+
+macro_rules! foreach_set {
+ ($m:ident) => {
+ #[cfg(feature = "alloc")]
+ $m!(BTreeSet<(K, V): Ord>);
+ #[cfg(feature = "std")]
+ $m!(HashSet<(K, V): Eq + Hash>);
+ #[cfg(all(feature = "std", feature = "indexmap_1"))]
+ $m!(IndexSet<(K, V): Eq + Hash>);
+ }
+}
+pub(crate) use foreach_set;
+
+macro_rules! foreach_set_create {
+ ($m:ident) => {
+ #[cfg(feature = "alloc")]
+ $m!(BTreeSet<T: Ord>, (|_| BTreeSet::new()), insert);
+ #[cfg(feature = "std")]
+ $m!(
+ HashSet<T: Eq + Hash, S: BuildHasher + Default>,
+ (|size| HashSet::with_capacity_and_hasher(size, S::default())),
+ insert
+ );
+ #[cfg(feature = "indexmap_1")]
+ $m!(
+ IndexSet<T: Eq + Hash, S: BuildHasher + Default>,
+ (|size| IndexSet::with_capacity_and_hasher(size, S::default())),
+ insert
+ );
+ }
+}
+pub(crate) use foreach_set_create;
+
+macro_rules! foreach_seq {
+ ($m:ident) => {
+ foreach_set!($m);
+
+ #[cfg(feature = "alloc")]
+ $m!(BinaryHeap<(K, V): Ord>);
+ #[cfg(feature = "alloc")]
+ $m!(LinkedList<(K, V)>);
+ #[cfg(feature = "alloc")]
+ $m!(Vec<(K, V)>);
+ #[cfg(feature = "alloc")]
+ $m!(VecDeque<(K, V)>);
+ }
+}
+pub(crate) use foreach_seq;
+
+macro_rules! foreach_seq_create {
+ ($m:ident) => {
+ foreach_set_create!($m);
+
+ #[cfg(feature = "alloc")]
+ $m!(
+ BinaryHeap<T: Ord>,
+ (|size| BinaryHeap::with_capacity(size)),
+ push
+ );
+ #[cfg(feature = "alloc")]
+ $m!(BoxedSlice<T>, (|size| Vec::with_capacity(size)), push);
+ #[cfg(feature = "alloc")]
+ $m!(LinkedList<T>, (|_| LinkedList::new()), push_back);
+ #[cfg(feature = "alloc")]
+ $m!(Vec<T>, (|size| Vec::with_capacity(size)), push);
+ #[cfg(feature = "alloc")]
+ $m!(
+ VecDeque<T>,
+ (|size| VecDeque::with_capacity(size)),
+ push_back
+ );
+ };
+}
+pub(crate) use foreach_seq_create;
+
+///////////////////////////////////////////////////////////////////////////////
+// region: Simple Wrapper types (e.g., Box, Option)
+
+#[cfg(feature = "alloc")]
+impl<'de, T, U> DeserializeAs<'de, Box<T>> for Box<U>
+where
+ U: DeserializeAs<'de, T>,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<Box<T>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ Ok(Box::new(
+ DeserializeAsWrap::<T, U>::deserialize(deserializer)?.into_inner(),
+ ))
+ }
+}
+
+impl<'de, T, U> DeserializeAs<'de, Option<T>> for Option<U>
+where
+ U: DeserializeAs<'de, T>,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<Option<T>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct OptionVisitor<T, U>(PhantomData<(T, U)>);
+
+ impl<'de, T, U> Visitor<'de> for OptionVisitor<T, U>
+ where
+ U: DeserializeAs<'de, T>,
+ {
+ type Value = Option<T>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("option")
+ }
+
+ #[inline]
+ fn visit_unit<E>(self) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(None)
+ }
+
+ #[inline]
+ fn visit_none<E>(self) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(None)
+ }
+
+ #[inline]
+ fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ U::deserialize_as(deserializer).map(Some)
+ }
+ }
+
+ deserializer.deserialize_option(OptionVisitor::<T, U>(PhantomData))
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'de, T, U> DeserializeAs<'de, Rc<T>> for Rc<U>
+where
+ U: DeserializeAs<'de, T>,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<Rc<T>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ Ok(Rc::new(
+ DeserializeAsWrap::<T, U>::deserialize(deserializer)?.into_inner(),
+ ))
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'de, T, U> DeserializeAs<'de, RcWeak<T>> for RcWeak<U>
+where
+ U: DeserializeAs<'de, T>,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<RcWeak<T>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ DeserializeAsWrap::<Option<Rc<T>>, Option<Rc<U>>>::deserialize(deserializer)?;
+ Ok(RcWeak::new())
+ }
+}
+
+#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
+impl<'de, T, U> DeserializeAs<'de, Arc<T>> for Arc<U>
+where
+ U: DeserializeAs<'de, T>,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<Arc<T>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ Ok(Arc::new(
+ DeserializeAsWrap::<T, U>::deserialize(deserializer)?.into_inner(),
+ ))
+ }
+}
+
+#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
+impl<'de, T, U> DeserializeAs<'de, ArcWeak<T>> for ArcWeak<U>
+where
+ U: DeserializeAs<'de, T>,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<ArcWeak<T>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ DeserializeAsWrap::<Option<Arc<T>>, Option<Arc<U>>>::deserialize(deserializer)?;
+ Ok(ArcWeak::new())
+ }
+}
+
+impl<'de, T, U> DeserializeAs<'de, Cell<T>> for Cell<U>
+where
+ U: DeserializeAs<'de, T>,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<Cell<T>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ Ok(Cell::new(
+ DeserializeAsWrap::<T, U>::deserialize(deserializer)?.into_inner(),
+ ))
+ }
+}
+
+impl<'de, T, U> DeserializeAs<'de, RefCell<T>> for RefCell<U>
+where
+ U: DeserializeAs<'de, T>,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<RefCell<T>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ Ok(RefCell::new(
+ DeserializeAsWrap::<T, U>::deserialize(deserializer)?.into_inner(),
+ ))
+ }
+}
+
+#[cfg(feature = "std")]
+impl<'de, T, U> DeserializeAs<'de, Mutex<T>> for Mutex<U>
+where
+ U: DeserializeAs<'de, T>,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<Mutex<T>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ Ok(Mutex::new(
+ DeserializeAsWrap::<T, U>::deserialize(deserializer)?.into_inner(),
+ ))
+ }
+}
+
+#[cfg(feature = "std")]
+impl<'de, T, U> DeserializeAs<'de, RwLock<T>> for RwLock<U>
+where
+ U: DeserializeAs<'de, T>,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<RwLock<T>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ Ok(RwLock::new(
+ DeserializeAsWrap::<T, U>::deserialize(deserializer)?.into_inner(),
+ ))
+ }
+}
+
+impl<'de, T, TAs, E, EAs> DeserializeAs<'de, Result<T, E>> for Result<TAs, EAs>
+where
+ TAs: DeserializeAs<'de, T>,
+ EAs: DeserializeAs<'de, E>,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<Result<T, E>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ Ok(
+ match Result::<DeserializeAsWrap<T, TAs>, DeserializeAsWrap<E, EAs>>::deserialize(
+ deserializer,
+ )? {
+ Ok(value) => Ok(value.into_inner()),
+ Err(err) => Err(err.into_inner()),
+ },
+ )
+ }
+}
+
+impl<'de, T, As, const N: usize> DeserializeAs<'de, [T; N]> for [As; N]
+where
+ As: DeserializeAs<'de, T>,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<[T; N], D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct ArrayVisitor<T, const M: usize>(PhantomData<T>);
+
+ impl<'de, T, As, const M: usize> Visitor<'de> for ArrayVisitor<DeserializeAsWrap<T, As>, M>
+ where
+ As: DeserializeAs<'de, T>,
+ {
+ type Value = [T; M];
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_fmt(format_args!("an array of size {M}"))
+ }
+
+ fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
+ where
+ A: SeqAccess<'de>,
+ {
+ utils::array_from_iterator(
+ utils::SeqIter::new(seq).map(
+ |res: Result<DeserializeAsWrap<T, As>, A::Error>| {
+ res.map(|t| t.into_inner())
+ },
+ ),
+ &self,
+ )
+ }
+ }
+
+ deserializer.deserialize_tuple(N, ArrayVisitor::<DeserializeAsWrap<T, As>, N>(PhantomData))
+ }
+}
+
+// endregion
+///////////////////////////////////////////////////////////////////////////////
+// region: Collection Types (e.g., Maps, Sets, Vec)
+
+#[cfg(feature = "alloc")]
+macro_rules! seq_impl {
+ (
+ $ty:ident < T $(: $tbound1:ident $(+ $tbound2:ident)*)* $(, $typaram:ident : $bound1:ident $(+ $bound2:ident)* )* >,
+ $with_capacity:expr,
+ $append:ident
+ ) => {
+ // Fix for clippy regression in macros on stable
+ // The bug no longer exists on nightly
+ // https://github.com/rust-lang/rust-clippy/issues/7768
+ #[allow(clippy::semicolon_if_nothing_returned)]
+ impl<'de, T, U $(, $typaram)*> DeserializeAs<'de, $ty<T $(, $typaram)*>> for $ty<U $(, $typaram)*>
+ where
+ U: DeserializeAs<'de, T>,
+ $(T: $tbound1 $(+ $tbound2)*,)*
+ $($typaram: $bound1 $(+ $bound2)*),*
+ {
+ fn deserialize_as<D>(deserializer: D) -> Result<$ty<T $(, $typaram)*>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct SeqVisitor<T, U $(, $typaram)*> {
+ marker: PhantomData<(T, U $(, $typaram)*)>,
+ }
+
+ impl<'de, T, U $(, $typaram)*> Visitor<'de> for SeqVisitor<T, U $(, $typaram)*>
+ where
+ U: DeserializeAs<'de, T>,
+ $(T: $tbound1 $(+ $tbound2)*,)*
+ $($typaram: $bound1 $(+ $bound2)*),*
+ {
+ type Value = $ty<T $(, $typaram)*>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a sequence")
+ }
+
+ fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
+ where
+ A: SeqAccess<'de>,
+ {
+ let mut values = ($with_capacity)(utils::size_hint_cautious(seq.size_hint()));
+
+ while let Some(value) = seq
+ .next_element()?
+ .map(|v: DeserializeAsWrap<T, U>| v.into_inner())
+ {
+ values.$append(value);
+ }
+
+ Ok(values.into())
+ }
+ }
+
+ let visitor = SeqVisitor::<T, U $(, $typaram)*> {
+ marker: PhantomData,
+ };
+ deserializer.deserialize_seq(visitor)
+ }
+ }
+ };
+}
+foreach_seq_create!(seq_impl);
+
+#[cfg(feature = "alloc")]
+macro_rules! map_impl {
+ (
+ $ty:ident < K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound1:ident $(+ $bound2:ident)*)* >,
+ $with_capacity:expr
+ ) => {
+ // Fix for clippy regression in macros on stable
+ // The bug no longer exists on nightly
+ // https://github.com/rust-lang/rust-clippy/issues/7768
+ #[allow(clippy::semicolon_if_nothing_returned)]
+ impl<'de, K, V, KU, VU $(, $typaram)*> DeserializeAs<'de, $ty<K, V $(, $typaram)*>> for $ty<KU, VU $(, $typaram)*>
+ where
+ KU: DeserializeAs<'de, K>,
+ VU: DeserializeAs<'de, V>,
+ $(K: $kbound1 $(+ $kbound2)*,)*
+ $($typaram: $bound1 $(+ $bound2)*),*
+ {
+ fn deserialize_as<D>(deserializer: D) -> Result<$ty<K, V $(, $typaram)*>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct MapVisitor<K, V, KU, VU $(, $typaram)*>(PhantomData<(K, V, KU, VU $(, $typaram)*)>);
+
+ impl<'de, K, V, KU, VU $(, $typaram)*> Visitor<'de> for MapVisitor<K, V, KU, VU $(, $typaram)*>
+ where
+ KU: DeserializeAs<'de, K>,
+ VU: DeserializeAs<'de, V>,
+ $(K: $kbound1 $(+ $kbound2)*,)*
+ $($typaram: $bound1 $(+ $bound2)*),*
+ {
+ type Value = $ty<K, V $(, $typaram)*>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a map")
+ }
+
+ #[inline]
+ fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
+ where
+ A: MapAccess<'de>,
+ {
+ let mut values = ($with_capacity)(utils::size_hint_cautious(map.size_hint()));
+
+ while let Some((key, value)) = (map.next_entry())?.map(|(k, v): (DeserializeAsWrap::<K, KU>, DeserializeAsWrap::<V, VU>)| (k.into_inner(), v.into_inner())) {
+ values.insert(key, value);
+ }
+
+ Ok(values)
+ }
+ }
+
+ let visitor = MapVisitor::<K, V, KU, VU $(, $typaram)*> (PhantomData);
+ deserializer.deserialize_map(visitor)
+ }
+ }
+ }
+}
+foreach_map_create!(map_impl);
+
+macro_rules! tuple_impl {
+ ($len:literal $($n:tt $t:ident $tas:ident)+) => {
+ impl<'de, $($t, $tas,)+> DeserializeAs<'de, ($($t,)+)> for ($($tas,)+)
+ where
+ $($tas: DeserializeAs<'de, $t>,)+
+ {
+ fn deserialize_as<D>(deserializer: D) -> Result<($($t,)+), D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct TupleVisitor<$($t,)+>(PhantomData<($($t,)+)>);
+
+ impl<'de, $($t, $tas,)+> Visitor<'de>
+ for TupleVisitor<$(DeserializeAsWrap<$t, $tas>,)+>
+ where
+ $($tas: DeserializeAs<'de, $t>,)+
+ {
+ type Value = ($($t,)+);
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str(concat!("a tuple of size ", $len))
+ }
+
+ #[allow(non_snake_case)]
+ fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
+ where
+ A: SeqAccess<'de>,
+ {
+ $(
+ let $t: DeserializeAsWrap<$t, $tas> = match seq.next_element()? {
+ Some(value) => value,
+ None => return Err(DeError::invalid_length($n, &self)),
+ };
+ )+
+
+ Ok(($($t.into_inner(),)+))
+ }
+ }
+
+ deserializer.deserialize_tuple(
+ $len,
+ TupleVisitor::<$(DeserializeAsWrap<$t, $tas>,)+>(PhantomData),
+ )
+ }
+ }
+ };
+}
+
+tuple_impl!(1 0 T0 As0);
+tuple_impl!(2 0 T0 As0 1 T1 As1);
+tuple_impl!(3 0 T0 As0 1 T1 As1 2 T2 As2);
+tuple_impl!(4 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3);
+tuple_impl!(5 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4);
+tuple_impl!(6 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5);
+tuple_impl!(7 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6);
+tuple_impl!(8 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7);
+tuple_impl!(9 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7 8 T8 As8);
+tuple_impl!(10 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7 8 T8 As8 9 T9 As9);
+tuple_impl!(11 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7 8 T8 As8 9 T9 As9 10 T10 As10);
+tuple_impl!(12 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7 8 T8 As8 9 T9 As9 10 T10 As10 11 T11 As11);
+tuple_impl!(13 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7 8 T8 As8 9 T9 As9 10 T10 As10 11 T11 As11 12 T12 As12);
+tuple_impl!(14 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7 8 T8 As8 9 T9 As9 10 T10 As10 11 T11 As11 12 T12 As12 13 T13 As13);
+tuple_impl!(15 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7 8 T8 As8 9 T9 As9 10 T10 As10 11 T11 As11 12 T12 As12 13 T13 As13 14 T14 As14);
+tuple_impl!(16 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7 8 T8 As8 9 T9 As9 10 T10 As10 11 T11 As11 12 T12 As12 13 T13 As13 14 T14 As14 15 T15 As15);
+
+#[cfg(feature = "alloc")]
+macro_rules! map_as_tuple_seq_intern {
+ ($tyorig:ident < K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound1:ident $(+ $bound2:ident)*)* >, $ty:ident <(KAs, VAs)>) => {
+ impl<'de, K, KAs, V, VAs> DeserializeAs<'de, $tyorig<K, V>> for $ty<(KAs, VAs)>
+ where
+ KAs: DeserializeAs<'de, K>,
+ VAs: DeserializeAs<'de, V>,
+ $(K: $kbound1 $(+ $kbound2)*,)*
+ {
+ fn deserialize_as<D>(deserializer: D) -> Result<$tyorig<K, V>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct SeqVisitor<K, KAs, V, VAs> {
+ marker: PhantomData<(K, KAs, V, VAs)>,
+ }
+
+ impl<'de, K, KAs, V, VAs> Visitor<'de> for SeqVisitor<K, KAs, V, VAs>
+ where
+ KAs: DeserializeAs<'de, K>,
+ VAs: DeserializeAs<'de, V>,
+ $(K: $kbound1 $(+ $kbound2)*,)*
+ {
+ type Value = $tyorig<K, V>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a sequence")
+ }
+
+ #[inline]
+ fn visit_seq<A>(self, access: A) -> Result<Self::Value, A::Error>
+ where
+ A: SeqAccess<'de>,
+ {
+ let iter = utils::SeqIter::new(access);
+ iter.map(|res| {
+ res.map(
+ |(k, v): (DeserializeAsWrap<K, KAs>, DeserializeAsWrap<V, VAs>)| {
+ (k.into_inner(), v.into_inner())
+ },
+ )
+ })
+ .collect()
+ }
+ }
+
+ let visitor = SeqVisitor::<K, KAs, V, VAs> {
+ marker: PhantomData,
+ };
+ deserializer.deserialize_seq(visitor)
+ }
+ }
+ };
+}
+#[cfg(feature = "alloc")]
+macro_rules! map_as_tuple_seq {
+ ($tyorig:ident < K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound1:ident $(+ $bound2:ident)*)* >) => {
+ map_as_tuple_seq_intern!($tyorig < K $(: $kbound1 $(+ $kbound2)*)* , V $(, $typaram : $bound1 $(+ $bound2)*)* > , Seq<(KAs, VAs)>);
+ #[cfg(feature = "alloc")]
+ map_as_tuple_seq_intern!($tyorig < K $(: $kbound1 $(+ $kbound2)*)* , V $(, $typaram : $bound1 $(+ $bound2)*)* >, Vec<(KAs, VAs)>);
+ }
+}
+foreach_map!(map_as_tuple_seq);
+
+#[cfg(feature = "alloc")]
+macro_rules! tuple_seq_as_map_impl_intern {
+ ($tyorig:ident < (K, V) $(: $($bound:ident $(+)?)+)?>, $ty:ident <KAs, VAs>) => {
+ #[allow(clippy::implicit_hasher)]
+ impl<'de, K, KAs, V, VAs> DeserializeAs<'de, $tyorig < (K, V) >> for $ty<KAs, VAs>
+ where
+ KAs: DeserializeAs<'de, K>,
+ VAs: DeserializeAs<'de, V>,
+ (K, V): $($($bound +)*)*,
+ {
+ fn deserialize_as<D>(deserializer: D) -> Result<$tyorig < (K, V) >, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct MapVisitor<K, KAs, V, VAs> {
+ marker: PhantomData<(K, KAs, V, VAs)>,
+ }
+
+ impl<'de, K, KAs, V, VAs> Visitor<'de> for MapVisitor<K, KAs, V, VAs>
+ where
+ KAs: DeserializeAs<'de, K>,
+ VAs: DeserializeAs<'de, V>,
+ (K, V): $($($bound +)*)*,
+ {
+ type Value = $tyorig < (K, V) >;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a map")
+ }
+
+ #[inline]
+ fn visit_map<A>(self, access: A) -> Result<Self::Value, A::Error>
+ where
+ A: MapAccess<'de>,
+ {
+ let iter = utils::MapIter::new(access);
+ iter.map(|res| {
+ res.map(
+ |(k, v): (DeserializeAsWrap<K, KAs>, DeserializeAsWrap<V, VAs>)| {
+ (k.into_inner(), v.into_inner())
+ },
+ )
+ })
+ .collect()
+ }
+ }
+
+ let visitor = MapVisitor::<K, KAs, V, VAs> {
+ marker: PhantomData,
+ };
+ deserializer.deserialize_map(visitor)
+ }
+ }
+ }
+}
+#[cfg(feature = "alloc")]
+macro_rules! tuple_seq_as_map_impl {
+ ($tyorig:ident < (K, V) $(: $($bound:ident $(+)?)+)?>) => {
+ tuple_seq_as_map_impl_intern!($tyorig < (K, V) $(: $($bound +)+)? >, Map<KAs, VAs>);
+ #[cfg(feature = "alloc")]
+ tuple_seq_as_map_impl_intern!($tyorig < (K, V) $(: $($bound +)+)? >, BTreeMap<KAs, VAs>);
+ #[cfg(feature = "std")]
+ tuple_seq_as_map_impl_intern!($tyorig < (K, V) $(: $($bound +)+)? >, HashMap<KAs, VAs>);
+ }
+}
+foreach_seq!(tuple_seq_as_map_impl);
+
+// Option does not implement FromIterator directly, so we need a different implementation
+#[cfg(feature = "alloc")]
+macro_rules! tuple_seq_as_map_option_impl {
+ ($ty:ident) => {
+ #[allow(clippy::implicit_hasher)]
+ impl<'de, K, KAs, V, VAs> DeserializeAs<'de, Option<(K, V)>> for $ty<KAs, VAs>
+ where
+ KAs: DeserializeAs<'de, K>,
+ VAs: DeserializeAs<'de, V>,
+ {
+ fn deserialize_as<D>(deserializer: D) -> Result<Option<(K, V)>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct MapVisitor<K, KAs, V, VAs> {
+ marker: PhantomData<(K, KAs, V, VAs)>,
+ }
+
+ impl<'de, K, KAs, V, VAs> Visitor<'de> for MapVisitor<K, KAs, V, VAs>
+ where
+ KAs: DeserializeAs<'de, K>,
+ VAs: DeserializeAs<'de, V>,
+ {
+ type Value = Option<(K, V)>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a map of size 1")
+ }
+
+ #[inline]
+ fn visit_map<A>(self, access: A) -> Result<Self::Value, A::Error>
+ where
+ A: MapAccess<'de>,
+ {
+ let iter = utils::MapIter::new(access);
+ iter.map(|res| {
+ res.map(
+ |(k, v): (DeserializeAsWrap<K, KAs>, DeserializeAsWrap<V, VAs>)| {
+ (k.into_inner(), v.into_inner())
+ },
+ )
+ })
+ .next()
+ .transpose()
+ }
+ }
+
+ let visitor = MapVisitor::<K, KAs, V, VAs> {
+ marker: PhantomData,
+ };
+ deserializer.deserialize_map(visitor)
+ }
+ }
+ };
+}
+#[cfg(feature = "alloc")]
+tuple_seq_as_map_option_impl!(BTreeMap);
+#[cfg(feature = "std")]
+tuple_seq_as_map_option_impl!(HashMap);
+
+macro_rules! tuple_seq_as_map_arr {
+ ($ty:ident <KAs, VAs>) => {
+ #[allow(clippy::implicit_hasher)]
+ impl<'de, K, KAs, V, VAs, const N: usize> DeserializeAs<'de, [(K, V); N]> for $ty<KAs, VAs>
+ where
+ KAs: DeserializeAs<'de, K>,
+ VAs: DeserializeAs<'de, V>,
+ {
+ fn deserialize_as<D>(deserializer: D) -> Result<[(K, V); N], D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct MapVisitor<K, KAs, V, VAs, const M: usize> {
+ marker: PhantomData<(K, KAs, V, VAs)>,
+ }
+
+ impl<'de, K, KAs, V, VAs, const M: usize> Visitor<'de> for MapVisitor<K, KAs, V, VAs, M>
+ where
+ KAs: DeserializeAs<'de, K>,
+ VAs: DeserializeAs<'de, V>,
+ {
+ type Value = [(K, V); M];
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_fmt(format_args!("a map of length {}", M))
+ }
+
+ fn visit_map<A>(self, access: A) -> Result<Self::Value, A::Error>
+ where
+ A: MapAccess<'de>,
+ {
+ utils::array_from_iterator(utils::MapIter::new(access).map(
+ |res: Result<(DeserializeAsWrap<K, KAs>, DeserializeAsWrap<V, VAs>), A::Error>| {
+ res.map(|(k, v)| (k.into_inner(), v.into_inner()))
+ }
+ ), &self)
+ }
+ }
+
+ let visitor = MapVisitor::<K, KAs, V, VAs, N> {
+ marker: PhantomData,
+ };
+ deserializer.deserialize_map(visitor)
+ }
+ }
+ }
+}
+tuple_seq_as_map_arr!(Map<KAs, VAs>);
+#[cfg(feature = "alloc")]
+tuple_seq_as_map_arr!(BTreeMap<KAs, VAs>);
+#[cfg(feature = "std")]
+tuple_seq_as_map_arr!(HashMap<KAs, VAs>);
+
+// endregion
+///////////////////////////////////////////////////////////////////////////////
+// region: Conversion types which cause different serialization behavior
+
+impl<'de, T: Deserialize<'de>> DeserializeAs<'de, T> for Same {
+ fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ T::deserialize(deserializer)
+ }
+}
+
+impl<'de, T> DeserializeAs<'de, T> for DisplayFromStr
+where
+ T: FromStr,
+ T::Err: Display,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ 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, "a string")
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ value.parse::<Self::Value>().map_err(DeError::custom)
+ }
+ }
+
+ deserializer.deserialize_str(Helper(PhantomData))
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'de, T, U> DeserializeAs<'de, Vec<T>> for VecSkipError<U>
+where
+ U: DeserializeAs<'de, T>,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<Vec<T>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ enum GoodOrError<T, TAs> {
+ Good(T),
+ // Only here to consume the TAs generic
+ Error(PhantomData<TAs>),
+ }
+
+ impl<'de, T, TAs> Deserialize<'de> for GoodOrError<T, TAs>
+ where
+ TAs: DeserializeAs<'de, T>,
+ {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let is_hr = deserializer.is_human_readable();
+ let content: content::de::Content<'de> = Deserialize::deserialize(deserializer)?;
+
+ Ok(
+ match <DeserializeAsWrap<T, TAs>>::deserialize(
+ content::de::ContentDeserializer::<D::Error>::new(content, is_hr),
+ ) {
+ Ok(elem) => GoodOrError::Good(elem.into_inner()),
+ Err(_) => GoodOrError::Error(PhantomData),
+ },
+ )
+ }
+ }
+
+ struct SeqVisitor<T, U> {
+ marker: PhantomData<T>,
+ marker2: PhantomData<U>,
+ }
+
+ impl<'de, T, TAs> Visitor<'de> for SeqVisitor<T, TAs>
+ where
+ TAs: DeserializeAs<'de, T>,
+ {
+ type Value = Vec<T>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a sequence")
+ }
+
+ fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
+ where
+ A: SeqAccess<'de>,
+ {
+ utils::SeqIter::new(seq)
+ .filter_map(|res: Result<GoodOrError<T, TAs>, A::Error>| match res {
+ Ok(GoodOrError::Good(value)) => Some(Ok(value)),
+ Ok(GoodOrError::Error(_)) => None,
+ Err(err) => Some(Err(err)),
+ })
+ .collect()
+ }
+ }
+
+ let visitor = SeqVisitor::<T, U> {
+ marker: PhantomData,
+ marker2: PhantomData,
+ };
+ deserializer.deserialize_seq(visitor)
+ }
+}
+
+impl<'de, Str> DeserializeAs<'de, Option<Str>> for NoneAsEmptyString
+where
+ Str: FromStr,
+ Str::Err: Display,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<Option<Str>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ 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("a string")
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ match value {
+ "" => Ok(None),
+ v => S::from_str(v).map(Some).map_err(DeError::custom),
+ }
+ }
+
+ // handles the `null` case
+ fn visit_unit<E>(self) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(None)
+ }
+ }
+
+ deserializer.deserialize_any(OptionStringEmptyNone(PhantomData))
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'de, T, TAs> DeserializeAs<'de, T> for DefaultOnError<TAs>
+where
+ TAs: DeserializeAs<'de, T>,
+ T: Default,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let is_hr = deserializer.is_human_readable();
+ let content: content::de::Content<'de> = match Deserialize::deserialize(deserializer) {
+ Ok(content) => content,
+ Err(_) => return Ok(Default::default()),
+ };
+
+ Ok(
+ match <DeserializeAsWrap<T, TAs>>::deserialize(content::de::ContentDeserializer::<
+ D::Error,
+ >::new(content, is_hr))
+ {
+ Ok(elem) => elem.into_inner(),
+ Err(_) => Default::default(),
+ },
+ )
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'de> DeserializeAs<'de, Vec<u8>> for BytesOrString {
+ fn deserialize_as<D>(deserializer: D) -> Result<Vec<u8>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ 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())
+ }
+
+ #[cfg(feature = "alloc")]
+ 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())
+ }
+
+ #[cfg(feature = "alloc")]
+ fn visit_string<E>(self, v: String) -> Result<Self::Value, E> {
+ Ok(v.into_bytes())
+ }
+
+ fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
+ where
+ A: SeqAccess<'de>,
+ {
+ utils::SeqIter::new(seq).collect()
+ }
+ }
+ deserializer.deserialize_any(BytesOrStringVisitor)
+ }
+}
+
+impl<'de, SEPARATOR, I, T> DeserializeAs<'de, I> for StringWithSeparator<SEPARATOR, T>
+where
+ SEPARATOR: Separator,
+ I: FromIterator<T>,
+ T: FromStr,
+ T::Err: Display,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<I, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct Helper<SEPARATOR, I, T>(PhantomData<(SEPARATOR, I, T)>);
+
+ impl<'de, SEPARATOR, I, T> Visitor<'de> for Helper<SEPARATOR, I, T>
+ where
+ SEPARATOR: Separator,
+ I: FromIterator<T>,
+ T: FromStr,
+ T::Err: Display,
+ {
+ type Value = I;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(formatter, "a string")
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ if value.is_empty() {
+ Ok(None.into_iter().collect())
+ } else {
+ value
+ .split(SEPARATOR::separator())
+ .map(FromStr::from_str)
+ .collect::<Result<_, _>>()
+ .map_err(DeError::custom)
+ }
+ }
+ }
+
+ deserializer.deserialize_str(Helper::<SEPARATOR, I, T>(PhantomData))
+ }
+}
+
+#[cfg(feature = "std")]
+macro_rules! use_signed_duration {
+ (
+ $main_trait:ident $internal_trait:ident =>
+ {
+ $ty:ty; $converter:ident =>
+ $({
+ $format:ty, $strictness:ty =>
+ $($tbound:ident: $bound:ident $(,)?)*
+ })*
+ }
+ ) => {
+ $(
+ impl<'de, $($tbound,)*> DeserializeAs<'de, $ty> for $main_trait<$format, $strictness>
+ where
+ $($tbound: $bound,)*
+ {
+ fn deserialize_as<D>(deserializer: D) -> Result<$ty, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let dur: DurationSigned = $internal_trait::<$format, $strictness>::deserialize_as(deserializer)?;
+ dur.$converter::<D>()
+ }
+ }
+ )*
+ };
+ (
+ $( $main_trait:ident $internal_trait:ident, )+ => $rest:tt
+ ) => {
+ $( use_signed_duration!($main_trait $internal_trait => $rest); )+
+ };
+}
+
+#[cfg(feature = "std")]
+use_signed_duration!(
+ DurationSeconds DurationSeconds,
+ DurationMilliSeconds DurationMilliSeconds,
+ DurationMicroSeconds DurationMicroSeconds,
+ DurationNanoSeconds DurationNanoSeconds,
+ => {
+ Duration; to_std_duration =>
+ {u64, Strict =>}
+ {f64, Strict =>}
+ {String, Strict =>}
+ {FORMAT, Flexible => FORMAT: Format}
+ }
+);
+#[cfg(feature = "std")]
+use_signed_duration!(
+ DurationSecondsWithFrac DurationSecondsWithFrac,
+ DurationMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ DurationMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ DurationNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ Duration; to_std_duration =>
+ {f64, Strict =>}
+ {String, Strict =>}
+ {FORMAT, Flexible => FORMAT: Format}
+ }
+);
+
+#[cfg(feature = "std")]
+use_signed_duration!(
+ TimestampSeconds DurationSeconds,
+ TimestampMilliSeconds DurationMilliSeconds,
+ TimestampMicroSeconds DurationMicroSeconds,
+ TimestampNanoSeconds DurationNanoSeconds,
+ => {
+ SystemTime; to_system_time =>
+ {i64, Strict =>}
+ {f64, Strict =>}
+ {String, Strict =>}
+ {FORMAT, Flexible => FORMAT: Format}
+ }
+);
+#[cfg(feature = "std")]
+use_signed_duration!(
+ TimestampSecondsWithFrac DurationSecondsWithFrac,
+ TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ SystemTime; to_system_time =>
+ {f64, Strict =>}
+ {String, Strict =>}
+ {FORMAT, Flexible => FORMAT: Format}
+ }
+);
+
+impl<'de, T, U> DeserializeAs<'de, T> for DefaultOnNull<U>
+where
+ U: DeserializeAs<'de, T>,
+ T: Default,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ Ok(Option::<U>::deserialize_as(deserializer)?.unwrap_or_default())
+ }
+}
+
+impl<'de> DeserializeAs<'de, &'de [u8]> for Bytes {
+ fn deserialize_as<D>(deserializer: D) -> Result<&'de [u8], D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ <&'de [u8]>::deserialize(deserializer)
+ }
+}
+
+// serde_bytes implementation for ByteBuf
+// https://github.com/serde-rs/bytes/blob/cbae606b9dc225fc094b031cc84eac9493da2058/src/bytebuf.rs#L196
+//
+// Implements:
+// * visit_seq
+// * visit_bytes
+// * visit_byte_buf
+// * visit_str
+// * visit_string
+#[cfg(feature = "alloc")]
+impl<'de> DeserializeAs<'de, Vec<u8>> for Bytes {
+ fn deserialize_as<D>(deserializer: D) -> Result<Vec<u8>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct VecVisitor;
+
+ impl<'de> Visitor<'de> for VecVisitor {
+ type Value = Vec<u8>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a byte array")
+ }
+
+ fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
+ where
+ A: SeqAccess<'de>,
+ {
+ utils::SeqIter::new(seq).collect::<Result<_, _>>()
+ }
+
+ fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(v.to_vec())
+ }
+
+ fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(v)
+ }
+
+ fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(v.as_bytes().to_vec())
+ }
+
+ fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(v.into_bytes())
+ }
+ }
+
+ deserializer.deserialize_byte_buf(VecVisitor)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'de> DeserializeAs<'de, Box<[u8]>> for Bytes {
+ fn deserialize_as<D>(deserializer: D) -> Result<Box<[u8]>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ <Bytes as DeserializeAs<'de, Vec<u8>>>::deserialize_as(deserializer)
+ .map(|vec| vec.into_boxed_slice())
+ }
+}
+
+// serde_bytes implementation for Cow<'a, [u8]>
+// https://github.com/serde-rs/bytes/blob/cbae606b9dc225fc094b031cc84eac9493da2058/src/de.rs#L77
+//
+// Implements:
+// * visit_borrowed_bytes
+// * visit_borrowed_str
+// * visit_bytes
+// * visit_str
+// * visit_byte_buf
+// * visit_string
+// * visit_seq
+#[cfg(feature = "alloc")]
+impl<'de> DeserializeAs<'de, Cow<'de, [u8]>> for Bytes {
+ fn deserialize_as<D>(deserializer: D) -> Result<Cow<'de, [u8]>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct CowVisitor;
+
+ impl<'de> Visitor<'de> for CowVisitor {
+ type Value = Cow<'de, [u8]>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a byte array")
+ }
+
+ fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(Cow::Borrowed(v))
+ }
+
+ fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(Cow::Borrowed(v.as_bytes()))
+ }
+
+ fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(Cow::Owned(v.to_vec()))
+ }
+
+ fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(Cow::Owned(v.as_bytes().to_vec()))
+ }
+
+ fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(Cow::Owned(v))
+ }
+
+ fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(Cow::Owned(v.into_bytes()))
+ }
+
+ fn visit_seq<V>(self, seq: V) -> Result<Self::Value, V::Error>
+ where
+ V: SeqAccess<'de>,
+ {
+ Ok(Cow::Owned(
+ utils::SeqIter::new(seq).collect::<Result<_, _>>()?,
+ ))
+ }
+ }
+
+ deserializer.deserialize_bytes(CowVisitor)
+ }
+}
+
+impl<'de, const N: usize> DeserializeAs<'de, [u8; N]> for Bytes {
+ fn deserialize_as<D>(deserializer: D) -> Result<[u8; N], D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct ArrayVisitor<const M: usize>;
+
+ impl<'de, const M: usize> Visitor<'de> for ArrayVisitor<M> {
+ type Value = [u8; M];
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_fmt(format_args!("an byte array of size {M}"))
+ }
+
+ fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
+ where
+ A: SeqAccess<'de>,
+ {
+ utils::array_from_iterator(utils::SeqIter::new(seq), &self)
+ }
+
+ fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ v.try_into()
+ .map_err(|_| DeError::invalid_length(v.len(), &self))
+ }
+
+ fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ v.as_bytes()
+ .try_into()
+ .map_err(|_| DeError::invalid_length(v.len(), &self))
+ }
+ }
+
+ deserializer.deserialize_bytes(ArrayVisitor::<N>)
+ }
+}
+
+impl<'de, const N: usize> DeserializeAs<'de, &'de [u8; N]> for Bytes {
+ fn deserialize_as<D>(deserializer: D) -> Result<&'de [u8; N], D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct ArrayVisitor<const M: usize>;
+
+ impl<'de, const M: usize> Visitor<'de> for ArrayVisitor<M> {
+ type Value = &'de [u8; M];
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_fmt(format_args!("a borrowed byte array of size {M}"))
+ }
+
+ fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ v.try_into()
+ .map_err(|_| DeError::invalid_length(v.len(), &self))
+ }
+
+ fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ v.as_bytes()
+ .try_into()
+ .map_err(|_| DeError::invalid_length(v.len(), &self))
+ }
+ }
+
+ deserializer.deserialize_bytes(ArrayVisitor::<N>)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'de, const N: usize> DeserializeAs<'de, Cow<'de, [u8; N]>> for Bytes {
+ fn deserialize_as<D>(deserializer: D) -> Result<Cow<'de, [u8; N]>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct CowVisitor<const M: usize>;
+
+ impl<'de, const M: usize> Visitor<'de> for CowVisitor<M> {
+ type Value = Cow<'de, [u8; M]>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a byte array")
+ }
+
+ fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(Cow::Borrowed(
+ v.try_into()
+ .map_err(|_| DeError::invalid_length(v.len(), &self))?,
+ ))
+ }
+
+ fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(Cow::Borrowed(
+ v.as_bytes()
+ .try_into()
+ .map_err(|_| DeError::invalid_length(v.len(), &self))?,
+ ))
+ }
+
+ fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(Cow::Owned(
+ v.to_vec()
+ .try_into()
+ .map_err(|_| DeError::invalid_length(v.len(), &self))?,
+ ))
+ }
+
+ fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(Cow::Owned(
+ v.as_bytes()
+ .to_vec()
+ .try_into()
+ .map_err(|_| DeError::invalid_length(v.len(), &self))?,
+ ))
+ }
+
+ fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ let len = v.len();
+ Ok(Cow::Owned(
+ v.try_into()
+ .map_err(|_| DeError::invalid_length(len, &self))?,
+ ))
+ }
+
+ fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ let len = v.len();
+ Ok(Cow::Owned(
+ v.into_bytes()
+ .try_into()
+ .map_err(|_| DeError::invalid_length(len, &self))?,
+ ))
+ }
+
+ fn visit_seq<V>(self, seq: V) -> Result<Self::Value, V::Error>
+ where
+ V: SeqAccess<'de>,
+ {
+ Ok(Cow::Owned(utils::array_from_iterator(
+ utils::SeqIter::new(seq),
+ &self,
+ )?))
+ }
+ }
+
+ deserializer.deserialize_bytes(CowVisitor)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'de, const N: usize> DeserializeAs<'de, Box<[u8; N]>> for Bytes {
+ fn deserialize_as<D>(deserializer: D) -> Result<Box<[u8; N]>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ Bytes::deserialize_as(deserializer).map(Box::new)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'de, T, TAs, FORMAT> DeserializeAs<'de, Vec<T>> for OneOrMany<TAs, FORMAT>
+where
+ TAs: DeserializeAs<'de, T>,
+ FORMAT: Format,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<Vec<T>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let is_hr = deserializer.is_human_readable();
+ let content: content::de::Content<'de> = Deserialize::deserialize(deserializer)?;
+
+ let one_err: D::Error = match <DeserializeAsWrap<T, TAs>>::deserialize(
+ content::de::ContentRefDeserializer::new(&content, is_hr),
+ ) {
+ Ok(one) => return Ok(alloc::vec![one.into_inner()]),
+ Err(err) => err,
+ };
+ let many_err: D::Error = match <DeserializeAsWrap<Vec<T>, Vec<TAs>>>::deserialize(
+ content::de::ContentDeserializer::new(content, is_hr),
+ ) {
+ Ok(many) => return Ok(many.into_inner()),
+ Err(err) => err,
+ };
+ Err(DeError::custom(format_args!(
+ "OneOrMany could not deserialize any variant:\n One: {}\n Many: {}",
+ one_err, many_err
+ )))
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'de, T, TAs1> DeserializeAs<'de, T> for PickFirst<(TAs1,)>
+where
+ TAs1: DeserializeAs<'de, T>,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ Ok(DeserializeAsWrap::<T, TAs1>::deserialize(deserializer)?.into_inner())
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'de, T, TAs1, TAs2> DeserializeAs<'de, T> for PickFirst<(TAs1, TAs2)>
+where
+ TAs1: DeserializeAs<'de, T>,
+ TAs2: DeserializeAs<'de, T>,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let is_hr = deserializer.is_human_readable();
+ let content: content::de::Content<'de> = Deserialize::deserialize(deserializer)?;
+
+ let first_err: D::Error = match <DeserializeAsWrap<T, TAs1>>::deserialize(
+ content::de::ContentRefDeserializer::new(&content, is_hr),
+ ) {
+ Ok(first) => return Ok(first.into_inner()),
+ Err(err) => err,
+ };
+ let second_err: D::Error = match <DeserializeAsWrap<T, TAs2>>::deserialize(
+ content::de::ContentDeserializer::new(content, is_hr),
+ ) {
+ Ok(second) => return Ok(second.into_inner()),
+ Err(err) => err,
+ };
+ Err(DeError::custom(format_args!(
+ "PickFirst could not deserialize any variant:\n First: {}\n Second: {}",
+ first_err, second_err
+ )))
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'de, T, TAs1, TAs2, TAs3> DeserializeAs<'de, T> for PickFirst<(TAs1, TAs2, TAs3)>
+where
+ TAs1: DeserializeAs<'de, T>,
+ TAs2: DeserializeAs<'de, T>,
+ TAs3: DeserializeAs<'de, T>,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let is_hr = deserializer.is_human_readable();
+ let content: content::de::Content<'de> = Deserialize::deserialize(deserializer)?;
+
+ let first_err: D::Error = match <DeserializeAsWrap<T, TAs1>>::deserialize(
+ content::de::ContentRefDeserializer::new(&content, is_hr),
+ ) {
+ Ok(first) => return Ok(first.into_inner()),
+ Err(err) => err,
+ };
+ let second_err: D::Error = match <DeserializeAsWrap<T, TAs2>>::deserialize(
+ content::de::ContentRefDeserializer::new(&content, is_hr),
+ ) {
+ Ok(second) => return Ok(second.into_inner()),
+ Err(err) => err,
+ };
+ let third_err: D::Error = match <DeserializeAsWrap<T, TAs3>>::deserialize(
+ content::de::ContentDeserializer::new(content, is_hr),
+ ) {
+ Ok(third) => return Ok(third.into_inner()),
+ Err(err) => err,
+ };
+ Err(DeError::custom(format_args!(
+ "PickFirst could not deserialize any variant:\n First: {}\n Second: {}\n Third: {}",
+ first_err, second_err, third_err,
+ )))
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'de, T, TAs1, TAs2, TAs3, TAs4> DeserializeAs<'de, T> for PickFirst<(TAs1, TAs2, TAs3, TAs4)>
+where
+ TAs1: DeserializeAs<'de, T>,
+ TAs2: DeserializeAs<'de, T>,
+ TAs3: DeserializeAs<'de, T>,
+ TAs4: DeserializeAs<'de, T>,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let is_hr = deserializer.is_human_readable();
+ let content: content::de::Content<'de> = Deserialize::deserialize(deserializer)?;
+
+ let first_err: D::Error = match <DeserializeAsWrap<T, TAs1>>::deserialize(
+ content::de::ContentRefDeserializer::new(&content, is_hr),
+ ) {
+ Ok(first) => return Ok(first.into_inner()),
+ Err(err) => err,
+ };
+ let second_err: D::Error = match <DeserializeAsWrap<T, TAs2>>::deserialize(
+ content::de::ContentRefDeserializer::new(&content, is_hr),
+ ) {
+ Ok(second) => return Ok(second.into_inner()),
+ Err(err) => err,
+ };
+ let third_err: D::Error = match <DeserializeAsWrap<T, TAs3>>::deserialize(
+ content::de::ContentRefDeserializer::new(&content, is_hr),
+ ) {
+ Ok(third) => return Ok(third.into_inner()),
+ Err(err) => err,
+ };
+ let fourth_err: D::Error = match <DeserializeAsWrap<T, TAs4>>::deserialize(
+ content::de::ContentDeserializer::new(content, is_hr),
+ ) {
+ Ok(fourth) => return Ok(fourth.into_inner()),
+ Err(err) => err,
+ };
+ Err(DeError::custom(format_args!(
+ "PickFirst could not deserialize any variant:\n First: {}\n Second: {}\n Third: {}\n Fourth: {}",
+ first_err, second_err, third_err, fourth_err,
+ )))
+ }
+}
+
+impl<'de, T, U> DeserializeAs<'de, T> for FromInto<U>
+where
+ U: Into<T>,
+ U: Deserialize<'de>,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ Ok(U::deserialize(deserializer)?.into())
+ }
+}
+
+impl<'de, T, U> DeserializeAs<'de, T> for TryFromInto<U>
+where
+ U: TryInto<T>,
+ <U as TryInto<T>>::Error: Display,
+ U: Deserialize<'de>,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ U::deserialize(deserializer)?
+ .try_into()
+ .map_err(DeError::custom)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'de> DeserializeAs<'de, Cow<'de, str>> for BorrowCow {
+ fn deserialize_as<D>(deserializer: D) -> Result<Cow<'de, str>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct CowVisitor;
+
+ impl<'de> Visitor<'de> for CowVisitor {
+ type Value = Cow<'de, str>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("an optionally borrowed string")
+ }
+
+ fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(Cow::Borrowed(v))
+ }
+
+ fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(Cow::Owned(v.to_owned()))
+ }
+
+ fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(Cow::Owned(v))
+ }
+ }
+
+ deserializer.deserialize_string(CowVisitor)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'de> DeserializeAs<'de, Cow<'de, [u8]>> for BorrowCow {
+ fn deserialize_as<D>(deserializer: D) -> Result<Cow<'de, [u8]>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ Bytes::deserialize_as(deserializer)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'de, const N: usize> DeserializeAs<'de, Cow<'de, [u8; N]>> for BorrowCow {
+ fn deserialize_as<D>(deserializer: D) -> Result<Cow<'de, [u8; N]>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ Bytes::deserialize_as(deserializer)
+ }
+}
+
+impl<'de> DeserializeAs<'de, bool> for BoolFromInt<Strict> {
+ fn deserialize_as<D>(deserializer: D) -> Result<bool, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct U8Visitor;
+ impl<'de> Visitor<'de> for U8Visitor {
+ type Value = bool;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("an integer 0 or 1")
+ }
+
+ fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ match v {
+ 0 => Ok(false),
+ 1 => Ok(true),
+ unexp => Err(DeError::invalid_value(
+ Unexpected::Unsigned(unexp as u64),
+ &"0 or 1",
+ )),
+ }
+ }
+
+ fn visit_i8<E>(self, v: i8) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ match v {
+ 0 => Ok(false),
+ 1 => Ok(true),
+ unexp => Err(DeError::invalid_value(
+ Unexpected::Signed(unexp as i64),
+ &"0 or 1",
+ )),
+ }
+ }
+
+ fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ match v {
+ 0 => Ok(false),
+ 1 => Ok(true),
+ unexp => Err(DeError::invalid_value(
+ Unexpected::Unsigned(unexp),
+ &"0 or 1",
+ )),
+ }
+ }
+
+ fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ match v {
+ 0 => Ok(false),
+ 1 => Ok(true),
+ unexp => Err(DeError::invalid_value(Unexpected::Signed(unexp), &"0 or 1")),
+ }
+ }
+
+ fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ match v {
+ 0 => Ok(false),
+ 1 => Ok(true),
+ unexp => Err(DeError::invalid_value(
+ Unexpected::Unsigned(unexp as u64),
+ &"0 or 1",
+ )),
+ }
+ }
+
+ fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ match v {
+ 0 => Ok(false),
+ 1 => Ok(true),
+ unexp => Err(DeError::invalid_value(
+ Unexpected::Signed(unexp as i64),
+ &"0 or 1",
+ )),
+ }
+ }
+ }
+
+ deserializer.deserialize_u8(U8Visitor)
+ }
+}
+
+impl<'de> DeserializeAs<'de, bool> for BoolFromInt<Flexible> {
+ fn deserialize_as<D>(deserializer: D) -> Result<bool, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct U8Visitor;
+ impl<'de> Visitor<'de> for U8Visitor {
+ type Value = bool;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("an integer")
+ }
+
+ fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(v != 0)
+ }
+
+ fn visit_i8<E>(self, v: i8) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(v != 0)
+ }
+
+ fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(v != 0)
+ }
+
+ fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(v != 0)
+ }
+
+ fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(v != 0)
+ }
+
+ fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(v != 0)
+ }
+ }
+
+ deserializer.deserialize_u8(U8Visitor)
+ }
+}
+
+// endregion
diff --git a/third_party/rust/serde_with/src/de/mod.rs b/third_party/rust/serde_with/src/de/mod.rs
new file mode 100644
index 0000000000..f9eb312498
--- /dev/null
+++ b/third_party/rust/serde_with/src/de/mod.rs
@@ -0,0 +1,158 @@
+//! Module for [`DeserializeAs`][] implementations
+//!
+//! The module contains the [`DeserializeAs`][] trait and helper code.
+//! Additionally, it contains implementations of [`DeserializeAs`][] for types defined in the Rust Standard Library or this crate.
+//!
+//! You can find more details on how to implement this trait for your types in the documentation of the [`DeserializeAs`][] trait and details about the usage in the [user guide][].
+//!
+//! [user guide]: crate::guide
+
+#[cfg(feature = "alloc")]
+mod duplicates;
+mod impls;
+
+use crate::prelude::*;
+
+/// A **data structure** that can be deserialized from any data format supported by Serde, analogue to [`Deserialize`].
+///
+/// The trait is analogue to the [`serde::Deserialize`][`Deserialize`] trait, with the same meaning of input and output arguments.
+/// It can and should be implemented using the same code structure as the [`Deserialize`] trait.
+/// As such, the same advice for [implementing `Deserialize`][impl-deserialize] applies here.
+///
+/// # Differences to [`Deserialize`]
+///
+/// The trait is only required for container-like types or types implementing specific conversion functions.
+/// Container-like types are [`Vec`], [`BTreeMap`], but also [`Option`] and [`Box`].
+/// Conversion types deserialize into a different Rust type.
+/// For example, [`DisplayFromStr`] uses the [`FromStr`] trait after deserializing a string and [`DurationSeconds`] creates a [`Duration`] from either String or integer values.
+///
+/// This code shows how to implement [`Deserialize`] for [`Box`]:
+///
+/// ```rust,ignore
+/// impl<'de, T: Deserialize<'de>> Deserialize<'de> for Box<T> {
+/// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+/// where
+/// D: Deserializer<'de>,
+/// {
+/// Ok(Box::new(Deserialize::deserialize(deserializer)?))
+/// }
+/// }
+/// ```
+///
+/// and this code shows how to do the same using [`DeserializeAs`][]:
+///
+/// ```rust,ignore
+/// impl<'de, T, U> DeserializeAs<'de, Box<T>> for Box<U>
+/// where
+/// U: DeserializeAs<'de, T>,
+/// {
+/// fn deserialize_as<D>(deserializer: D) -> Result<Box<T>, D::Error>
+/// where
+/// D: Deserializer<'de>,
+/// {
+/// Ok(Box::new(
+/// DeserializeAsWrap::<T, U>::deserialize(deserializer)?.into_inner(),
+/// ))
+/// }
+/// }
+/// ```
+///
+/// It uses two type parameters, `T` and `U` instead of only one and performs the deserialization step using the `DeserializeAsWrap` type.
+/// The `T` type is the on the Rust side after deserialization, whereas the `U` type determines how the value will be deserialized.
+/// These two changes are usually enough to make a container type implement [`DeserializeAs`][].
+///
+///
+/// [`DeserializeAsWrap`] is a piece of glue code which turns [`DeserializeAs`] into a serde compatible datatype, by converting all calls to `deserialize` into `deserialize_as`.
+/// This allows us to implement [`DeserializeAs`] such that it can be applied recursively throughout the whole data structure.
+/// This is mostly important for container types, such as `Vec` or `BTreeMap`.
+/// In a `BTreeMap` this allows us to specify two different serialization behaviors, one for key and one for value, using the [`DeserializeAs`] trait.
+///
+/// ## Implementing a converter Type
+///
+/// This shows a simplified implementation for [`DisplayFromStr`].
+///
+/// ```rust
+/// # #[cfg(all(feature = "macros"))] {
+/// # use serde::Deserialize;
+/// # use serde::de::Error;
+/// # use serde_with::{serde_as, DeserializeAs};
+/// # use std::str::FromStr;
+/// # use std::fmt::Display;
+/// struct DisplayFromStr;
+///
+/// impl<'de, T> DeserializeAs<'de, T> for DisplayFromStr
+/// where
+/// T: FromStr,
+/// T::Err: Display,
+/// {
+/// fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
+/// where
+/// D: serde::Deserializer<'de>,
+/// {
+/// let s = String::deserialize(deserializer).map_err(Error::custom)?;
+/// s.parse().map_err(Error::custom)
+/// }
+/// }
+/// #
+/// # #[serde_as]
+/// # #[derive(serde::Deserialize)]
+/// # struct S (#[serde_as(as = "DisplayFromStr")] bool);
+/// #
+/// # assert_eq!(false, serde_json::from_str::<S>(r#""false""#).unwrap().0);
+/// # }
+/// ```
+/// [`Box`]: std::boxed::Box
+/// [`BTreeMap`]: std::collections::BTreeMap
+/// [`Duration`]: std::time::Duration
+/// [`FromStr`]: std::str::FromStr
+/// [`Vec`]: std::vec::Vec
+/// [impl-deserialize]: https://serde.rs/impl-deserialize.html
+pub trait DeserializeAs<'de, T>: Sized {
+ /// Deserialize this value from the given Serde deserializer.
+ fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
+ where
+ D: Deserializer<'de>;
+}
+
+/// Helper type to implement [`DeserializeAs`] for container-like types.
+pub struct DeserializeAsWrap<T, U> {
+ value: T,
+ marker: PhantomData<U>,
+}
+
+impl<T, U> DeserializeAsWrap<T, U> {
+ /// Return the inner value of type `T`.
+ pub fn into_inner(self) -> T {
+ self.value
+ }
+}
+
+impl<'de, T, U> Deserialize<'de> for DeserializeAsWrap<T, U>
+where
+ U: DeserializeAs<'de, T>,
+{
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ U::deserialize_as(deserializer).map(|value| Self {
+ value,
+ marker: PhantomData,
+ })
+ }
+}
+
+impl<T: ?Sized> As<T> {
+ /// Deserialize type `T` using [`DeserializeAs`][]
+ ///
+ /// The function signature is compatible with [serde's with-annotation][with-annotation].
+ ///
+ /// [with-annotation]: https://serde.rs/field-attrs.html#with
+ pub fn deserialize<'de, D, I>(deserializer: D) -> Result<I, D::Error>
+ where
+ T: DeserializeAs<'de, I>,
+ D: Deserializer<'de>,
+ {
+ T::deserialize_as(deserializer)
+ }
+}
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..0c482c5ded
--- /dev/null
+++ b/third_party/rust/serde_with/src/duplicate_key_impls/error_on_duplicate.rs
@@ -0,0 +1,127 @@
+use crate::prelude::*;
+#[cfg(feature = "indexmap_1")]
+use indexmap_1::{IndexMap, IndexSet};
+
+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;
+}
+
+#[cfg(feature = "std")]
+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)
+ }
+}
+
+#[cfg(feature = "indexmap_1")]
+impl<T, S> PreventDuplicateInsertsSet<T> for IndexSet<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)
+ }
+}
+
+#[cfg(feature = "std")]
+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()
+ }
+}
+
+#[cfg(feature = "indexmap_1")]
+impl<K, V, S> PreventDuplicateInsertsMap<K, V> for IndexMap<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..5895eb6f66
--- /dev/null
+++ b/third_party/rust/serde_with/src/duplicate_key_impls/first_value_wins.rs
@@ -0,0 +1,89 @@
+use crate::prelude::*;
+#[cfg(feature = "indexmap_1")]
+use indexmap_1::IndexMap;
+
+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);
+}
+
+#[cfg(feature = "std")]
+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);
+ }
+ }
+ }
+}
+
+#[cfg(feature = "indexmap_1")]
+impl<K, V, S> DuplicateInsertsFirstWinsMap<K, V> for IndexMap<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 indexmap_1::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 alloc::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/last_value_wins.rs b/third_party/rust/serde_with/src/duplicate_key_impls/last_value_wins.rs
new file mode 100644
index 0000000000..68b3fd7318
--- /dev/null
+++ b/third_party/rust/serde_with/src/duplicate_key_impls/last_value_wins.rs
@@ -0,0 +1,68 @@
+use crate::prelude::*;
+#[cfg(feature = "indexmap_1")]
+use indexmap_1::IndexSet;
+
+pub trait DuplicateInsertsLastWinsSet<T> {
+ fn new(size_hint: Option<usize>) -> Self;
+
+ /// Insert or replace the existing value
+ fn replace(&mut self, value: T);
+}
+
+#[cfg(feature = "std")]
+impl<T, S> DuplicateInsertsLastWinsSet<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 replace(&mut self, value: T) {
+ // Hashset already fulfils the contract
+ self.replace(value);
+ }
+}
+
+#[cfg(feature = "indexmap_1")]
+impl<T, S> DuplicateInsertsLastWinsSet<T> for IndexSet<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 replace(&mut self, value: T) {
+ // Hashset already fulfils the contract
+ self.replace(value);
+ }
+}
+
+impl<T> DuplicateInsertsLastWinsSet<T> for BTreeSet<T>
+where
+ T: Ord,
+{
+ #[inline]
+ fn new(_size_hint: Option<usize>) -> Self {
+ Self::new()
+ }
+
+ #[inline]
+ fn replace(&mut self, value: T) {
+ // BTreeSet already fulfils the contract
+ self.replace(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..da3cdfc0f2
--- /dev/null
+++ b/third_party/rust/serde_with/src/duplicate_key_impls/mod.rs
@@ -0,0 +1,9 @@
+mod error_on_duplicate;
+mod first_value_wins;
+mod last_value_wins;
+
+pub use self::{
+ error_on_duplicate::{PreventDuplicateInsertsMap, PreventDuplicateInsertsSet},
+ first_value_wins::DuplicateInsertsFirstWinsMap,
+ last_value_wins::DuplicateInsertsLastWinsSet,
+};
diff --git a/third_party/rust/serde_with/src/enum_map.rs b/third_party/rust/serde_with/src/enum_map.rs
new file mode 100644
index 0000000000..bc6f1378ba
--- /dev/null
+++ b/third_party/rust/serde_with/src/enum_map.rs
@@ -0,0 +1,921 @@
+use crate::{
+ content::ser::{Content, ContentSerializer},
+ prelude::*,
+};
+
+/// Represent a list of enum values as a map.
+///
+/// This **only works** if the enum uses the default *externally tagged* representation.
+/// Other enum representations are not supported.
+///
+/// serde data formats often represent *externally tagged* enums as maps with a single key.
+/// The key is the enum variant name, and the value is the variant value.
+/// Sometimes a map with multiple keys should be treated like a list of enum values.
+///
+/// # Examples
+///
+/// ## JSON Map with multiple keys
+///
+/// ```rust
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// use serde_with::{serde_as, EnumMap};
+///
+/// # #[derive(Debug, Clone, PartialEq, Eq)]
+/// #[derive(Serialize, Deserialize)]
+/// enum EnumValue {
+/// Int(i32),
+/// String(String),
+/// Unit,
+/// Tuple(i32, String, bool),
+/// Struct {
+/// a: i32,
+/// b: String,
+/// c: bool,
+/// },
+/// }
+///
+/// #[serde_as]
+/// # #[derive(Debug, Clone, PartialEq, Eq)]
+/// #[derive(Serialize, Deserialize)]
+/// struct VecEnumValues (
+/// #[serde_as(as = "EnumMap")]
+/// Vec<EnumValue>,
+/// );
+///
+/// // ---
+///
+/// // This will serialize this list of values
+/// let values = VecEnumValues(vec![
+/// EnumValue::Int(123),
+/// EnumValue::String("FooBar".to_string()),
+/// EnumValue::Int(456),
+/// EnumValue::String("XXX".to_string()),
+/// EnumValue::Unit,
+/// EnumValue::Tuple(1, "Middle".to_string(), false),
+/// EnumValue::Struct {
+/// a: 666,
+/// b: "BBB".to_string(),
+/// c: true,
+/// },
+/// ]);
+///
+/// // into this JSON map
+/// // Duplicate keys are emitted for identical enum variants.
+/// let expected =
+/// r#"{
+/// "Int": 123,
+/// "String": "FooBar",
+/// "Int": 456,
+/// "String": "XXX",
+/// "Unit": null,
+/// "Tuple": [
+/// 1,
+/// "Middle",
+/// false
+/// ],
+/// "Struct": {
+/// "a": 666,
+/// "b": "BBB",
+/// "c": true
+/// }
+/// }"#;
+///
+/// // Both serialization and deserialization work flawlessly.
+/// let serialized = serde_json::to_string_pretty(&values).unwrap();
+/// assert_eq!(expected, serialized);
+/// let deserialized: VecEnumValues = serde_json::from_str(&serialized).unwrap();
+/// assert_eq!(values, deserialized);
+/// # }
+/// ```
+///
+/// ## XML structure with varying keys
+///
+/// With `serde_xml_rs` tuple and struct variants are not supported since they fail to roundtrip.
+/// The enum may have such variants as long as they are not serialized or deserialized.
+///
+/// ```
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// use serde_with::{serde_as, EnumMap};
+///
+/// # #[derive(Debug, Clone, PartialEq, Eq)]
+/// #[derive(Serialize, Deserialize)]
+/// enum EnumValue {
+/// Int(i32),
+/// String(String),
+/// Unit,
+/// }
+///
+/// #[serde_as]
+/// # #[derive(Debug, Clone, PartialEq, Eq)]
+/// #[derive(Serialize, Deserialize)]
+/// struct VecEnumValues {
+/// #[serde_as(as = "EnumMap")]
+/// vec: Vec<EnumValue>,
+/// }
+///
+/// // ---
+///
+/// // This will serialize this list of values
+/// let values = VecEnumValues {
+/// vec: vec![
+/// EnumValue::Int(123),
+/// EnumValue::String("FooBar".to_string()),
+/// EnumValue::Int(456),
+/// EnumValue::String("XXX".to_string()),
+/// EnumValue::Unit,
+/// ],
+/// };
+///
+/// // into this XML document
+/// // Duplicate keys are emitted for identical enum variants.
+/// let expected = r#"
+/// <?xml version="1.0" encoding="UTF-8"?>
+/// <VecEnumValues>
+/// <vec>
+/// <Int>123</Int>
+/// <String>FooBar</String>
+/// <Int>456</Int>
+/// <String>XXX</String>
+/// <Unit />
+/// </vec>
+/// </VecEnumValues>"#
+/// // Remove whitespace
+/// .replace(" ", "")
+/// .replace('\n', "");
+///
+/// // Both serialization and deserialization work flawlessly.
+/// let serialized = serde_xml_rs::to_string(&values).unwrap();
+/// assert_eq!(expected, serialized);
+/// let deserialized: VecEnumValues = serde_xml_rs::from_str(&serialized).unwrap();
+/// assert_eq!(values, deserialized);
+/// # }
+/// ```
+pub struct EnumMap;
+
+impl<T> SerializeAs<Vec<T>> for EnumMap
+where
+ T: Serialize,
+{
+ fn serialize_as<S>(source: &Vec<T>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ source.serialize(SeqAsMapSerializer(serializer))
+ }
+}
+
+impl<'de, T> DeserializeAs<'de, Vec<T>> for EnumMap
+where
+ T: Deserialize<'de>,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<Vec<T>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct EnumMapVisitor<T> {
+ is_human_readable: bool,
+ phantom: PhantomData<T>,
+ }
+
+ impl<'de, T> Visitor<'de> for EnumMapVisitor<T>
+ where
+ T: Deserialize<'de>,
+ {
+ type Value = Vec<T>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(formatter, "a map of enum values")
+ }
+
+ fn visit_map<A: MapAccess<'de>>(self, map: A) -> Result<Self::Value, A::Error> {
+ Vec::deserialize(SeqDeserializer {
+ delegate: map,
+ is_human_readable: self.is_human_readable,
+ })
+ }
+ }
+
+ let is_human_readable = deserializer.is_human_readable();
+ deserializer.deserialize_map(EnumMapVisitor {
+ is_human_readable,
+ phantom: PhantomData,
+ })
+ }
+}
+
+static END_OF_MAP_IDENTIFIER: &str = "__PRIVATE_END_OF_MAP_MARKER__";
+
+// Serialization code below here
+
+/// Convert a sequence to a map during serialization.
+///
+/// Only `serialize_seq` is implemented and forwarded to `serialize_map` on the inner `Serializer`.
+/// The elements are serialized with [`SerializeSeqElement`].
+struct SeqAsMapSerializer<S>(S);
+
+impl<S> Serializer for SeqAsMapSerializer<S>
+where
+ S: Serializer,
+{
+ type Ok = S::Ok;
+ type Error = S::Error;
+
+ type SerializeSeq = SerializeSeqElement<S::SerializeMap>;
+ type SerializeTuple = Impossible<S::Ok, S::Error>;
+ type SerializeTupleStruct = Impossible<S::Ok, S::Error>;
+ type SerializeTupleVariant = Impossible<S::Ok, S::Error>;
+ type SerializeMap = Impossible<S::Ok, S::Error>;
+ type SerializeStruct = Impossible<S::Ok, S::Error>;
+ type SerializeStructVariant = Impossible<S::Ok, S::Error>;
+
+ fn is_human_readable(&self) -> bool {
+ self.0.is_human_readable()
+ }
+
+ fn serialize_bool(self, _v: bool) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_i8(self, _v: i8) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_i16(self, _v: i16) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_i32(self, _v: i32) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_i64(self, _v: i64) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_i128(self, _v: i128) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_u8(self, _v: u8) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_u16(self, _v: u16) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_u32(self, _v: u32) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_u64(self, _v: u64) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_u128(self, _v: u128) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_f32(self, _v: f32) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_f64(self, _v: f64) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_char(self, _v: char) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_str(self, _v: &str) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_bytes(self, _v: &[u8]) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<Self::Ok, Self::Error>
+ where
+ T: Serialize,
+ {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_unit_variant(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ ) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_newtype_struct<T: ?Sized>(
+ self,
+ _name: &'static str,
+ _value: &T,
+ ) -> Result<Self::Ok, Self::Error>
+ where
+ T: Serialize,
+ {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_newtype_variant<T: ?Sized>(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ _value: &T,
+ ) -> Result<Self::Ok, Self::Error>
+ where
+ T: Serialize,
+ {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
+ let is_human_readable = self.0.is_human_readable();
+ self.0
+ .serialize_map(len)
+ .map(|delegate| SerializeSeqElement {
+ delegate,
+ is_human_readable,
+ })
+ }
+
+ fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_tuple_struct(
+ self,
+ _name: &'static str,
+ _len: usize,
+ ) -> Result<Self::SerializeTupleStruct, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_tuple_variant(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ _len: usize,
+ ) -> Result<Self::SerializeTupleVariant, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_struct(
+ self,
+ _name: &'static str,
+ _len: usize,
+ ) -> Result<Self::SerializeStruct, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_struct_variant(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ _len: usize,
+ ) -> Result<Self::SerializeStructVariant, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+}
+
+/// Serialize a single element but turn the sequence into a map logic.
+///
+/// It uses [`EnumAsMapElementSerializer`] for the map element serialization.
+///
+/// The [`Serializer`] implementation handles all the `serialize_*_variant` functions and defers to [`SerializeVariant`] for the more complicated tuple and struct variants.
+struct SerializeSeqElement<M> {
+ delegate: M,
+ is_human_readable: bool,
+}
+
+impl<M> SerializeSeq for SerializeSeqElement<M>
+where
+ M: SerializeMap,
+{
+ type Ok = M::Ok;
+ type Error = M::Error;
+
+ fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
+ where
+ T: Serialize,
+ {
+ value.serialize(EnumAsMapElementSerializer {
+ delegate: &mut self.delegate,
+ is_human_readable: self.is_human_readable,
+ })?;
+ Ok(())
+ }
+
+ fn end(self) -> Result<Self::Ok, Self::Error> {
+ self.delegate.end()
+ }
+}
+
+struct EnumAsMapElementSerializer<'a, M> {
+ delegate: &'a mut M,
+ is_human_readable: bool,
+}
+
+impl<'a, M> Serializer for EnumAsMapElementSerializer<'a, M>
+where
+ M: SerializeMap,
+{
+ type Ok = ();
+ type Error = M::Error;
+
+ type SerializeSeq = Impossible<Self::Ok, Self::Error>;
+ type SerializeTuple = Impossible<Self::Ok, Self::Error>;
+ type SerializeTupleStruct = Impossible<Self::Ok, Self::Error>;
+ type SerializeTupleVariant = SerializeVariant<'a, M>;
+ type SerializeMap = Impossible<Self::Ok, Self::Error>;
+ type SerializeStruct = Impossible<Self::Ok, Self::Error>;
+ type SerializeStructVariant = SerializeVariant<'a, M>;
+
+ fn is_human_readable(&self) -> bool {
+ self.is_human_readable
+ }
+
+ fn serialize_bool(self, _v: bool) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_i8(self, _v: i8) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_i16(self, _v: i16) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_i32(self, _v: i32) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_i64(self, _v: i64) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_i128(self, _v: i128) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_u8(self, _v: u8) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_u16(self, _v: u16) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_u32(self, _v: u32) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_u64(self, _v: u64) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_u128(self, _v: u128) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_f32(self, _v: f32) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_f64(self, _v: f64) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_char(self, _v: char) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_str(self, _v: &str) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_bytes(self, _v: &[u8]) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<Self::Ok, Self::Error>
+ where
+ T: Serialize,
+ {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_unit_variant(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ variant: &'static str,
+ ) -> Result<Self::Ok, Self::Error> {
+ self.delegate.serialize_entry(variant, &())?;
+ Ok(())
+ }
+
+ fn serialize_newtype_struct<T: ?Sized>(
+ self,
+ _name: &'static str,
+ _value: &T,
+ ) -> Result<Self::Ok, Self::Error>
+ where
+ T: Serialize,
+ {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_newtype_variant<T: ?Sized>(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ variant: &'static str,
+ value: &T,
+ ) -> Result<Self::Ok, Self::Error>
+ where
+ T: Serialize,
+ {
+ self.delegate.serialize_entry(variant, value)?;
+ Ok(())
+ }
+
+ fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_tuple_struct(
+ self,
+ _name: &'static str,
+ _len: usize,
+ ) -> Result<Self::SerializeTupleStruct, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_tuple_variant(
+ self,
+ name: &'static str,
+ _variant_index: u32,
+ variant: &'static str,
+ len: usize,
+ ) -> Result<Self::SerializeTupleVariant, Self::Error> {
+ Ok(SerializeVariant {
+ delegate: self.delegate,
+ is_human_readable: self.is_human_readable,
+ variant,
+ content: Content::TupleStruct(name, Vec::with_capacity(len)),
+ })
+ }
+
+ fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_struct(
+ self,
+ _name: &'static str,
+ _len: usize,
+ ) -> Result<Self::SerializeStruct, Self::Error> {
+ Err(SerError::custom("wrong type for EnumMap"))
+ }
+
+ fn serialize_struct_variant(
+ self,
+ name: &'static str,
+ _variant_index: u32,
+ variant: &'static str,
+ len: usize,
+ ) -> Result<Self::SerializeStructVariant, Self::Error> {
+ Ok(SerializeVariant {
+ delegate: self.delegate,
+ is_human_readable: self.is_human_readable,
+ variant,
+ content: Content::Struct(name, Vec::with_capacity(len)),
+ })
+ }
+}
+
+/// Serialize a struct or tuple variant enum as a map element
+///
+/// [`SerializeStructVariant`] serializes a struct variant, and [`SerializeTupleVariant`] a tuple variant.
+struct SerializeVariant<'a, M> {
+ delegate: &'a mut M,
+ is_human_readable: bool,
+ variant: &'static str,
+ content: Content,
+}
+
+impl<'a, M> SerializeStructVariant for SerializeVariant<'a, M>
+where
+ M: SerializeMap,
+{
+ type Ok = ();
+
+ type Error = M::Error;
+
+ fn serialize_field<T: ?Sized>(
+ &mut self,
+ key: &'static str,
+ value: &T,
+ ) -> Result<(), Self::Error>
+ where
+ T: Serialize,
+ {
+ // Serialize to a Content type first
+ let value: Content = value.serialize(ContentSerializer::new(self.is_human_readable))?;
+ if let Content::Struct(_name, fields) = &mut self.content {
+ fields.push((key, value));
+ }
+ Ok(())
+ }
+
+ fn end(self) -> Result<Self::Ok, Self::Error> {
+ self.delegate.serialize_entry(&self.variant, &self.content)
+ }
+}
+
+impl<'a, M> SerializeTupleVariant for SerializeVariant<'a, M>
+where
+ M: SerializeMap,
+{
+ type Ok = ();
+
+ type Error = M::Error;
+
+ fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
+ where
+ T: Serialize,
+ {
+ // Serialize to a Content type first
+ let value: Content = value.serialize(ContentSerializer::new(self.is_human_readable))?;
+ if let Content::TupleStruct(_name, fields) = &mut self.content {
+ fields.push(value);
+ }
+ Ok(())
+ }
+
+ fn end(self) -> Result<Self::Ok, Self::Error> {
+ self.delegate.serialize_entry(&self.variant, &self.content)
+ }
+}
+
+// Below is deserialization code
+
+/// Deserialize the sequence of enum instances.
+///
+/// The main [`Deserializer`] implementation handles the outer sequence (e.g., `Vec`), while the [`SeqAccess`] implementation is responsible for the inner elements.
+struct SeqDeserializer<M> {
+ delegate: M,
+ is_human_readable: bool,
+}
+
+impl<'de, M> Deserializer<'de> for SeqDeserializer<M>
+where
+ M: MapAccess<'de>,
+{
+ type Error = M::Error;
+
+ fn is_human_readable(&self) -> bool {
+ self.is_human_readable
+ }
+
+ fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_seq(self)
+ }
+
+ fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_seq(visitor)
+ }
+
+ serde::forward_to_deserialize_any! {
+ bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
+ bytes byte_buf option unit unit_struct newtype_struct tuple
+ tuple_struct map struct enum identifier ignored_any
+ }
+}
+
+impl<'de, M> SeqAccess<'de> for SeqDeserializer<M>
+where
+ M: MapAccess<'de>,
+{
+ type Error = M::Error;
+
+ fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
+ where
+ T: DeserializeSeed<'de>,
+ {
+ // We need to check if the map is done, or if there are still remaining elements.
+ // But we cannot ask the MapAccess directly.
+ // The only way is trying to deserialize, but we don't know the type yet.
+ // So we assume there is a value and try to deserialize it.
+ // If we later on find out that there is no value, we return a special error value, which we turn into `None`.
+ match seed.deserialize(EnumDeserializer {
+ delegate: &mut self.delegate,
+ is_human_readable: self.is_human_readable,
+ }) {
+ Ok(value) => Ok(Some(value)),
+ Err(err) => {
+ // Unfortunately we loose the optional aspect of MapAccess, so we need to special case an error value to mark the end of the map.
+ if err.to_string().contains(END_OF_MAP_IDENTIFIER) {
+ Ok(None)
+ } else {
+ Err(err)
+ }
+ }
+ }
+ }
+
+ fn size_hint(&self) -> Option<usize> {
+ self.delegate.size_hint()
+ }
+}
+
+/// Deserialize an enum from a map element
+///
+/// The [`Deserializer`] implementation is the starting point, which first calls the [`EnumAccess`] methods.
+/// The [`EnumAccess`] is used to deserialize the enum variant type of the enum.
+/// The [`VariantAccess`] is used to deserialize the value part of the enum.
+struct EnumDeserializer<M> {
+ delegate: M,
+ is_human_readable: bool,
+}
+
+impl<'de, M> Deserializer<'de> for EnumDeserializer<M>
+where
+ M: MapAccess<'de>,
+{
+ type Error = M::Error;
+
+ fn is_human_readable(&self) -> bool {
+ self.is_human_readable
+ }
+
+ fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_enum("", &[], visitor)
+ }
+
+ fn deserialize_enum<V>(
+ self,
+ _name: &'static str,
+ _variants: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_enum(self)
+ }
+
+ serde::forward_to_deserialize_any! {
+ bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
+ bytes byte_buf option unit unit_struct newtype_struct seq tuple
+ tuple_struct map struct identifier ignored_any
+ }
+}
+
+impl<'de, M> EnumAccess<'de> for EnumDeserializer<M>
+where
+ M: MapAccess<'de>,
+{
+ type Error = M::Error;
+ type Variant = Self;
+
+ fn variant_seed<T>(mut self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error>
+ where
+ T: DeserializeSeed<'de>,
+ {
+ match self.delegate.next_key_seed(seed)? {
+ Some(key) => Ok((key, self)),
+
+ // Unfortunately we loose the optional aspect of MapAccess, so we need to special case an error value to mark the end of the map.
+ None => Err(DeError::custom(END_OF_MAP_IDENTIFIER)),
+ }
+ }
+}
+
+impl<'de, M> VariantAccess<'de> for EnumDeserializer<M>
+where
+ M: MapAccess<'de>,
+{
+ type Error = M::Error;
+
+ fn unit_variant(mut self) -> Result<(), Self::Error> {
+ self.delegate.next_value()
+ }
+
+ fn newtype_variant_seed<T>(mut self, seed: T) -> Result<T::Value, Self::Error>
+ where
+ T: DeserializeSeed<'de>,
+ {
+ self.delegate.next_value_seed(seed)
+ }
+
+ fn tuple_variant<V>(mut self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.delegate
+ .next_value_seed(SeedTupleVariant { len, visitor })
+ }
+
+ fn struct_variant<V>(
+ mut self,
+ _fields: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.delegate.next_value_seed(SeedStructVariant { visitor })
+ }
+}
+
+struct SeedTupleVariant<V> {
+ len: usize,
+ visitor: V,
+}
+
+impl<'de, V> DeserializeSeed<'de> for SeedTupleVariant<V>
+where
+ V: Visitor<'de>,
+{
+ type Value = V::Value;
+
+ fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ deserializer.deserialize_tuple(self.len, self.visitor)
+ }
+}
+
+struct SeedStructVariant<V> {
+ visitor: V,
+}
+
+impl<'de, V> DeserializeSeed<'de> for SeedStructVariant<V>
+where
+ V: Visitor<'de>,
+{
+ type Value = V::Value;
+
+ fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ deserializer.deserialize_map(self.visitor)
+ }
+}
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..6dab1618c3
--- /dev/null
+++ b/third_party/rust/serde_with/src/flatten_maybe.rs
@@ -0,0 +1,88 @@
+/// 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
+/// # 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.
+/// serde_with::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 {
+ ($fn:ident, $field:tt) => {
+ fn $fn<'de, T, D>(deserializer: D) -> $crate::__private__::Result<T, D::Error>
+ where
+ T: $crate::serde::Deserialize<'de>,
+ D: $crate::serde::Deserializer<'de>,
+ {
+ use $crate::{
+ __private__::{
+ Option::{self, None, Some},
+ Result::{self, Err, Ok},
+ },
+ serde,
+ };
+
+ #[derive($crate::serde::Deserialize)]
+ #[serde(crate = "serde")]
+ pub struct Both<T> {
+ #[serde(flatten)]
+ flat: Option<T>,
+ #[serde(rename = $field)]
+ not_flat: Option<T>,
+ }
+
+ let both: Both<T> = $crate::serde::Deserialize::deserialize(deserializer)?;
+ match (both.flat, both.not_flat) {
+ (Some(t), None) | (None, Some(t)) => Ok(t),
+ (None, None) => Err($crate::serde::de::Error::missing_field($field)),
+ (Some(_), Some(_)) => Err($crate::serde::de::Error::custom(concat!(
+ "`",
+ $field,
+ "` is both flattened and not"
+ ))),
+ }
+ }
+ };
+}
diff --git a/third_party/rust/serde_with/src/formats.rs b/third_party/rust/serde_with/src/formats.rs
new file mode 100644
index 0000000000..27228325f2
--- /dev/null
+++ b/third_party/rust/serde_with/src/formats.rs
@@ -0,0 +1,140 @@
+//! Specify the format and how lenient the deserialization is
+
+#[allow(unused_imports)]
+use crate::prelude::*;
+
+/// Specify how to serialize/deserialize a type
+///
+/// The format specifier allows to configure how a value is serialized/deserialized.
+/// For example, you can serialize a timestamp as an integer using the UNIX epoch, as a string containing an integer, or as a string using ISO 8601.
+/// This [`Format`] traits allows more flexibility in configuring the format without the need to create a new type for each case.
+pub trait Format {}
+
+macro_rules! impl_format {
+ ($(#[$attr:meta] $t:ty)*) => {
+ $(
+ #[$attr]
+ impl Format for $t {}
+ )*
+ };
+}
+macro_rules! create_format {
+ ($(#[$attr:meta] $t:ident)*) => {
+ $(
+ #[$attr]
+ pub struct $t;
+ impl_format!(#[$attr] $t);
+ )*
+ };
+}
+impl_format!(
+ /// Serialize into an i8
+ i8
+ /// Serialize into a u8
+ u8
+ /// Serialize into an i16
+ i16
+ /// Serialize into a u16
+ u16
+ /// Serialize into an i32
+ i32
+ /// Serialize into a u32
+ u32
+ /// Serialize into an i64
+ i64
+ /// Serialize into a u64
+ u64
+ /// Serialize into an i128
+ i128
+ /// Serialize into a u128
+ u128
+
+ /// Serialize into a f32
+ f32
+ /// Serialize into a f64
+ f64
+
+ /// Serialize into a bool
+ bool
+);
+#[cfg(feature = "alloc")]
+impl_format!(
+ /// Serialize into a String
+ String
+);
+
+create_format!(
+ /// Use uppercase characters
+ Uppercase
+ /// Use lowercase characters
+ Lowercase
+
+ /// Use in combination with [`OneOrMany`](crate::OneOrMany). Emit single element for lists of size 1.
+ PreferOne
+ /// Use in combination with [`OneOrMany`](crate::OneOrMany). Always emit the list form.
+ PreferMany
+
+ /// Emit padding during serialization.
+ Padded
+ /// Do not emit padding during serialization.
+ Unpadded
+);
+
+/// Specify how lenient the deserialization process should be
+///
+/// Formats which make use of this trait should specify how it affects the deserialization behavior.
+pub trait Strictness {}
+
+/// Use strict deserialization behavior, see [`Strictness`].
+pub struct Strict;
+impl Strictness for Strict {}
+
+/// Use a flexible deserialization behavior, see [`Strictness`].
+pub struct Flexible;
+impl Strictness for Flexible {}
+
+/// 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
+pub struct SpaceSeparator;
+
+impl Separator for SpaceSeparator {
+ #[inline]
+ fn separator() -> &'static str {
+ " "
+ }
+}
+
+/// Predefined separator using a single comma
+pub struct CommaSeparator;
+
+impl Separator for CommaSeparator {
+ #[inline]
+ fn separator() -> &'static str {
+ ","
+ }
+}
+
+/// Predefined separator using a single semicolon
+pub struct SemicolonSeparator;
+
+impl Separator for SemicolonSeparator {
+ #[inline]
+ fn separator() -> &'static str {
+ ";"
+ }
+}
+
+/// Predefined separator using a single semicolon
+pub struct ColonSeparator;
+
+impl Separator for ColonSeparator {
+ #[inline]
+ fn separator() -> &'static str {
+ ":"
+ }
+}
diff --git a/third_party/rust/serde_with/src/guide.md b/third_party/rust/serde_with/src/guide.md
new file mode 100644
index 0000000000..788d4c9201
--- /dev/null
+++ b/third_party/rust/serde_with/src/guide.md
@@ -0,0 +1,86 @@
+# `serde_with` User Guide
+
+This crate provides helper functions to extend and change how [`serde`] serializes different data types.
+For example, you can serialize [a map as a sequence of tuples][crate::guide::serde_as#maps-to-vec-of-tuples], serialize [using the `Display` and `FromStr` traits][`DisplayFromStr`], or serialize [an empty `String` like `None`][NoneAsEmptyString].
+`serde_with` covers types from the Rust Standard Library and some common crates like [`chrono`][serde_with_chrono].
+
+[**A list of all supported transformations is available on this page.**](crate::guide::serde_as_transformations)
+
+The crate offers four types of functionality.
+
+## 1. A more flexible and composable replacement for the with annotation, called `serde_as`
+
+This is an alternative to [serde's with-annotation][with-annotation], which adds flexibility and composability to the scheme.
+The main downside is that it work with fewer types than [with-annotations][with-annotation].
+However, all types from the Rust Standard Library should be supported in all combinations and any missing entry is a bug.
+
+You mirror the type structure of the field you want to de/serialize.
+You can specify converters for the inner types of a field, e.g., `Vec<DisplayFromStr>`.
+The default de/serialization behavior can be restored by using `_` as a placeholder, e.g., `BTreeMap<_, DisplayFromStr>`.
+
+The `serde_as` scheme is based on two new traits: [`SerializeAs`] and [`DeserializeAs`].
+[Check out the detailed page about `serde_as` and the available features.](crate::guide::serde_as)
+
+### Example
+
+```rust
+# use serde::{Deserialize, Serialize};
+# use serde_with::{serde_as, DisplayFromStr, Map};
+# use std::net::Ipv4Addr;
+#
+#[serde_as]
+# #[derive(Debug, PartialEq, Eq)]
+#[derive(Deserialize, Serialize)]
+struct Data {
+ // Type does not implement Serialize or Deserialize
+ #[serde_as(as = "DisplayFromStr")]
+ address: Ipv4Addr,
+ // Treat the Vec like a map with duplicates
+ // Convert u32 into a String and keep the String the same type
+ #[serde_as(as = "Map<DisplayFromStr, _>")]
+ vec_as_map: Vec<(u32, String)>,
+}
+
+let data = Data {
+ address: Ipv4Addr::new(192, 168, 0, 1),
+ vec_as_map: vec![
+ (123, "Hello".into()),
+ (456, "World".into()),
+ (123, "Hello".into()),
+ ],
+};
+
+let json = r#"{
+ "address": "192.168.0.1",
+ "vec_as_map": {
+ "123": "Hello",
+ "456": "World",
+ "123": "Hello"
+ }
+}"#;
+
+// Test Serialization
+assert_eq!(json, serde_json::to_string_pretty(&data).unwrap());
+// Test Deserialization
+assert_eq!(data, serde_json::from_str(json).unwrap());
+```
+
+## 2. proc-macros to make it easier to use both above parts
+
+The proc-macros are an optional addition and improve the user experience for common tasks.
+We have already seen how the `serde_as` attribute is used to define the serialization instructions.
+
+The proc-macro attributes are defined in the [`serde_with_macros`] crate and re-exported from the root of this crate.
+The proc-macros are optional, but enabled by default.
+For further details, please refer to the documentation of each proc-macro.
+
+## 3. Derive macros to implement `Deserialize` and `Serialize`
+
+The derive macros work similar to the serde provided ones, but they do implement other de/serialization schemes.
+For example, the derives [`DeserializeFromStr`] and [`SerializeDisplay`] require that the type also implement [`FromStr`] and [`Display`] and de/serializes from/to a string instead of the usual way of iterating over all fields.
+
+[`Display`]: std::fmt::Display
+[`FromStr`]: std::str::FromStr
+[`serde_with_macros`]: serde_with_macros
+[serde_with_chrono]: crate::chrono
+[with-annotation]: https://serde.rs/field-attrs.html#with
diff --git a/third_party/rust/serde_with/src/guide/feature_flags.md b/third_party/rust/serde_with/src/guide/feature_flags.md
new file mode 100644
index 0000000000..39b6d4e72c
--- /dev/null
+++ b/third_party/rust/serde_with/src/guide/feature_flags.md
@@ -0,0 +1,88 @@
+# Available Feature Flags
+
+This crate has the following features which can be enabled.
+Each entry will explain the feature in more detail.
+
+`serde_with` is fully `no_std` compatible.
+Using it in a `no_std` environment requires using `default-features = false`, since `std` is enabled by default.
+
+1. [`alloc`](#alloc)
+2. [`std` (default)](#std-default)
+3. [`base64`](#base64)
+4. [`chrono_0_4`](#chrono_0_4)
+5. [`guide`](#guide)
+6. [`hex`](#hex)
+7. [`indexmap_1`](#indexmap_1)
+8. [`json`](#json)
+9. [`macros` (default)](#macros-default)
+10. [`time_0_3`](#time_0_3)
+
+## `alloc`
+
+Enable support for types from the `alloc` crate when running in a `no_std` environment.
+
+## `std` (default)
+
+Enables support for various types from the std library.
+This will enable `std` support in all dependencies too.
+The feature enabled by default and also enables `alloc`.
+
+## `base64`
+
+The `base64` feature enables serializing data in base64 format.
+
+This pulls in `base64` as a dependency.
+It enables the `alloc` feature.
+
+## `chrono_0_4`
+
+The `chrono_0_4` feature enables integration of `chrono_0_4` specific conversions.
+This includes support for the timestamp and duration types.
+More features are available in combination with `alloc` or `std`.
+The legacy feature name `chrono` is still available for v1 compatability.
+
+This pulls in `chrono` v0.4 as a dependency.
+
+## `guide`
+
+The `guide` feature enables inclusion of this user guide.
+The feature only changes the rustdoc output and enables no other effects.
+
+## `hex`
+
+The `hex` feature enables serializing data in hex format.
+
+This pulls in `hex` as a dependency.
+It enables the `alloc` feature.
+
+## `indexmap_1`
+
+The `indexmap_1` feature enables implementations of `indexmap_1` specific checks.
+This includes support for checking duplicate keys and duplicate values.
+The legacy feature name `indexmap` is still available for v1 compatability.
+
+This pulls in `indexmap` as a dependency.
+It enables the `alloc` feature.
+Some functionality is only available when `std` is enabled too.
+
+## `json`
+
+The `json` features enables JSON conversions from the `json` module.
+
+This pulls in `serde_json` as a dependency.
+It enables the `alloc` feature.
+
+## `macros` (default)
+
+The `macros` features enables all helper macros and derives.
+It is enabled by default, since the macros provide a usability benefit, especially for `serde_as`.
+
+This pulls in `serde_with_macros` as a dependency.
+
+## `time_0_3`
+
+The `time_0_3` enables integration of `time` v0.3 specific conversions.
+This includes support for the timestamp and duration types.
+
+This pulls in `time` v0.3 as a dependency.
+Some functionality is only available when `alloc` or `std` is enabled too.
diff --git a/third_party/rust/serde_with/src/guide/serde_as.md b/third_party/rust/serde_with/src/guide/serde_as.md
new file mode 100644
index 0000000000..2087906759
--- /dev/null
+++ b/third_party/rust/serde_with/src/guide/serde_as.md
@@ -0,0 +1,344 @@
+# `serde_as` Annotation
+
+This is an alternative to serde's with-annotation.
+It is more flexible and composable, but work with fewer types.
+
+The scheme is based on two new traits, [`SerializeAs`] and [`DeserializeAs`], which need to be implemented by all types which want to be compatible with `serde_as`.
+The proc-macro attribute [`#[serde_as]`][crate::serde_as] exists as a usability boost for users.
+The basic design of `serde_as` was developed by [@markazmierczak](https://github.com/markazmierczak).
+
+This page contains some general advice on the usage of `serde_as` and on implementing the necessary traits.
+[**A list of all supported transformations enabled by `serde_as` is available on this page.**](crate::guide::serde_as_transformations)
+
+1. [Switching from serde's with to `serde_as`](#switching-from-serdes-with-to-serde_as)
+ 1. [Deserializing Optional Fields](#deserializing-optional-fields)
+ 2. [Gating `serde_as` on Features](#gating-serde_as-on-features)
+2. [Implementing `SerializeAs` / `DeserializeAs`](#implementing-serializeas--deserializeas)
+ 1. [Using `#[serde_as]` on types without `SerializeAs` and `Serialize` implementations](#using-serde_as-on-types-without-serializeas-and-serialize-implementations)
+ 2. [Using `#[serde_as]` with serde's remote derives](#using-serde_as-with-serdes-remote-derives)
+3. [Re-exporting `serde_as`](#re-exporting-serde_as)
+
+## Switching from serde's with to `serde_as`
+
+For the user, the main difference is that instead of
+
+```rust,ignore
+#[serde(with = "...")]
+```
+
+you now have to write
+
+```rust,ignore
+#[serde_as(as = "...")]
+```
+
+and place the `#[serde_as]` attribute *before* the `#[derive]` attribute.
+You still need the `#[derive(Serialize, Deserialize)]` on the struct/enum.
+You mirror the type structure of the field you want to de/serialize.
+You can specify converters for the inner types of a field, e.g., `Vec<DisplayFromStr>`.
+The default de/serialization behavior can be restored by using `_` as a placeholder, e.g., `BTreeMap<_, DisplayFromStr>`.
+
+All together, this looks like:
+
+```rust
+use serde::{Deserialize, Serialize};
+use serde_with::{serde_as, DisplayFromStr};
+
+#[serde_as]
+#[derive(Serialize, Deserialize)]
+struct A {
+ #[serde_as(as = "DisplayFromStr")]
+ mime: mime::Mime,
+}
+```
+
+The main advantage is that you can compose `serde_as` stuff, which is impossible with the with-annotation.
+For example, the `mime` field from above could be nested in one or more data structures:
+
+```rust
+# use std::collections::BTreeMap;
+# use serde::{Deserialize, Serialize};
+# use serde_with::{serde_as, DisplayFromStr};
+#
+#[serde_as]
+#[derive(Serialize, Deserialize)]
+struct A {
+ #[serde_as(as = "Option<BTreeMap<_, Vec<DisplayFromStr>>>")]
+ mime: Option<BTreeMap<String, Vec<mime::Mime>>>,
+}
+```
+
+### Deserializing Optional Fields
+
+In many cases using `serde_as` on a field of type `Option` should behave as expected.
+This mean the field can still be missing during deserialization and will be filled with the value `None`.
+
+This "magic" can break in some cases. Then it becomes necessary to apply `#[serde(default)]` on the field in question.
+If the field is of type `Option<T>` and the conversion type is of `Option<S>`, the default attribute is automatically applied.
+These variants are detected as `Option`.
+* `Option`
+* `std::option::Option`, with or without leading `::`
+* `core::option::Option`, with or without leading `::`
+
+Any renaming will interfere with the detection, such as `use std::option::Option as StdOption;`.
+For more information you can inspect the documentation of the `serde_as` macro.
+
+```rust
+# use serde::{Deserialize, Serialize};
+# use serde_with::{serde_as, DisplayFromStr};
+#
+#[serde_as]
+#[derive(Serialize, Deserialize)]
+struct A {
+ #[serde_as(as = "Option<DisplayFromStr>")]
+ // In this situation boths `Option`s will be correctly identified and
+ // `#[serde(default)]` will be applied on this field.
+ val: Option<u32>,
+}
+```
+
+In the future, this behavior might change and `default` would be applied on `Option<T>` fields.
+You can add your feedback at [serde_with#185].
+
+### Gating `serde_as` on Features
+
+Gating `serde_as` behind optional features is currently not supported.
+More details can be found in the corresponding issue [serde_with#355].
+
+```rust,ignore
+#[cfg_attr(feature="serde" ,serde_as)]
+#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
+struct StructC {
+ #[cfg_attr(feature="serde" ,serde_as(as = "Vec<(_, _)>"))]
+ map: HashMap<(i32,i32), i32>,
+}
+```
+
+The `serde_as` proc-macro attribute will not recognize the `serde_as` attribute on the field and will not perform the necessary translation steps.
+The problem can be avoided by forcing Rust to evaluate all cfg-expressions before running `serde_as`.
+This is possible with the `#[cfg_eval]` attribute, which is considered for stabilization ([rust#82679], [rust#87221]).
+
+As a workaround, it is possible to remove the `serde_as` proc-macro attribute and perform the transformation manually.
+The transformation steps are listed in the [`serde_as`] documentations.
+For the example above, this means to replace the field attribute with:
+
+```rust,ignore
+use serde_with::{As, Same};
+
+#[cfg_attr(feature="serde", serde(with = "As::<Vec<(Same, Same)>>"))]
+map: HashMap<(i32,i32), i32>,
+```
+
+[rust#82679]: https://github.com/rust-lang/rust/issues/82679
+[rust#87221]: https://github.com/rust-lang/rust/pull/87221
+[serde_with#355]: https://github.com/jonasbb/serde_with/issues/355
+
+## Implementing `SerializeAs` / `DeserializeAs`
+
+You can support [`SerializeAs`] / [`DeserializeAs`] on your own types too.
+Most "leaf" types do not need to implement these traits, since they are supported implicitly.
+"Leaf" type refers to types which directly serialize like plain data types.
+[`SerializeAs`] / [`DeserializeAs`] is very important for collection types, like `Vec` or `BTreeMap`, since they need special handling for the key/value de/serialization such that the conversions can be done on the key/values.
+You also find them implemented on the conversion types, such as the [`DisplayFromStr`] type.
+These make up the bulk of this crate and allow you to perform all the nice conversions to [hex strings], the [bytes to string converter], or [duration to UNIX epoch].
+
+In many cases, conversion is only required from one serializable type to another one, without requiring the full power of the `Serialize` or `Deserialize` traits.
+In these cases, the [`serde_conv!`] macro conveniently allows defining conversion types without the boilerplate.
+The documentation of [`serde_conv!`] contains more details how to use it.
+
+The trait documentations for [`SerializeAs`] and [`DeserializeAs`] describe in details how to implement them for container types like `Box` or `Vec` and other types.
+
+### Using `#[serde_as]` on types without `SerializeAs` and `Serialize` implementations
+
+The `SerializeAs` and `DeserializeAs` traits can easily be used together with types from other crates without running into orphan rule problems.
+This is a distinct advantage of the `serde_as` system.
+For this example we assume we have a type `RemoteType` from a dependency which does not implement `Serialize` nor `SerializeAs`.
+We assume we have a module containing a `serialize` and a `deserialize` function, which can be used in the `#[serde(with = "MODULE")]` annotation.
+You find an example in the [official serde documentation](https://serde.rs/custom-date-format.html).
+
+Our goal is to serialize this `Data` struct.
+Right now, we do not have anything we can use to replace `???` with, since `_` only works if `RemoteType` would implement `Serialize`, which it does not.
+
+```rust
+# #[cfg(FALSE)] {
+#[serde_as]
+#[derive(serde::Serialize)]
+struct Data {
+ #[serde_as(as = "Vec<???>")]
+ vec: Vec<RemoteType>,
+}
+# }
+```
+
+We need to create a new type for which we can implement `SerializeAs`, to replace the `???`.
+The `SerializeAs` implementation is **always** written for a local type.
+This allows it to seamlessly work with types from dependencies without running into orphan rule problems.
+
+```rust
+# #[cfg(FALSE)] {
+struct LocalType;
+
+impl SerializeAs<RemoteType> for LocalType {
+ fn serialize_as<S>(value: &RemoteType, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ MODULE::serialize(value, serializer)
+ }
+}
+
+impl<'de> DeserializeAs<'de, RemoteType> for LocalType {
+ fn deserialize_as<D>(deserializer: D) -> Result<RemoteType, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ MODULE::deserialize(deserializer)
+ }
+}
+# }
+```
+
+This is how the final implementation looks like.
+We assumed we have a module `MODULE` with a `serialize` function already, which we use here to provide the implementation.
+As can be seen, this is mostly boilerplate, since the most part is encapsulated in `$module::serialize`.
+The final `Data` struct will now look like:
+
+```rust
+# #[cfg(FALSE)] {
+#[serde_as]
+#[derive(serde::Serialize)]
+struct Data {
+ #[serde_as(as = "Vec<LocalType>")]
+ vec: Vec<RemoteType>,
+}
+# }
+```
+
+### Using `#[serde_as]` with serde's remote derives
+
+A special case of the above section is using it on remote derives.
+This is a special functionality of serde, where it derives the de/serialization code for a type from another crate if all fields are `pub`.
+You can find all the details in the [official serde documentation](https://serde.rs/remote-derive.html).
+
+```rust
+# #[cfg(FALSE)] {
+// Pretend that this is somebody else's crate, not a module.
+mod other_crate {
+ // Neither Serde nor the other crate provides Serialize and Deserialize
+ // impls for this struct.
+ pub struct Duration {
+ pub secs: i64,
+ pub nanos: i32,
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+use other_crate::Duration;
+
+// Serde calls this the definition of the remote type. It is just a copy of the
+// remote data structure. The `remote` attribute gives the path to the actual
+// type we intend to derive code for.
+#[derive(serde::Serialize, serde::Deserialize)]
+#[serde(remote = "Duration")]
+struct DurationDef {
+ secs: i64,
+ nanos: i32,
+}
+# }
+```
+
+Our goal is now to use `Duration` within `serde_as`.
+We use the existing `DurationDef` type and its `serialize` and `deserialize` functions.
+We can write this implementation.
+The implementation for `DeserializeAs` works analogue.
+
+```rust
+# #[cfg(FALSE)] {
+impl SerializeAs<Duration> for DurationDef {
+ fn serialize_as<S>(value: &Duration, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: serde::Serializer,
+ {
+ DurationDef::serialize(value, serializer)
+ }
+}
+# }
+```
+
+This now allows us to use `Duration` for serialization.
+
+```rust
+# #[cfg(FALSE)] {
+use other_crate::Duration;
+
+#[serde_as]
+#[derive(serde::Serialize)]
+struct Data {
+ #[serde_as(as = "Vec<DurationDef>")]
+ vec: Vec<Duration>,
+}
+# }
+```
+
+## Re-exporting `serde_as`
+
+If `serde_as` is being used in a context where the `serde_with` crate is not available from the root
+path, but is re-exported at some other path, the `crate = "..."` attribute argument should be used
+to specify its path. This may be the case if `serde_as` is being used in a procedural macro -
+otherwise, users of that macro would need to add `serde_with` to their own Cargo manifest.
+
+The `crate` argument will generally be used in conjunction with [`serde`'s own `crate` argument].
+
+For example, a type definition may be defined in a procedural macro:
+
+```rust,ignore
+// some_other_lib_derive/src/lib.rs
+
+use proc_macro::TokenStream;
+use quote::quote;
+
+#[proc_macro]
+pub fn define_some_type(_item: TokenStream) -> TokenStream {
+ let def = quote! {
+ #[serde(crate = "::some_other_lib::serde")]
+ #[::some_other_lib::serde_with::serde_as(crate = "::some_other_lib::serde_with")]
+ #[derive(::some_other_lib::serde::Deserialize)]
+ struct Data {
+ #[serde_as(as = "_")]
+ a: u32,
+ }
+ };
+
+ TokenStream::from(def)
+}
+```
+
+This can be re-exported through a library which also re-exports `serde` and `serde_with`:
+
+```rust,ignore
+// some_other_lib/src/lib.rs
+
+pub use serde;
+pub use serde_with;
+pub use some_other_lib_derive::define_some_type;
+```
+
+The procedural macro can be used by other crates without any additional imports:
+
+```rust,ignore
+// consuming_crate/src/main.rs
+
+some_other_lib::define_some_type!();
+```
+
+[`DeserializeAs`]: crate::DeserializeAs
+[`DisplayFromStr`]: crate::DisplayFromStr
+[`serde_as`]: crate::serde_as
+[`serde_conv!`]: crate::serde_conv!
+[`serde`'s own `crate` argument]: https://serde.rs/container-attrs.html#crate
+[`SerializeAs`]: crate::SerializeAs
+[bytes to string converter]: crate::BytesOrString
+[duration to UNIX epoch]: crate::DurationSeconds
+[hex strings]: crate::hex::Hex
+[serde_with#185]: https://github.com/jonasbb/serde_with/issues/185
diff --git a/third_party/rust/serde_with/src/guide/serde_as_transformations.md b/third_party/rust/serde_with/src/guide/serde_as_transformations.md
new file mode 100644
index 0000000000..7cce186420
--- /dev/null
+++ b/third_party/rust/serde_with/src/guide/serde_as_transformations.md
@@ -0,0 +1,599 @@
+# De/Serialize Transformations Available
+
+This page lists the transformations implemented in this crate and supported by `serde_as`.
+
+1. [Base64 encode bytes](#base64-encode-bytes)
+2. [Big Array support](#big-array-support)
+3. [`bool` from integer](#bool-from-integer)
+4. [Borrow from the input for `Cow` type](#borrow-from-the-input-for-cow-type)
+5. [`Bytes` with more efficiency](#bytes-with-more-efficiency)
+6. [Convert to an intermediate type using `Into`](#convert-to-an-intermediate-type-using-into)
+7. [Convert to an intermediate type using `TryInto`](#convert-to-an-intermediate-type-using-tryinto)
+8. [`Default` from `null`](#default-from-null)
+9. [De/Serialize into `Vec`, ignoring errors](#deserialize-into-vec-ignoring-errors)
+10. [De/Serialize with `FromStr` and `Display`](#deserialize-with-fromstr-and-display)
+11. [`Duration` as seconds](#duration-as-seconds)
+12. [Hex encode bytes](#hex-encode-bytes)
+13. [Ignore deserialization errors](#ignore-deserialization-errors)
+14. [`Maps` to `Vec` of enums](#maps-to-vec-of-enums)
+15. [`Maps` to `Vec` of tuples](#maps-to-vec-of-tuples)
+16. [`NaiveDateTime` like UTC timestamp](#naivedatetime-like-utc-timestamp)
+17. [`None` as empty `String`](#none-as-empty-string)
+18. [One or many elements into `Vec`](#one-or-many-elements-into-vec)
+19. [Overwrite existing set values](#overwrite-existing-set-values)
+20. [Pick first successful deserialization](#pick-first-successful-deserialization)
+21. [Prefer the first map key when duplicates exist](#prefer-the-first-map-key-when-duplicates-exist)
+22. [Prevent duplicate map keys](#prevent-duplicate-map-keys)
+23. [Prevent duplicate set values](#prevent-duplicate-set-values)
+24. [Struct fields as map keys](#struct-fields-as-map-keys)
+25. [Timestamps as seconds since UNIX epoch](#timestamps-as-seconds-since-unix-epoch)
+26. [Value into JSON String](#value-into-json-string)
+27. [`Vec` of tuples to `Maps`](#vec-of-tuples-to-maps)
+28. [Well-known time formats for `OffsetDateTime`](#well-known-time-formats-for-offsetdatetime)
+
+## Base64 encode bytes
+
+[`Base64`]
+
+Requires the `base64` feature.
+The character set and padding behavior can be configured.
+
+```ignore
+// Rust
+#[serde_as(as = "serde_with::base64::Base64")]
+value: Vec<u8>,
+#[serde_as(as = "Base64<Bcrypt, Unpadded>")]
+bcrypt_unpadded: Vec<u8>,
+
+// JSON
+"value": "SGVsbG8gV29ybGQ=",
+"bcrypt_unpadded": "QETqZE6eT07wZEO",
+```
+
+## Big Array support
+
+Support for arrays of arbitrary size.
+
+```ignore
+// Rust
+#[serde_as(as = "[[_; 64]; 33]")]
+value: [[u8; 64]; 33],
+
+// JSON
+"value": [[0,0,0,0,0,...], [0,0,0,...], ...],
+```
+
+## `bool` from integer
+
+Deserialize an integer and convert it into a `bool`.
+[`BoolFromInt<Strict>`] (default) deserializes 0 to `false` and `1` to `true`, other numbers are errors.
+[`BoolFromInt<Flexible>`] deserializes any non-zero as `true`.
+Serialization only emits 0/1.
+
+```ignore
+// Rust
+#[serde_as(as = "BoolFromInt")] // BoolFromInt<Strict>
+b: bool,
+
+// JSON
+"b": 1,
+```
+
+## Borrow from the input for `Cow` type
+
+The types `Cow<'_, str>`, `Cow<'_, [u8]>`, or `Cow<'_, [u8; N]>` can borrow from the input, avoiding extra copies.
+
+```ignore
+// Rust
+#[serde_as(as = "BorrowCow")]
+value: Cow<'a, str>,
+
+// JSON
+"value": "foobar",
+```
+
+## `Bytes` with more efficiency
+
+[`Bytes`]
+
+More efficient serialization for byte slices and similar.
+
+```ignore
+// Rust
+#[serde_as(as = "Bytes")]
+value: Vec<u8>,
+
+// JSON
+"value": [0, 1, 2, 3, ...],
+```
+
+## Convert to an intermediate type using `Into`
+
+[`FromInto`]
+
+```ignore
+// Rust
+#[serde_as(as = "FromInto<(u8, u8, u8)>")]
+value: Rgb,
+
+impl From<(u8, u8, u8)> for Rgb { ... }
+impl From<Rgb> for (u8, u8, u8) { ... }
+
+// JSON
+"value": [128, 64, 32],
+```
+
+## Convert to an intermediate type using `TryInto`
+
+[`TryFromInto`]
+
+```ignore
+// Rust
+#[serde_as(as = "TryFromInto<i8>")]
+value: u8,
+
+// JSON
+"value": 127,
+```
+
+## `Default` from `null`
+
+[`DefaultOnNull`]
+
+```ignore
+// Rust
+#[serde_as(as = "DefaultOnNull")]
+value: u32,
+#[serde_as(as = "DefaultOnNull<DisplayFromStr>")]
+value2: u32,
+
+// JSON
+"value": 123,
+"value2": "999",
+
+// Deserializes null into the Default value, i.e.,
+null => 0
+```
+
+## De/Serialize into `Vec`, ignoring errors
+
+[`VecSkipError`]
+
+For formats with heterogenous-typed sequences, we can collect only the deserializable elements.
+This is also useful for unknown enum variants.
+
+```ignore
+#[derive(serde::Deserialize)]
+enum Color {
+ Red,
+ Green,
+ Blue,
+}
+
+// JSON
+"colors": ["Blue", "Yellow", "Green"],
+
+// Rust
+#[serde_as(as = "VecSkipError<_>")]
+colors: Vec<Color>,
+
+// => vec![Blue, Green]
+```
+
+## De/Serialize with `FromStr` and `Display`
+
+Useful if a type implements `FromStr` / `Display` but not `Deserialize` / `Serialize`.
+
+[`DisplayFromStr`]
+
+```ignore
+// Rust
+#[serde_as(as = "serde_with::DisplayFromStr")]
+value: u128,
+#[serde_as(as = "serde_with::DisplayFromStr")]
+mime: mime::Mime,
+
+// JSON
+"value": "340282366920938463463374607431768211455",
+"mime": "text/*",
+```
+
+## `Duration` as seconds
+
+[`DurationSeconds`]
+
+```ignore
+// Rust
+#[serde_as(as = "serde_with::DurationSeconds<u64>")]
+value: Duration,
+
+// JSON
+"value": 86400,
+```
+
+[`DurationSecondsWithFrac`] supports subsecond precision:
+
+```ignore
+// Rust
+#[serde_as(as = "serde_with::DurationSecondsWithFrac<f64>")]
+value: Duration,
+
+// JSON
+"value": 1.234,
+```
+
+Different serialization formats are possible:
+
+```ignore
+// Rust
+#[serde_as(as = "serde_with::DurationSecondsWithFrac<String>")]
+value: Duration,
+
+// JSON
+"value": "1.234",
+```
+
+The same conversions are also implemented for [`chrono::Duration`] with the `chrono` feature.
+
+The same conversions are also implemented for [`time::Duration`] with the `time_0_3` feature.
+
+## Hex encode bytes
+
+[`Hex`]
+
+Requires the `hex` feature.
+The hex string can use upper- and lowercase characters.
+
+```ignore
+// Rust
+#[serde_as(as = "serde_with::hex::Hex")]
+lowercase: Vec<u8>,
+#[serde_as(as = "serde_with::hex::Hex<serde_with::formats::Uppercase>")]
+uppercase: Vec<u8>,
+
+// JSON
+"lowercase": "deadbeef",
+"uppercase": "DEADBEEF",
+```
+
+## Ignore deserialization errors
+
+Check the documentation for [`DefaultOnError`].
+
+## `Maps` to `Vec` of enums
+
+[`EnumMap`]
+
+Combine multiple enum values into a single map.
+The key is the enum variant name, and the value is the variant value.
+This only works with [*externally tagged*] enums, the default enum representation.
+Other forms cannot be supported.
+
+```ignore
+enum EnumValue {
+ Int(i32),
+ String(String),
+ Unit,
+ Tuple(i32, String),
+ Struct {
+ a: i32,
+ b: String,
+ },
+}
+
+// Rust
+struct VecEnumValues (
+ #[serde_as(as = "EnumMap")]
+ Vec<EnumValue>,
+);
+
+VecEnumValues(vec![
+ EnumValue::Int(123),
+ EnumValue::String("Foo".to_string()),
+ EnumValue::Unit,
+ EnumValue::Tuple(1, "Bar".to_string()),
+ EnumValue::Struct {
+ a: 666,
+ b: "Baz".to_string(),
+ },
+])
+
+// JSON
+{
+ "Int": 123,
+ "String": "Foo",
+ "Unit": null,
+ "Tuple": [
+ 1,
+ "Bar",
+ ],
+ "Struct": {
+ "a": 666,
+ "b": "Baz",
+ }
+}
+```
+
+[*externally tagged*]: https://serde.rs/enum-representations.html#externally-tagged
+
+## `Maps` to `Vec` of tuples
+
+```ignore
+// Rust
+#[serde_as(as = "Seq<(_, _)>")] // also works with Vec
+value: HashMap<String, u32>, // also works with other maps like BTreeMap or IndexMap
+
+// JSON
+"value": [
+ ["hello", 1],
+ ["world", 2]
+],
+```
+
+The [inverse operation](#vec-of-tuples-to-maps) is also available.
+
+## `NaiveDateTime` like UTC timestamp
+
+Requires the `chrono` feature.
+
+```ignore
+// Rust
+#[serde_as(as = "chrono::DateTime<chrono::Utc>")]
+value: chrono::NaiveDateTime,
+
+// JSON
+"value": "1994-11-05T08:15:30Z",
+ ^ Pretend DateTime is UTC
+```
+
+## `None` as empty `String`
+
+[`NoneAsEmptyString`]
+
+```ignore
+// Rust
+#[serde_as(as = "serde_with::NoneAsEmptyString")]
+value: Option<String>,
+
+// JSON
+"value": "", // converts to None
+
+"value": "Hello World!", // converts to Some
+```
+
+## One or many elements into `Vec`
+
+[`OneOrMany`]
+
+```ignore
+// Rust
+#[serde_as(as = "serde_with::OneOrMany<_>")]
+value: Vec<String>,
+
+// JSON
+"value": "", // Deserializes single elements
+
+"value": ["Hello", "World!"], // or lists of many
+```
+
+## Overwrite existing set values
+
+[`SetLastValueWins`]
+
+serdes default behavior for sets is to take the first value, when multiple "equal" values are inserted into a set.
+This changes the logic, to prefer the last value.
+
+## Pick first successful deserialization
+
+[`PickFirst`]
+
+```ignore
+// Rust
+#[serde_as(as = "serde_with::PickFirst<(_, serde_with::DisplayFromStr)>")]
+value: u32,
+
+// JSON
+// serialize into
+"value": 666,
+// deserialize from either
+"value": 666,
+"value": "666",
+```
+
+## Prefer the first map key when duplicates exist
+
+[`MapFirstKeyWins`]
+
+serdes default behavior is to take the last key and value combination, if multiple "equal" keys exist.
+This changes the logic to instead prefer the first found key-value combination.
+
+## Prevent duplicate map keys
+
+[`MapPreventDuplicates`]
+
+Error during deserialization, when duplicate map keys are detected.
+
+## Prevent duplicate set values
+
+[`SetPreventDuplicates`]
+
+Error during deserialization, when duplicate set values are detected.
+
+## Struct fields as map keys
+
+[`KeyValueMap`]
+
+This conversion is possible for structs and maps, using the `$key$` field.
+Tuples, tuple structs, and sequences are supported by turning the first value into the map key.
+
+Each of the `SimpleStruct`s
+
+```ignore
+// Somewhere there is a collection:
+// #[serde_as(as = "KeyValueMap<_>")]
+// Vec<SimpleStruct>,
+
+#[derive(Serialize, Deserialize)]
+struct SimpleStruct {
+ b: bool,
+ // The field named `$key$` will become the map key
+ #[serde(rename = "$key$")]
+ id: String,
+ i: i32,
+}
+```
+
+will turn into a JSON snippet like this.
+
+```json
+"id-0000": {
+ "b": false,
+ "i": 123
+},
+```
+
+## Timestamps as seconds since UNIX epoch
+
+[`TimestampSeconds`]
+
+```ignore
+// Rust
+#[serde_as(as = "serde_with::TimestampSeconds<i64>")]
+value: SystemTime,
+
+// JSON
+"value": 86400,
+```
+
+[`TimestampSecondsWithFrac`] supports subsecond precision:
+
+```ignore
+// Rust
+#[serde_as(as = "serde_with::TimestampSecondsWithFrac<f64>")]
+value: SystemTime,
+
+// JSON
+"value": 1.234,
+```
+
+Different serialization formats are possible:
+
+```ignore
+// Rust
+#[serde_as(as = "serde_with::TimestampSecondsWithFrac<String>")]
+value: SystemTime,
+
+// JSON
+"value": "1.234",
+```
+
+The same conversions are also implemented for [`chrono::DateTime<Utc>`], [`chrono::DateTime<Local>`], and [`chrono::NaiveDateTime`] with the `chrono` feature.
+
+The conversions are available for [`time::OffsetDateTime`] and [`time::PrimitiveDateTime`] with the `time_0_3` feature enabled.
+
+## Value into JSON String
+
+Some JSON APIs are weird and return a JSON encoded string in a JSON response
+
+[`JsonString`]
+
+Requires the `json` feature.
+
+```ignore
+// Rust
+#[derive(Deserialize, Serialize)]
+struct OtherStruct {
+ value: usize,
+}
+
+#[serde_as(as = "serde_with::json::JsonString")]
+value: OtherStruct,
+
+// JSON
+"value": "{\"value\":5}",
+```
+
+```ignore
+#[serde_as(as = "JsonString<Vec<(JsonString, _)>>")]
+value: BTreeMap<[u8; 2], u32>,
+
+// JSON
+{"value":"[[\"[1,2]\",3],[\"[4,5]\",6]]"}
+```
+
+## `Vec` of tuples to `Maps`
+
+```ignore
+// Rust
+#[serde_as(as = "Map<_, _>")] // also works with BTreeMap and HashMap
+value: Vec<(String, u32)>,
+
+// JSON
+"value": {
+ "hello": 1,
+ "world": 2
+},
+```
+
+This operation is also available for other sequence types.
+This includes `BinaryHeap<(K, V)>`, `BTreeSet<(K, V)>`, `HashSet<(K, V)>`, `LinkedList<(K, V)>`, `VecDeque<(K, V)>`, `Option<(K, V)>` and `[(K, V); N]` for all sizes of N.
+
+The [inverse operation](#maps-to-vec-of-tuples) is also available.
+
+## Well-known time formats for `OffsetDateTime`
+
+[`time::OffsetDateTime`] can be serialized in string format in different well-known formats.
+Three formats are supported, [`time::format_description::well_known::Rfc2822`], [`time::format_description::well_known::Rfc3339`], and [`time::format_description::well_known::Iso8601`].
+
+```ignore
+// Rust
+#[serde_as(as = "time::format_description::well_known::Rfc2822")]
+rfc_2822: OffsetDateTime,
+#[serde_as(as = "time::format_description::well_known::Rfc3339")]
+rfc_3339: OffsetDateTime,
+#[serde_as(as = "time::format_description::well_known::Iso8601<Config>")]
+iso_8601: OffsetDateTime,
+
+// JSON
+"rfc_2822": "Fri, 21 Nov 1997 09:55:06 -0600",
+"rfc_3339": "1997-11-21T09:55:06-06:00",
+"iso_8061": "1997-11-21T09:55:06-06:00",
+```
+
+These conversions are available with the `time_0_3` feature flag.
+
+[`Base64`]: crate::base64::Base64
+[`BoolFromInt<Flexible>`]: crate::BoolFromInt
+[`BoolFromInt<Strict>`]: crate::BoolFromInt
+[`Bytes`]: crate::Bytes
+[`chrono::DateTime<Local>`]: chrono::DateTime
+[`chrono::DateTime<Utc>`]: chrono::DateTime
+[`chrono::Duration`]: chrono::Duration
+[`chrono::NaiveDateTime`]: chrono::NaiveDateTime
+[`DefaultOnError`]: crate::DefaultOnError
+[`DefaultOnNull`]: crate::DefaultOnNull
+[`DisplayFromStr`]: crate::DisplayFromStr
+[`DurationSeconds`]: crate::DurationSeconds
+[`DurationSecondsWithFrac`]: crate::DurationSecondsWithFrac
+[`EnumMap`]: crate::EnumMap
+[`FromInto`]: crate::FromInto
+[`Hex`]: crate::hex::Hex
+[`JsonString`]: crate::json::JsonString
+[`KeyValueMap`]: crate::KeyValueMap
+[`MapFirstKeyWins`]: crate::MapFirstKeyWins
+[`MapPreventDuplicates`]: crate::MapPreventDuplicates
+[`NoneAsEmptyString`]: crate::NoneAsEmptyString
+[`OneOrMany`]: crate::OneOrMany
+[`PickFirst`]: crate::PickFirst
+[`SetLastValueWins`]: crate::SetLastValueWins
+[`SetPreventDuplicates`]: crate::SetPreventDuplicates
+[`time::Duration`]: time_0_3::Duration
+[`time::format_description::well_known::Iso8601`]: time_0_3::format_description::well_known::Iso8601
+[`time::format_description::well_known::Rfc2822`]: time_0_3::format_description::well_known::Rfc2822
+[`time::format_description::well_known::Rfc3339`]: time_0_3::format_description::well_known::Rfc3339
+[`time::OffsetDateTime`]: time_0_3::OffsetDateTime
+[`time::PrimitiveDateTime`]: time_0_3::PrimitiveDateTime
+[`TimestampSeconds`]: crate::TimestampSeconds
+[`TimestampSecondsWithFrac`]: crate::TimestampSecondsWithFrac
+[`TryFromInto`]: crate::TryFromInto
+[`VecSkipError`]: crate::VecSkipError
diff --git a/third_party/rust/serde_with/src/hex.rs b/third_party/rust/serde_with/src/hex.rs
new file mode 100644
index 0000000000..b104321476
--- /dev/null
+++ b/third_party/rust/serde_with/src/hex.rs
@@ -0,0 +1,143 @@
+//! De/Serialization of hexadecimal encoded bytes
+//!
+//! This modules is only available when using the `hex` feature of the crate.
+//!
+//! Please check the documentation on the [`Hex`] type for details.
+
+use crate::prelude::*;
+
+/// Serialize bytes as a hex string
+///
+/// The type serializes a sequence of bytes as a hexadecimal string.
+/// It works on any type implementing `AsRef<[u8]>` for serialization and `TryFrom<Vec<u8>>` for deserialization.
+///
+/// The format type parameter specifies if the hex string should use lower- or uppercase characters.
+/// Valid options are the types [`formats::Lowercase`] and [`formats::Uppercase`].
+/// Deserialization always supports lower- and uppercase characters, even mixed in one string.
+///
+/// # Example
+///
+/// ```rust
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// # use serde_with::serde_as;
+/// #
+/// #[serde_as]
+/// # #[derive(Debug, PartialEq, Eq)]
+/// #[derive(Deserialize, Serialize)]
+/// struct BytesLowercase(
+/// // Equivalent to serde_with::hex::Hex<serde_with::formats::Lowercase>
+/// #[serde_as(as = "serde_with::hex::Hex")]
+/// Vec<u8>
+/// );
+///
+/// #[serde_as]
+/// # #[derive(Debug, PartialEq, Eq)]
+/// #[derive(Deserialize, Serialize)]
+/// struct BytesUppercase(
+/// #[serde_as(as = "serde_with::hex::Hex<serde_with::formats::Uppercase>")]
+/// Vec<u8>
+/// );
+///
+/// let b = b"Hello World!";
+///
+/// // Hex with lowercase letters
+/// assert_eq!(
+/// json!("48656c6c6f20576f726c6421"),
+/// serde_json::to_value(BytesLowercase(b.to_vec())).unwrap()
+/// );
+/// // Hex with uppercase letters
+/// assert_eq!(
+/// json!("48656C6C6F20576F726C6421"),
+/// serde_json::to_value(BytesUppercase(b.to_vec())).unwrap()
+/// );
+///
+/// // Serialization always work from lower- and uppercase characters, even mixed case.
+/// assert_eq!(
+/// BytesLowercase(vec![0x00, 0xaa, 0xbc, 0x99, 0xff]),
+/// serde_json::from_value(json!("00aAbc99FF")).unwrap()
+/// );
+/// assert_eq!(
+/// BytesUppercase(vec![0x00, 0xaa, 0xbc, 0x99, 0xff]),
+/// serde_json::from_value(json!("00aAbc99FF")).unwrap()
+/// );
+///
+/// #[serde_as]
+/// # #[derive(Debug, PartialEq, Eq)]
+/// #[derive(Deserialize, Serialize)]
+/// struct ByteArray(
+/// // Equivalent to serde_with::hex::Hex<serde_with::formats::Lowercase>
+/// #[serde_as(as = "serde_with::hex::Hex")]
+/// [u8; 12]
+/// );
+///
+/// let b = b"Hello World!";
+///
+/// assert_eq!(
+/// json!("48656c6c6f20576f726c6421"),
+/// serde_json::to_value(ByteArray(b.clone())).unwrap()
+/// );
+///
+/// // Serialization always work from lower- and uppercase characters, even mixed case.
+/// assert_eq!(
+/// ByteArray([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0xaa, 0xbc, 0x99, 0xff]),
+/// serde_json::from_value(json!("0011223344556677aAbc99FF")).unwrap()
+/// );
+///
+/// // Remember that the conversion may fail. (The following errors are specific to fixed-size arrays)
+/// let error_result: Result<ByteArray, _> = serde_json::from_value(json!("42")); // Too short
+/// error_result.unwrap_err();
+///
+/// let error_result: Result<ByteArray, _> =
+/// serde_json::from_value(json!("000000000000000000000000000000")); // Too long
+/// error_result.unwrap_err();
+/// # }
+/// ```
+pub struct Hex<FORMAT: formats::Format = formats::Lowercase>(PhantomData<FORMAT>);
+
+impl<T> SerializeAs<T> for Hex<formats::Lowercase>
+where
+ T: AsRef<[u8]>,
+{
+ fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serializer.serialize_str(&::hex::encode(source))
+ }
+}
+
+impl<T> SerializeAs<T> for Hex<formats::Uppercase>
+where
+ T: AsRef<[u8]>,
+{
+ fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serializer.serialize_str(&::hex::encode_upper(source))
+ }
+}
+
+impl<'de, T, FORMAT> DeserializeAs<'de, T> for Hex<FORMAT>
+where
+ T: TryFrom<Vec<u8>>,
+ FORMAT: formats::Format,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ <Cow<'de, str> as Deserialize<'de>>::deserialize(deserializer)
+ .and_then(|s| ::hex::decode(&*s).map_err(DeError::custom))
+ .and_then(|vec: Vec<u8>| {
+ let length = vec.len();
+ vec.try_into().map_err(|_e: T::Error| {
+ DeError::custom(format_args!(
+ "Can't convert a Byte Vector of length {length} to the output type."
+ ))
+ })
+ })
+ }
+}
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..5a192e1b33
--- /dev/null
+++ b/third_party/rust/serde_with/src/json.rs
@@ -0,0 +1,121 @@
+//! De/Serialization of JSON
+//!
+//! This modules is only available when using the `json` feature of the crate.
+
+use crate::prelude::*;
+
+/// Serialize value as string containing JSON
+///
+/// *Note*: This type is not necessary for normal usage of serde with JSON.
+/// It is only required if the serialized format contains a string, which itself contains JSON.
+///
+/// # Errors
+///
+/// Serialization can fail if `T`'s implementation of `Serialize` decides to
+/// fail, or if `T` contains a map with non-string keys.
+///
+/// # Examples
+///
+/// ```
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_with::{serde_as, json::JsonString};
+/// #
+/// #[serde_as]
+/// #[derive(Deserialize, Serialize)]
+/// struct A {
+/// #[serde_as(as = "JsonString")]
+/// 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()
+/// );
+/// # }
+/// ```
+///
+/// The `JsonString` converter takes a type argument, which allows altering the serialization behavior of the inner value, before it gets turned into a JSON string.
+///
+/// ```
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_with::{serde_as, json::JsonString};
+/// # use std::collections::BTreeMap;
+/// #
+/// #[serde_as]
+/// #[derive(Debug, Serialize, Deserialize, PartialEq)]
+/// struct Struct {
+/// #[serde_as(as = "JsonString<Vec<(JsonString, _)>>")]
+/// value: BTreeMap<[u8; 2], u32>,
+/// }
+///
+/// let value = Struct {
+/// value: BTreeMap::from([([1, 2], 3), ([4, 5], 6)]),
+/// };
+/// assert_eq!(
+/// r#"{"value":"[[\"[1,2]\",3],[\"[4,5]\",6]]"}"#,
+/// serde_json::to_string(&value).unwrap()
+/// );
+/// # }
+/// ```
+pub struct JsonString<T = Same>(PhantomData<T>);
+
+impl<T, TAs> SerializeAs<T> for JsonString<TAs>
+where
+ TAs: SerializeAs<T>,
+{
+ fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serializer.serialize_str(
+ &serde_json::to_string(&SerializeAsWrap::<T, TAs>::new(source))
+ .map_err(SerError::custom)?,
+ )
+ }
+}
+
+impl<'de, T, TAs> DeserializeAs<'de, T> for JsonString<TAs>
+where
+ TAs: for<'a> DeserializeAs<'a, T>,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct Helper<S, SAs>(PhantomData<(S, SAs)>);
+
+ impl<'de, S, SAs> Visitor<'de> for Helper<S, SAs>
+ where
+ SAs: for<'a> DeserializeAs<'a, S>,
+ {
+ type Value = S;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("valid json object")
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<S, E>
+ where
+ E: DeError,
+ {
+ serde_json::from_str(value)
+ .map(DeserializeAsWrap::<S, SAs>::into_inner)
+ .map_err(DeError::custom)
+ }
+ }
+
+ deserializer.deserialize_str(Helper::<T, TAs>(PhantomData))
+ }
+}
diff --git a/third_party/rust/serde_with/src/key_value_map.rs b/third_party/rust/serde_with/src/key_value_map.rs
new file mode 100644
index 0000000000..67d9232b1b
--- /dev/null
+++ b/third_party/rust/serde_with/src/key_value_map.rs
@@ -0,0 +1,1298 @@
+use crate::{
+ content::{
+ de::{Content as DeContent, ContentDeserializer},
+ ser::{Content as SerContent, ContentSerializer},
+ },
+ prelude::*,
+};
+
+/// Convert `Vec` elements into key-value map entries
+///
+/// This maps a single struct/tuple/etc. to a map entry.
+/// The map key is converted to a struct field.
+/// The other values will be mapped to the map value.
+///
+/// The conversion supports structs, tuple structs, tuples, maps, and sequences.
+/// Structs need a field that is named `$key$` to be used as the map key.
+/// This can be done with the `#[serde(rename = "$key$")]` attribute.
+/// Maps similarly need a map-key that is named `$key$`.
+/// For tuples, tuple structs, and sequences the first element is used as the map key.
+///
+/// # Examples
+///
+/// ## Struct with String key in JSON
+///
+/// ```rust
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// use serde_with::{serde_as, KeyValueMap};
+///
+/// # #[derive(Debug, Clone, PartialEq, Eq)]
+/// #[derive(Serialize, Deserialize)]
+/// struct SimpleStruct {
+/// b: bool,
+/// // The field named `$key$` will become the map key
+/// #[serde(rename = "$key$")]
+/// id: String,
+/// i: i32,
+/// }
+///
+/// #[serde_as]
+/// # #[derive(Debug, Clone, PartialEq, Eq)]
+/// #[derive(Serialize, Deserialize)]
+/// struct KVMap(
+/// #[serde_as(as = "KeyValueMap<_>")]
+/// Vec<SimpleStruct>,
+/// );
+///
+/// // ---
+///
+/// // This will serialize this list of values
+/// let values = KVMap(vec![
+/// SimpleStruct {
+/// b: false,
+/// id: "id-0000".to_string(),
+/// i: 123,
+/// },
+/// SimpleStruct {
+/// b: true,
+/// id: "id-0001".to_string(),
+/// i: 555,
+/// },
+/// SimpleStruct {
+/// b: false,
+/// id: "id-0002".to_string(),
+/// i: 987,
+/// },
+/// ]);
+///
+/// // into this JSON map
+/// let expected =
+/// r#"{
+/// "id-0000": {
+/// "b": false,
+/// "i": 123
+/// },
+/// "id-0001": {
+/// "b": true,
+/// "i": 555
+/// },
+/// "id-0002": {
+/// "b": false,
+/// "i": 987
+/// }
+/// }"#;
+///
+/// // Both serialization and deserialization work flawlessly.
+/// let serialized = serde_json::to_string_pretty(&values).unwrap();
+/// assert_eq!(expected, serialized);
+/// let deserialized: KVMap = serde_json::from_str(&serialized).unwrap();
+/// assert_eq!(values, deserialized);
+/// # }
+/// ```
+///
+/// ## Tuple struct with complex key in YAML
+///
+/// ```rust
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// use serde_with::{serde_as, KeyValueMap};
+/// use std::net::IpAddr;
+/// # use std::str::FromStr;
+///
+/// # #[derive(Debug, Clone, PartialEq, Eq)]
+/// #[derive(Serialize, Deserialize)]
+/// struct TupleStruct (
+/// // The first element in a tuple struct, tuple, or sequence becomes the map key
+/// (IpAddr, u8),
+/// bool,
+/// );
+///
+/// #[serde_as]
+/// # #[derive(Debug, Clone, PartialEq, Eq)]
+/// #[derive(Serialize, Deserialize)]
+/// struct KVMap(
+/// #[serde_as(as = "KeyValueMap<_>")]
+/// Vec<TupleStruct>,
+/// );
+///
+/// // ---
+///
+/// // This will serialize this list of values
+/// let values = KVMap(vec![
+/// TupleStruct(
+/// (IpAddr::from_str("127.0.0.1").unwrap(), 8),
+/// true
+/// ),
+/// TupleStruct(
+/// (IpAddr::from_str("::1").unwrap(), 128),
+/// true
+/// ),
+/// TupleStruct(
+/// (IpAddr::from_str("198.51.100.0").unwrap(), 24),
+/// true
+/// ),
+/// ]);
+///
+/// // into this YAML
+/// let expected =
+/// r#"? - 127.0.0.1
+/// - 8
+/// : - true
+/// ? - ::1
+/// - 128
+/// : - true
+/// ? - 198.51.100.0
+/// - 24
+/// : - true
+/// "#;
+///
+/// // Both serialization and deserialization work flawlessly.
+/// let serialized = serde_yaml::to_string(&values).unwrap();
+/// assert_eq!(expected, serialized);
+/// let deserialized: KVMap = serde_yaml::from_str(&serialized).unwrap();
+/// assert_eq!(values, deserialized);
+/// # }
+/// ```
+pub struct KeyValueMap<T>(PhantomData<T>);
+
+impl<T, TAs> SerializeAs<Vec<T>> for KeyValueMap<TAs>
+where
+ TAs: SerializeAs<T>,
+{
+ fn serialize_as<S>(source: &Vec<T>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ <Vec<TAs>>::serialize_as(source, SeqAsMapSerializer(serializer))
+ }
+}
+
+impl<'de, T, TAs> DeserializeAs<'de, Vec<T>> for KeyValueMap<TAs>
+where
+ TAs: DeserializeAs<'de, T>,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<Vec<T>, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct KeyValueMapVisitor<T, TAs> {
+ is_human_readable: bool,
+ phantom: PhantomData<(T, TAs)>,
+ }
+
+ impl<'de, T, TAs> Visitor<'de> for KeyValueMapVisitor<T, TAs>
+ where
+ TAs: DeserializeAs<'de, T>,
+ {
+ type Value = Vec<T>;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(formatter, "a map")
+ }
+
+ fn visit_map<A: MapAccess<'de>>(self, map: A) -> Result<Self::Value, A::Error> {
+ <Vec<TAs>>::deserialize_as(SeqDeserializer {
+ delegate: map,
+ is_human_readable: self.is_human_readable,
+ })
+ }
+ }
+
+ let is_human_readable = deserializer.is_human_readable();
+ deserializer.deserialize_map(KeyValueMapVisitor::<T, TAs> {
+ is_human_readable,
+ phantom: PhantomData,
+ })
+ }
+}
+
+// TODO Replace this with a const generic string once adt_const_params is stable.
+// This will allow something like this.
+// The `"id"` part is the field name, which gets converted to/from the map key.
+// #[serde_as(as = r#"KeyValueMap<"id", _>"#)]
+// Vec<SimpleStruct>,
+static MAP_KEY_IDENTIFIER: &str = "$key$";
+
+/// Convert a sequence to a map during serialization.
+///
+/// Only `serialize_seq` is implemented and forwarded to `serialize_map` on the inner `Serializer`.
+/// The elements are serialized with [`SerializeSeqElement`].
+struct SeqAsMapSerializer<S>(S);
+
+impl<S> Serializer for SeqAsMapSerializer<S>
+where
+ S: Serializer,
+{
+ type Ok = S::Ok;
+ type Error = S::Error;
+
+ type SerializeSeq = SerializeSeqElement<S::SerializeMap>;
+ type SerializeTuple = Impossible<S::Ok, S::Error>;
+ type SerializeTupleStruct = Impossible<S::Ok, S::Error>;
+ type SerializeTupleVariant = Impossible<S::Ok, S::Error>;
+ type SerializeMap = Impossible<S::Ok, S::Error>;
+ type SerializeStruct = Impossible<S::Ok, S::Error>;
+ type SerializeStructVariant = Impossible<S::Ok, S::Error>;
+
+ fn is_human_readable(&self) -> bool {
+ self.0.is_human_readable()
+ }
+
+ fn serialize_bool(self, _v: bool) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_i8(self, _v: i8) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_i16(self, _v: i16) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_i32(self, _v: i32) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_i64(self, _v: i64) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_i128(self, _v: i128) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_u8(self, _v: u8) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_u16(self, _v: u16) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_u32(self, _v: u32) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_u64(self, _v: u64) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_u128(self, _v: u128) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_f32(self, _v: f32) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_f64(self, _v: f64) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_char(self, _v: char) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_str(self, _v: &str) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_bytes(self, _v: &[u8]) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<Self::Ok, Self::Error>
+ where
+ T: Serialize,
+ {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_unit_variant(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ ) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_newtype_struct<T: ?Sized>(
+ self,
+ _name: &'static str,
+ _value: &T,
+ ) -> Result<Self::Ok, Self::Error>
+ where
+ T: Serialize,
+ {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_newtype_variant<T: ?Sized>(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ _value: &T,
+ ) -> Result<Self::Ok, Self::Error>
+ where
+ T: Serialize,
+ {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
+ let is_human_readable = self.0.is_human_readable();
+ self.0
+ .serialize_map(len)
+ .map(|delegate| SerializeSeqElement {
+ delegate,
+ is_human_readable,
+ })
+ }
+
+ fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_tuple_struct(
+ self,
+ _name: &'static str,
+ _len: usize,
+ ) -> Result<Self::SerializeTupleStruct, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_tuple_variant(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ _len: usize,
+ ) -> Result<Self::SerializeTupleVariant, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_struct(
+ self,
+ _name: &'static str,
+ _len: usize,
+ ) -> Result<Self::SerializeStruct, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_struct_variant(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ _len: usize,
+ ) -> Result<Self::SerializeStructVariant, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+}
+
+/// Serialize a single element but turn the sequence into a map logic.
+///
+/// It uses [`ElementAsKeyValueSerializer`] for the map element serialization.
+///
+/// The [`Serializer`] implementation handles `serialize_struct`, `serialize_map` and `serialize_seq` functions by deferring the work to [`SerializeStruct`], [`SerializeMap`] and [`SerializeSeq`] respectively.
+
+struct SerializeSeqElement<M> {
+ delegate: M,
+ is_human_readable: bool,
+}
+
+impl<M> SerializeSeq for SerializeSeqElement<M>
+where
+ M: SerializeMap,
+{
+ type Ok = M::Ok;
+ type Error = M::Error;
+
+ fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
+ where
+ T: Serialize,
+ {
+ value.serialize(ElementAsKeyValueSerializer {
+ delegate: &mut self.delegate,
+ is_human_readable: self.is_human_readable,
+ })?;
+ Ok(())
+ }
+
+ fn end(self) -> Result<Self::Ok, Self::Error> {
+ self.delegate.end()
+ }
+}
+
+struct ElementAsKeyValueSerializer<'a, M> {
+ delegate: &'a mut M,
+ is_human_readable: bool,
+}
+
+impl<'a, M> Serializer for ElementAsKeyValueSerializer<'a, M>
+where
+ M: SerializeMap,
+{
+ type Ok = ();
+ type Error = M::Error;
+
+ type SerializeSeq = KeyValueSeqSerializer<'a, M>;
+ type SerializeTuple = KeyValueTupleSerializer<'a, M>;
+ type SerializeTupleStruct = KeyValueTupleStructSerializer<'a, M>;
+ type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
+ type SerializeMap = KeyValueMapSerializer<'a, M>;
+ type SerializeStruct = KeyValueStructSerializer<'a, M>;
+ type SerializeStructVariant = Impossible<Self::Ok, Self::Error>;
+
+ fn is_human_readable(&self) -> bool {
+ self.is_human_readable
+ }
+
+ fn serialize_bool(self, _v: bool) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_i8(self, _v: i8) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_i16(self, _v: i16) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_i32(self, _v: i32) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_i64(self, _v: i64) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_i128(self, _v: i128) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_u8(self, _v: u8) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_u16(self, _v: u16) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_u32(self, _v: u32) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_u64(self, _v: u64) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_u128(self, _v: u128) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_f32(self, _v: f32) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_f64(self, _v: f64) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_char(self, _v: char) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_str(self, _v: &str) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_bytes(self, _v: &[u8]) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<Self::Ok, Self::Error>
+ where
+ T: Serialize,
+ {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_unit_variant(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ ) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_newtype_struct<T: ?Sized>(
+ self,
+ _name: &'static str,
+ _value: &T,
+ ) -> Result<Self::Ok, Self::Error>
+ where
+ T: Serialize,
+ {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_newtype_variant<T: ?Sized>(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ _value: &T,
+ ) -> Result<Self::Ok, Self::Error>
+ where
+ T: Serialize,
+ {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
+ Ok(KeyValueSeqSerializer {
+ delegate: self.delegate,
+ is_human_readable: self.is_human_readable,
+ content: Vec::with_capacity(len.unwrap_or(17) - 1),
+ key: None,
+ })
+ }
+
+ fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
+ Ok(KeyValueTupleSerializer {
+ delegate: self.delegate,
+ is_human_readable: self.is_human_readable,
+ content: Vec::with_capacity(len - 1),
+ key: None,
+ })
+ }
+
+ fn serialize_tuple_struct(
+ self,
+ name: &'static str,
+ len: usize,
+ ) -> Result<Self::SerializeTupleStruct, Self::Error> {
+ Ok(KeyValueTupleStructSerializer {
+ delegate: self.delegate,
+ is_human_readable: self.is_human_readable,
+ name,
+ content: Vec::with_capacity(len - 1),
+ key: None,
+ })
+ }
+
+ fn serialize_tuple_variant(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ _len: usize,
+ ) -> Result<Self::SerializeTupleVariant, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+
+ fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
+ Ok(KeyValueMapSerializer {
+ delegate: self.delegate,
+ is_human_readable: self.is_human_readable,
+ content: Vec::with_capacity(len.unwrap_or(17) - 1),
+ next_is_magic_key: false,
+ key: None,
+ tmp: None,
+ })
+ }
+
+ fn serialize_struct(
+ self,
+ name: &'static str,
+ len: usize,
+ ) -> Result<Self::SerializeStruct, Self::Error> {
+ Ok(KeyValueStructSerializer {
+ delegate: self.delegate,
+ is_human_readable: self.is_human_readable,
+ name,
+ content: Vec::with_capacity(len - 1),
+ key: None,
+ })
+ }
+
+ fn serialize_struct_variant(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ _len: usize,
+ ) -> Result<Self::SerializeStructVariant, Self::Error> {
+ Err(SerError::custom("wrong type for KeyValueMap"))
+ }
+}
+
+/// Serialize a sequence to a key and value pair of a map.
+///
+/// This requires that the sequence has at least one element.
+struct KeyValueSeqSerializer<'a, M> {
+ delegate: &'a mut M,
+ is_human_readable: bool,
+ content: Vec<SerContent>,
+ key: Option<SerContent>,
+}
+
+impl<'a, M> SerializeSeq for KeyValueSeqSerializer<'a, M>
+where
+ M: SerializeMap,
+{
+ type Ok = ();
+ type Error = M::Error;
+
+ fn serialize_element<T: ?Sized>(&mut self, element: &T) -> Result<(), Self::Error>
+ where
+ T: Serialize,
+ {
+ let element: SerContent =
+ element.serialize(ContentSerializer::new(self.is_human_readable))?;
+ if self.key.is_none() {
+ self.key = Some(element);
+ return Ok(());
+ }
+ self.content.push(element);
+ Ok(())
+ }
+
+ fn end(self) -> Result<Self::Ok, Self::Error> {
+ if let Some(key) = self.key {
+ self.delegate
+ .serialize_entry(&key, &SerContent::Seq(self.content))
+ } else {
+ Err(SerError::custom("TODO, missing value for `$key$` field"))
+ }
+ }
+}
+
+/// Serialize a tuple to a key and value pair of a map.
+///
+/// This requires that the tuple has at least one element.
+struct KeyValueTupleSerializer<'a, M> {
+ delegate: &'a mut M,
+ is_human_readable: bool,
+ content: Vec<SerContent>,
+ key: Option<SerContent>,
+}
+
+impl<'a, M> SerializeTuple for KeyValueTupleSerializer<'a, M>
+where
+ M: SerializeMap,
+{
+ type Ok = ();
+ type Error = M::Error;
+
+ fn serialize_element<T: ?Sized>(&mut self, element: &T) -> Result<(), Self::Error>
+ where
+ T: Serialize,
+ {
+ let element: SerContent =
+ element.serialize(ContentSerializer::new(self.is_human_readable))?;
+ if self.key.is_none() {
+ self.key = Some(element);
+ return Ok(());
+ }
+ self.content.push(element);
+ Ok(())
+ }
+
+ fn end(self) -> Result<Self::Ok, Self::Error> {
+ if let Some(key) = self.key {
+ self.delegate
+ .serialize_entry(&key, &SerContent::Tuple(self.content))
+ } else {
+ Err(SerError::custom("TODO, missing value for `$key$` field"))
+ }
+ }
+}
+
+/// Serialize a tuple struct to a key and value pair of a map.
+///
+/// This requires that the tuple struct has at least one element.
+struct KeyValueTupleStructSerializer<'a, M> {
+ delegate: &'a mut M,
+ is_human_readable: bool,
+ name: &'static str,
+ content: Vec<SerContent>,
+ key: Option<SerContent>,
+}
+
+impl<'a, M> SerializeTupleStruct for KeyValueTupleStructSerializer<'a, M>
+where
+ M: SerializeMap,
+{
+ type Ok = ();
+ type Error = M::Error;
+
+ fn serialize_field<T: ?Sized>(&mut self, field: &T) -> Result<(), Self::Error>
+ where
+ T: Serialize,
+ {
+ let field: SerContent = field.serialize(ContentSerializer::new(self.is_human_readable))?;
+ if self.key.is_none() {
+ self.key = Some(field);
+ return Ok(());
+ }
+ self.content.push(field);
+ Ok(())
+ }
+
+ fn end(self) -> Result<Self::Ok, Self::Error> {
+ if let Some(key) = self.key {
+ self.delegate
+ .serialize_entry(&key, &SerContent::TupleStruct(self.name, self.content))
+ } else {
+ Err(SerError::custom("TODO, missing value for `$key$` field"))
+ }
+ }
+}
+
+/// Serialize a map to a key and value pair of a map.
+///
+/// This requires that the map has one element which serializes using the magic `$key$` key.
+struct KeyValueMapSerializer<'a, M> {
+ delegate: &'a mut M,
+ is_human_readable: bool,
+ content: Vec<(SerContent, SerContent)>,
+ next_is_magic_key: bool,
+ key: Option<SerContent>,
+ tmp: Option<SerContent>,
+}
+
+impl<'a, M> SerializeMap for KeyValueMapSerializer<'a, M>
+where
+ M: SerializeMap,
+{
+ type Ok = ();
+ type Error = M::Error;
+
+ fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Self::Error>
+ where
+ T: Serialize,
+ {
+ let key: SerContent = key.serialize(ContentSerializer::new(self.is_human_readable))?;
+ if key.as_str() == Some(MAP_KEY_IDENTIFIER) {
+ self.next_is_magic_key = true;
+ return Ok(());
+ }
+ self.tmp = Some(key);
+ Ok(())
+ }
+
+ fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
+ where
+ T: Serialize,
+ {
+ let value: SerContent = value.serialize(ContentSerializer::new(self.is_human_readable))?;
+
+ if self.next_is_magic_key {
+ self.next_is_magic_key = false;
+ self.key = Some(value);
+ return Ok(());
+ }
+ self.content.push((
+ self.tmp
+ .take()
+ .expect("serialize_value called before serialize_key"),
+ value,
+ ));
+ Ok(())
+ }
+
+ fn end(self) -> Result<Self::Ok, Self::Error> {
+ if let Some(key) = self.key {
+ self.delegate
+ .serialize_entry(&key, &SerContent::Map(self.content))
+ } else {
+ Err(SerError::custom("TODO, missing value for `$key$` field"))
+ }
+ }
+}
+
+/// Serialize a struct to a key and value pair of a map.
+///
+/// This requires that the struct has one field named `$key$`.
+struct KeyValueStructSerializer<'a, M> {
+ delegate: &'a mut M,
+ is_human_readable: bool,
+ name: &'static str,
+ content: Vec<(&'static str, SerContent)>,
+ key: Option<SerContent>,
+}
+
+impl<'a, M> SerializeStruct for KeyValueStructSerializer<'a, M>
+where
+ M: SerializeMap,
+{
+ type Ok = ();
+ type Error = M::Error;
+
+ fn serialize_field<T: ?Sized>(
+ &mut self,
+ key: &'static str,
+ value: &T,
+ ) -> Result<(), Self::Error>
+ where
+ T: Serialize,
+ {
+ // Serialize to a Content type first
+ let value: SerContent = value.serialize(ContentSerializer::new(self.is_human_readable))?;
+
+ if key == MAP_KEY_IDENTIFIER {
+ self.key = Some(value);
+ return Ok(());
+ }
+ self.content.push((key, value));
+ Ok(())
+ }
+
+ fn end(self) -> Result<Self::Ok, Self::Error> {
+ if let Some(key) = self.key {
+ self.delegate
+ .serialize_entry(&key, &SerContent::Struct(self.name, self.content))
+ } else {
+ Err(SerError::custom("TODO, missing value for `key` field"))
+ }
+ }
+}
+
+// Below is deserialization code
+
+/// Deserialize the sequence of enum instances.
+///
+/// The main [`Deserializer`] implementation handles the outer sequence (e.g., `Vec`), while the [`SeqAccess`] implementation is responsible for the inner elements.
+struct SeqDeserializer<M> {
+ delegate: M,
+ is_human_readable: bool,
+}
+
+impl<'de, M> Deserializer<'de> for SeqDeserializer<M>
+where
+ M: MapAccess<'de>,
+{
+ type Error = M::Error;
+
+ fn is_human_readable(&self) -> bool {
+ self.is_human_readable
+ }
+
+ fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_seq(self)
+ }
+
+ fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_seq(visitor)
+ }
+
+ serde::forward_to_deserialize_any! {
+ bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
+ bytes byte_buf option unit unit_struct newtype_struct tuple
+ tuple_struct map struct enum identifier ignored_any
+ }
+}
+
+impl<'de, M> SeqAccess<'de> for SeqDeserializer<M>
+where
+ M: MapAccess<'de>,
+{
+ type Error = M::Error;
+
+ fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
+ where
+ T: DeserializeSeed<'de>,
+ {
+ let key_value: Option<DeContent<'de>> = self.delegate.next_key()?;
+ if let Some(key_value) = key_value {
+ seed.deserialize(MapKeyDeserializer {
+ delegate: &mut self.delegate,
+ is_human_readable: self.is_human_readable,
+ key_value,
+ })
+ .map(Some)
+ } else {
+ Ok(None)
+ }
+ }
+
+ fn size_hint(&self) -> Option<usize> {
+ self.delegate.size_hint()
+ }
+}
+
+struct MapKeyDeserializer<'de, M> {
+ delegate: M,
+ is_human_readable: bool,
+ key_value: DeContent<'de>,
+}
+
+impl<'de, M> Deserializer<'de> for MapKeyDeserializer<'de, M>
+where
+ M: MapAccess<'de>,
+{
+ type Error = M::Error;
+
+ fn is_human_readable(&self) -> bool {
+ self.is_human_readable
+ }
+
+ fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_map(visitor)
+ }
+
+ fn deserialize_seq<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.delegate.next_value_seed(KeyValueSeqDeserialize {
+ delegate: visitor,
+ first: Some(self.key_value),
+ })
+ }
+
+ fn deserialize_tuple<V>(mut self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.delegate.next_value_seed(KeyValueTupleDeserialize {
+ delegate: visitor,
+ len,
+ first: Some(self.key_value),
+ })
+ }
+
+ fn deserialize_tuple_struct<V>(
+ mut self,
+ name: &'static str,
+ len: usize,
+ visitor: V,
+ ) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.delegate
+ .next_value_seed(KeyValueTupleStructDeserialize {
+ delegate: visitor,
+ name,
+ len,
+ first: Some(self.key_value),
+ })
+ }
+
+ fn deserialize_map<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.delegate.next_value_seed(KeyValueMapDeserialize {
+ delegate: visitor,
+ first: Some(self.key_value),
+ })
+ }
+
+ fn deserialize_struct<V>(
+ mut self,
+ name: &'static str,
+ fields: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.delegate.next_value_seed(KeyValueStructDeserialize {
+ delegate: visitor,
+ name,
+ fields,
+ first: Some(self.key_value),
+ })
+ }
+
+ serde::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
+ enum identifier ignored_any
+ }
+}
+
+struct KeyValueSeqDeserialize<'de, V> {
+ delegate: V,
+ first: Option<DeContent<'de>>,
+}
+
+impl<'de, V> DeserializeSeed<'de> for KeyValueSeqDeserialize<'de, V>
+where
+ V: Visitor<'de>,
+{
+ type Value = V::Value;
+
+ fn deserialize<D>(mut self, deserializer: D) -> Result<Self::Value, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let is_human_readable = deserializer.is_human_readable();
+ deserializer.deserialize_seq(VisitorWrapper {
+ delegate: self.delegate,
+ is_human_readable,
+ first: self.first.take(),
+ })
+ }
+}
+
+struct KeyValueTupleDeserialize<'de, V> {
+ delegate: V,
+ len: usize,
+ first: Option<DeContent<'de>>,
+}
+
+impl<'de, V> DeserializeSeed<'de> for KeyValueTupleDeserialize<'de, V>
+where
+ V: Visitor<'de>,
+{
+ type Value = V::Value;
+
+ fn deserialize<D>(mut self, deserializer: D) -> Result<Self::Value, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let is_human_readable = deserializer.is_human_readable();
+ deserializer.deserialize_tuple(
+ self.len,
+ VisitorWrapper {
+ delegate: self.delegate,
+ is_human_readable,
+ first: self.first.take(),
+ },
+ )
+ }
+}
+
+struct KeyValueTupleStructDeserialize<'de, V> {
+ delegate: V,
+ name: &'static str,
+ len: usize,
+ first: Option<DeContent<'de>>,
+}
+
+impl<'de, V> DeserializeSeed<'de> for KeyValueTupleStructDeserialize<'de, V>
+where
+ V: Visitor<'de>,
+{
+ type Value = V::Value;
+
+ fn deserialize<D>(mut self, deserializer: D) -> Result<Self::Value, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let is_human_readable = deserializer.is_human_readable();
+ deserializer.deserialize_tuple_struct(
+ self.name,
+ self.len,
+ VisitorWrapper {
+ delegate: self.delegate,
+ is_human_readable,
+ first: self.first.take(),
+ },
+ )
+ }
+}
+
+struct KeyValueMapDeserialize<'de, V> {
+ delegate: V,
+ first: Option<DeContent<'de>>,
+}
+
+impl<'de, V> DeserializeSeed<'de> for KeyValueMapDeserialize<'de, V>
+where
+ V: Visitor<'de>,
+{
+ type Value = V::Value;
+
+ fn deserialize<D>(mut self, deserializer: D) -> Result<Self::Value, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let is_human_readable = deserializer.is_human_readable();
+ deserializer.deserialize_map(VisitorWrapper {
+ delegate: self.delegate,
+ is_human_readable,
+ first: self.first.take(),
+ })
+ }
+}
+
+struct KeyValueStructDeserialize<'de, V> {
+ delegate: V,
+ name: &'static str,
+ fields: &'static [&'static str],
+ first: Option<DeContent<'de>>,
+}
+
+impl<'de, V> DeserializeSeed<'de> for KeyValueStructDeserialize<'de, V>
+where
+ V: Visitor<'de>,
+{
+ type Value = V::Value;
+
+ fn deserialize<D>(mut self, deserializer: D) -> Result<Self::Value, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let is_human_readable = deserializer.is_human_readable();
+ deserializer.deserialize_struct(
+ self.name,
+ self.fields,
+ VisitorWrapper {
+ delegate: self.delegate,
+ is_human_readable,
+ first: self.first.take(),
+ },
+ )
+ }
+}
+
+struct VisitorWrapper<'de, V> {
+ delegate: V,
+ is_human_readable: bool,
+ first: Option<DeContent<'de>>,
+}
+
+impl<'de, V> Visitor<'de> for VisitorWrapper<'de, 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(MapAccessWrapper {
+ delegate: map,
+ is_human_readable: self.is_human_readable,
+ first: self.first,
+ })
+ }
+
+ fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
+ where
+ A: SeqAccess<'de>,
+ {
+ self.delegate.visit_seq(SeqAccessWrapper {
+ delegate: seq,
+ is_human_readable: self.is_human_readable,
+ first: self.first,
+ })
+ }
+}
+
+struct MapAccessWrapper<'de, M> {
+ delegate: M,
+ is_human_readable: bool,
+ first: Option<DeContent<'de>>,
+}
+
+impl<'de, M> MapAccess<'de> for MapAccessWrapper<'de, M>
+where
+ M: MapAccess<'de>,
+{
+ type Error = M::Error;
+
+ fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
+ where
+ K: DeserializeSeed<'de>,
+ {
+ if self.first.is_some() {
+ seed.deserialize(serde::de::value::StringDeserializer::new(
+ MAP_KEY_IDENTIFIER.to_string(),
+ ))
+ .map(Some)
+ } else {
+ self.delegate.next_key_seed(seed)
+ }
+ }
+
+ fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
+ where
+ V: DeserializeSeed<'de>,
+ {
+ if let Some(first) = self.first.take() {
+ seed.deserialize(ContentDeserializer::new(first, self.is_human_readable))
+ } else {
+ self.delegate.next_value_seed(seed)
+ }
+ }
+}
+
+struct SeqAccessWrapper<'de, M> {
+ delegate: M,
+ is_human_readable: bool,
+ first: Option<DeContent<'de>>,
+}
+
+impl<'de, S> SeqAccess<'de> for SeqAccessWrapper<'de, S>
+where
+ S: SeqAccess<'de>,
+{
+ type Error = S::Error;
+
+ fn next_element_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
+ where
+ K: DeserializeSeed<'de>,
+ {
+ if let Some(first) = self.first.take() {
+ seed.deserialize(ContentDeserializer::new(first, self.is_human_readable))
+ .map(Some)
+ } else {
+ self.delegate.next_element_seed(seed)
+ }
+ }
+}
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..3add59975a
--- /dev/null
+++ b/third_party/rust/serde_with/src/lib.rs
@@ -0,0 +1,2339 @@
+#![warn(
+ clippy::semicolon_if_nothing_returned,
+ // New clippy lints, not yet stable
+ // clippy::std_instead_of_core,
+ // clippy::std_instead_of_alloc,
+ // clippy::alloc_instead_of_core,
+ missing_docs,
+ rust_2018_idioms,
+ rustdoc::missing_crate_level_docs,
+ trivial_casts,
+ trivial_numeric_casts,
+ unused_extern_crates,
+ unused_import_braces,
+ unused_qualifications,
+ variant_size_differences
+)]
+#![doc(test(attr(forbid(unsafe_code))))]
+#![doc(test(attr(deny(
+ missing_debug_implementations,
+ trivial_casts,
+ trivial_numeric_casts,
+ unused_extern_crates,
+ unused_import_braces,
+ unused_qualifications,
+))))]
+#![doc(test(attr(warn(rust_2018_idioms))))]
+// Not needed for 2018 edition and conflicts with `rust_2018_idioms`
+#![doc(test(no_crate_inject))]
+#![doc(html_root_url = "https://docs.rs/serde_with/3.0.0/")]
+#![cfg_attr(docsrs, feature(doc_cfg))]
+#![allow(
+ // clippy is broken and shows wrong warnings
+ // clippy on stable does not know yet about the lint name
+ unknown_lints,
+ // https://github.com/rust-lang/rust-clippy/issues/8560
+ clippy::only_used_in_recursion,
+ // https://github.com/rust-lang/rust-clippy/issues/8867
+ clippy::derive_partial_eq_without_eq,
+ // https://github.com/rust-lang/rust-clippy/issues/9101
+ clippy::explicit_auto_deref
+)]
+#![no_std]
+
+//! [![crates.io badge](https://img.shields.io/crates/v/serde_with.svg)](https://crates.io/crates/serde_with/)
+//! [![Build Status](https://github.com/jonasbb/serde_with/workflows/Rust%20CI/badge.svg)](https://github.com/jonasbb/serde_with)
+//! [![codecov](https://codecov.io/gh/jonasbb/serde_with/branch/master/graph/badge.svg)](https://codecov.io/gh/jonasbb/serde_with)
+//! [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/4322/badge)](https://bestpractices.coreinfrastructure.org/projects/4322)
+//! [![Rustexplorer](https://img.shields.io/badge/Try%20on-rustexplorer-lightgrey?logo=rust&logoColor=orange)](https://www.rustexplorer.com/b/py7ida)
+//!
+//! ---
+//!
+//! This crate provides custom de/serialization helpers to use in combination with [serde's with-annotation][with-annotation] and with the improved [`serde_as`][as-annotation]-annotation.
+//! Some common use cases are:
+//!
+//! * De/Serializing a type using the `Display` and `FromStr` traits, e.g., for `u8`, `url::Url`, or `mime::Mime`.
+//! Check [`DisplayFromStr`] for details.
+//! * Support for arrays larger than 32 elements or using const generics.
+//! With `serde_as` large arrays are supported, even if they are nested in other types.
+//! `[bool; 64]`, `Option<[u8; M]>`, and `Box<[[u8; 64]; N]>` are all supported, as [this examples shows](#large-and-const-generic-arrays).
+//! * Skip serializing all empty `Option` types with [`#[skip_serializing_none]`][skip_serializing_none].
+//! * Apply a prefix to each field name of a struct, without changing the de/serialize implementations of the struct using [`with_prefix!`][].
+//! * Deserialize a comma separated list like `#hash,#tags,#are,#great` into a `Vec<String>`.
+//! Check the documentation for [`serde_with::StringWithSeparator::<CommaSeparator, T>`][StringWithSeparator].
+//!
+//! ## Getting Help
+//!
+//! **Check out the [user guide][user guide] to find out more tips and tricks about this crate.**
+//!
+//! For further help using this crate you can [open a new discussion](https://github.com/jonasbb/serde_with/discussions/new) or ask on [users.rust-lang.org](https://users.rust-lang.org/).
+//! For bugs, please open a [new issue](https://github.com/jonasbb/serde_with/issues/new) on GitHub.
+//!
+//! # Use `serde_with` in your Project
+//!
+//! ```bash
+//! # Add the current version to your Cargo.toml
+//! cargo add serde_with
+//! ```
+//!
+//! The crate contains different features for integration with other common crates.
+//! Check the [feature flags][] section for information about all available features.
+//!
+//! # Examples
+//!
+//! Annotate your struct or enum to enable the custom de/serializer.
+//! The `#[serde_as]` attribute must be placed *before* the `#[derive]`.
+//!
+//! The `as` is analogous to the `with` attribute of serde.
+//! You mirror the type structure of the field you want to de/serialize.
+//! You can specify converters for the inner types of a field, e.g., `Vec<DisplayFromStr>`.
+//! The default de/serialization behavior can be restored by using `_` as a placeholder, e.g., `BTreeMap<_, DisplayFromStr>`.
+//!
+//! ## `DisplayFromStr`
+//!
+//! [![Rustexplorer](https://img.shields.io/badge/Try%20on-rustexplorer-lightgrey?logo=rust&logoColor=orange)](https://www.rustexplorer.com/b/py7ida)
+//! ```rust
+//! # #[cfg(feature = "macros")]
+//! # use serde::{Deserialize, Serialize};
+//! # #[cfg(feature = "macros")]
+//! # use serde_with::{serde_as, DisplayFromStr};
+//! # #[cfg(feature = "macros")]
+//! #[serde_as]
+//! # #[derive(Debug, Eq, PartialEq)]
+//! #[derive(Deserialize, Serialize)]
+//! struct Foo {
+//! // Serialize with Display, deserialize with FromStr
+//! #[serde_as(as = "DisplayFromStr")]
+//! bar: u8,
+//! }
+//!
+//! # #[cfg(all(feature = "macros", feature = "json"))] {
+//! // This will serialize
+//! # let foo =
+//! Foo {bar: 12}
+//! # ;
+//!
+//! // into this JSON
+//! # let json = r#"
+//! {"bar": "12"}
+//! # "#;
+//! # assert_eq!(json.replace(" ", "").replace("\n", ""), serde_json::to_string(&foo).unwrap());
+//! # assert_eq!(foo, serde_json::from_str(&json).unwrap());
+//! # }
+//! ```
+//!
+//! ## Large and const-generic arrays
+//!
+//! serde does not support arrays with more than 32 elements or using const-generics.
+//! The `serde_as` attribute allows circumventing this restriction, even for nested types and nested arrays.
+//!
+//! On top of it, `[u8; N]` (aka, bytes) can use the specialized `"Bytes"` for efficiency much like the `serde_bytes` crate.
+//!
+//! [![Rustexplorer](https://img.shields.io/badge/Try%20on-rustexplorer-lightgrey?logo=rust&logoColor=orange)](https://www.rustexplorer.com/b/um0xyi)
+//! ```rust
+//! # #[cfg(feature = "macros")]
+//! # use serde::{Deserialize, Serialize};
+//! # #[cfg(feature = "macros")]
+//! # use serde_with::{serde_as, Bytes};
+//! # #[cfg(feature = "macros")]
+//! #[serde_as]
+//! # #[derive(Debug, Eq, PartialEq)]
+//! #[derive(Deserialize, Serialize)]
+//! struct Arrays<const N: usize, const M: usize> {
+//! #[serde_as(as = "[_; N]")]
+//! constgeneric: [bool; N],
+//!
+//! #[serde_as(as = "Box<[[_; 64]; N]>")]
+//! nested: Box<[[u8; 64]; N]>,
+//!
+//! #[serde_as(as = "Option<[_; M]>")]
+//! optional: Option<[u8; M]>,
+//!
+//! #[serde_as(as = "Bytes")]
+//! bytes: [u8; M],
+//! }
+//!
+//! # #[cfg(all(feature = "macros", feature = "json"))] {
+//! // This allows us to serialize a struct like this
+//! let arrays: Arrays<100, 128> = Arrays {
+//! constgeneric: [true; 100],
+//! nested: Box::new([[111; 64]; 100]),
+//! optional: Some([222; 128]),
+//! bytes: [0x42; 128],
+//! };
+//! assert!(serde_json::to_string(&arrays).is_ok());
+//! # }
+//! ```
+//!
+//! ## `skip_serializing_none`
+//!
+//! This situation often occurs with JSON, but other formats also support optional fields.
+//! If many fields are optional, putting the annotations on the structs can become tedious.
+//! The `#[skip_serializing_none]` attribute must be placed *before* the `#[derive]`.
+//!
+//! [![Rustexplorer](https://img.shields.io/badge/Try%20on-rustexplorer-lightgrey?logo=rust&logoColor=orange)](https://www.rustexplorer.com/b/xr1tm0)
+//! ```rust
+//! # #[cfg(feature = "macros")]
+//! # use serde::{Deserialize, Serialize};
+//! # #[cfg(feature = "macros")]
+//! # use serde_with::skip_serializing_none;
+//! # #[cfg(feature = "macros")]
+//! #[skip_serializing_none]
+//! # #[derive(Debug, Eq, PartialEq)]
+//! #[derive(Deserialize, Serialize)]
+//! struct Foo {
+//! a: Option<usize>,
+//! b: Option<usize>,
+//! c: Option<usize>,
+//! d: Option<usize>,
+//! e: Option<usize>,
+//! f: Option<usize>,
+//! g: Option<usize>,
+//! }
+//!
+//! # #[cfg(all(feature = "macros", feature = "json"))] {
+//! // This will serialize
+//! # let foo =
+//! Foo {a: None, b: None, c: None, d: Some(4), e: None, f: None, g: Some(7)}
+//! # ;
+//!
+//! // into this JSON
+//! # let json = r#"
+//! {"d": 4, "g": 7}
+//! # "#;
+//! # assert_eq!(json.replace(" ", "").replace("\n", ""), serde_json::to_string(&foo).unwrap());
+//! # assert_eq!(foo, serde_json::from_str(&json).unwrap());
+//! # }
+//! ```
+//!
+//! ## Advanced `serde_as` usage
+//!
+//! This example is mainly supposed to highlight the flexibility of the `serde_as`-annotation compared to [serde's with-annotation][with-annotation].
+//! More details about `serde_as` can be found in the [user guide].
+//!
+//! ```rust
+//! # #[cfg(all(feature = "macros", feature = "hex"))]
+//! # use {
+//! # serde::{Deserialize, Serialize},
+//! # serde_with::{serde_as, DisplayFromStr, DurationSeconds, hex::Hex, Map},
+//! # };
+//! use std::time::Duration;
+//!
+//! # #[cfg(all(feature = "macros", feature = "hex"))]
+//! #[serde_as]
+//! # #[derive(Debug, Eq, PartialEq)]
+//! #[derive(Deserialize, Serialize)]
+//! enum Foo {
+//! Durations(
+//! // Serialize them into a list of number as seconds
+//! #[serde_as(as = "Vec<DurationSeconds>")]
+//! Vec<Duration>,
+//! ),
+//! Bytes {
+//! // We can treat a Vec like a map with duplicates.
+//! // JSON only allows string keys, so convert i32 to strings
+//! // The bytes will be hex encoded
+//! #[serde_as(as = "Map<DisplayFromStr, Hex>")]
+//! bytes: Vec<(i32, Vec<u8>)>,
+//! }
+//! }
+//!
+//! # #[cfg(all(feature = "macros", feature = "json", feature = "hex"))] {
+//! // This will serialize
+//! # let foo =
+//! Foo::Durations(
+//! vec![Duration::new(5, 0), Duration::new(3600, 0), Duration::new(0, 0)]
+//! )
+//! # ;
+//! // into this JSON
+//! # let json = r#"
+//! {
+//! "Durations": [5, 3600, 0]
+//! }
+//! # "#;
+//! # assert_eq!(json.replace(" ", "").replace("\n", ""), serde_json::to_string(&foo).unwrap());
+//! # assert_eq!(foo, serde_json::from_str(&json).unwrap());
+//!
+//! // and serializes
+//! # let foo =
+//! Foo::Bytes {
+//! bytes: vec![
+//! (1, vec![0, 1, 2]),
+//! (-100, vec![100, 200, 255]),
+//! (1, vec![0, 111, 222]),
+//! ],
+//! }
+//! # ;
+//! // into this JSON
+//! # let json = r#"
+//! {
+//! "Bytes": {
+//! "bytes": {
+//! "1": "000102",
+//! "-100": "64c8ff",
+//! "1": "006fde"
+//! }
+//! }
+//! }
+//! # "#;
+//! # assert_eq!(json.replace(" ", "").replace("\n", ""), serde_json::to_string(&foo).unwrap());
+//! # assert_eq!(foo, serde_json::from_str(&json).unwrap());
+//! # }
+//! ```
+//!
+//! [`DisplayFromStr`]: https://docs.rs/serde_with/3.0.0/serde_with/struct.DisplayFromStr.html
+//! [`with_prefix!`]: https://docs.rs/serde_with/3.0.0/serde_with/macro.with_prefix.html
+//! [feature flags]: https://docs.rs/serde_with/3.0.0/serde_with/guide/feature_flags/index.html
+//! [skip_serializing_none]: https://docs.rs/serde_with/3.0.0/serde_with/attr.skip_serializing_none.html
+//! [StringWithSeparator]: https://docs.rs/serde_with/3.0.0/serde_with/struct.StringWithSeparator.html
+//! [user guide]: https://docs.rs/serde_with/3.0.0/serde_with/guide/index.html
+//! [with-annotation]: https://serde.rs/field-attrs.html#with
+//! [as-annotation]: https://docs.rs/serde_with/3.0.0/serde_with/guide/serde_as/index.html
+
+#[cfg(feature = "alloc")]
+extern crate alloc;
+#[doc(hidden)]
+pub extern crate core;
+#[doc(hidden)]
+pub extern crate serde;
+#[cfg(feature = "std")]
+extern crate std;
+
+#[cfg(feature = "base64")]
+#[cfg_attr(docsrs, doc(cfg(feature = "base64")))]
+pub mod base64;
+#[cfg(feature = "chrono_0_4")]
+#[cfg_attr(docsrs, doc(cfg(feature = "chrono_0_4")))]
+pub mod chrono_0_4;
+/// Legacy export of the [`chrono_0_4`] module.
+#[cfg(feature = "chrono")]
+#[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
+pub mod chrono {
+ pub use chrono_0_4::*;
+}
+#[cfg(feature = "alloc")]
+mod content;
+pub mod de;
+#[cfg(feature = "alloc")]
+mod duplicate_key_impls;
+#[cfg(feature = "alloc")]
+mod enum_map;
+#[cfg(feature = "std")]
+mod flatten_maybe;
+pub mod formats;
+#[cfg(feature = "hex")]
+#[cfg_attr(docsrs, doc(cfg(feature = "hex")))]
+pub mod hex;
+#[cfg(feature = "json")]
+#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
+pub mod json;
+#[cfg(feature = "alloc")]
+mod key_value_map;
+pub mod rust;
+pub mod ser;
+#[cfg(feature = "std")]
+mod serde_conv;
+#[cfg(feature = "time_0_3")]
+#[cfg_attr(docsrs, doc(cfg(feature = "time_0_3")))]
+pub mod time_0_3;
+mod utils;
+#[cfg(feature = "std")]
+#[doc(hidden)]
+pub mod with_prefix;
+
+// Taken from shepmaster/snafu
+// Originally licensed as MIT+Apache 2
+// https://github.com/shepmaster/snafu/blob/fd37d79d4531ed1d3eebffad0d658928eb860cfe/src/lib.rs#L121-L165
+#[cfg(feature = "guide")]
+#[allow(unused_macro_rules)]
+macro_rules! generate_guide {
+ (pub mod $name:ident; $($rest:tt)*) => {
+ generate_guide!(@gen ".", pub mod $name { } $($rest)*);
+ };
+ (pub mod $name:ident { $($children:tt)* } $($rest:tt)*) => {
+ generate_guide!(@gen ".", pub mod $name { $($children)* } $($rest)*);
+ };
+ (@gen $prefix:expr, ) => {};
+ (@gen $prefix:expr, pub mod $name:ident; $($rest:tt)*) => {
+ generate_guide!(@gen $prefix, pub mod $name { } $($rest)*);
+ };
+ (@gen $prefix:expr, @code pub mod $name:ident; $($rest:tt)*) => {
+ pub mod $name;
+ generate_guide!(@gen $prefix, $($rest)*);
+ };
+ (@gen $prefix:expr, pub mod $name:ident { $($children:tt)* } $($rest:tt)*) => {
+ doc_comment::doc_comment! {
+ include_str!(concat!($prefix, "/", stringify!($name), ".md")),
+ pub mod $name {
+ generate_guide!(@gen concat!($prefix, "/", stringify!($name)), $($children)*);
+ }
+ }
+ generate_guide!(@gen $prefix, $($rest)*);
+ };
+}
+
+#[cfg(feature = "guide")]
+generate_guide! {
+ pub mod guide {
+ pub mod feature_flags;
+ pub mod serde_as;
+ pub mod serde_as_transformations;
+ }
+}
+
+pub(crate) mod prelude {
+ #![allow(unused_imports)]
+
+ pub(crate) use crate::utils::duration::{DurationSigned, Sign};
+ pub use crate::{de::*, ser::*, *};
+ #[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
+ pub use alloc::sync::{Arc, Weak as ArcWeak};
+ #[cfg(feature = "alloc")]
+ pub use alloc::{
+ borrow::{Cow, ToOwned},
+ boxed::Box,
+ collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque},
+ rc::{Rc, Weak as RcWeak},
+ string::{String, ToString},
+ vec::Vec,
+ };
+ pub use core::{
+ cell::{Cell, RefCell},
+ convert::{TryFrom, TryInto},
+ fmt::{self, Display},
+ hash::{BuildHasher, Hash},
+ marker::PhantomData,
+ option::Option,
+ result::Result,
+ str::FromStr,
+ time::Duration,
+ };
+ pub use serde::{
+ de::{
+ Deserialize, DeserializeOwned, DeserializeSeed, Deserializer, EnumAccess,
+ Error as DeError, Expected, IgnoredAny, IntoDeserializer, MapAccess, SeqAccess,
+ Unexpected, VariantAccess, Visitor,
+ },
+ forward_to_deserialize_any,
+ ser::{
+ Error as SerError, Impossible, Serialize, SerializeMap, SerializeSeq, SerializeStruct,
+ SerializeStructVariant, SerializeTuple, SerializeTupleStruct, SerializeTupleVariant,
+ Serializer,
+ },
+ };
+ #[cfg(feature = "std")]
+ pub use std::{
+ collections::{HashMap, HashSet},
+ sync::{Mutex, RwLock},
+ time::SystemTime,
+ };
+}
+
+/// This module is not part of the public API
+///
+/// Do not rely on any exports.
+#[doc(hidden)]
+pub mod __private__ {
+ pub use crate::prelude::*;
+}
+
+#[cfg(feature = "alloc")]
+#[doc(inline)]
+pub use crate::enum_map::EnumMap;
+#[cfg(feature = "alloc")]
+#[doc(inline)]
+pub use crate::key_value_map::KeyValueMap;
+#[doc(inline)]
+pub use crate::{de::DeserializeAs, ser::SerializeAs};
+use core::marker::PhantomData;
+// Re-Export all proc_macros, as these should be seen as part of the serde_with crate
+#[cfg(feature = "macros")]
+#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
+#[doc(inline)]
+pub use serde_with_macros::*;
+
+/// Adapter to convert from `serde_as` to the serde traits.
+///
+/// The `As` type adapter allows using types which implement [`DeserializeAs`] or [`SerializeAs`] in place of serde's with-annotation.
+/// The with-annotation allows running custom code when de/serializing, however it is quite inflexible.
+/// The traits [`DeserializeAs`]/[`SerializeAs`] are more flexible, as they allow composition and nesting of types to create more complex de/serialization behavior.
+/// However, they are not directly compatible with serde, as they are not provided by serde.
+/// The `As` type adapter makes them compatible, by forwarding the function calls to `serialize`/`deserialize` to the corresponding functions `serialize_as` and `deserialize_as`.
+///
+/// It is not required to use this type directly.
+/// Instead, it is highly encouraged to use the [`#[serde_as]`][serde_as] attribute since it includes further usability improvements.
+/// If the use of the use of the proc-macro is not acceptable, then `As` can be used directly with serde.
+///
+/// ```rust
+/// # #[cfg(feature = "alloc")] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_with::{As, DisplayFromStr};
+/// #
+/// #[derive(Deserialize, Serialize)]
+/// # struct S {
+/// // Serialize numbers as sequence of strings, using Display and FromStr
+/// #[serde(with = "As::<Vec<DisplayFromStr>>")]
+/// field: Vec<u8>,
+/// # }
+/// # }
+/// ```
+/// If the normal `Deserialize`/`Serialize` traits should be used, the placeholder type [`Same`] can be used.
+/// It implements [`DeserializeAs`][]/[`SerializeAs`][], when the underlying type implements `Deserialize`/`Serialize`.
+///
+/// ```rust
+/// # #[cfg(feature = "alloc")] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_with::{As, DisplayFromStr, Same};
+/// # use std::collections::BTreeMap;
+/// #
+/// #[derive(Deserialize, Serialize)]
+/// # struct S {
+/// // Serialize map, turn keys into strings but keep type of value
+/// #[serde(with = "As::<BTreeMap<DisplayFromStr, Same>>")]
+/// field: BTreeMap<u8, i32>,
+/// # }
+/// # }
+/// ```
+///
+/// [serde_as]: https://docs.rs/serde_with/3.0.0/serde_with/attr.serde_as.html
+pub struct As<T: ?Sized>(PhantomData<T>);
+
+/// Adapter to convert from `serde_as` to the serde traits.
+///
+/// This is the counter-type to [`As`][].
+/// It can be used whenever a type implementing [`DeserializeAs`][]/[`SerializeAs`][] is required but the normal `Deserialize`/`Serialize` traits should be used.
+/// Check [`As`] for an example.
+pub struct Same;
+
+/// De/Serialize using [`Display`] and [`FromStr`] implementation
+///
+/// This allows deserializing 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.
+///
+/// Another use case is types with [`Display`] and [`FromStr`] implementations, but without serde
+/// support, which can be found in some crates.
+///
+/// If you control the type you want to de/serialize, you can instead use the two derive macros, [`SerializeDisplay`] and [`DeserializeFromStr`].
+/// They properly implement the traits [`serde::Serialize`] and [`serde::Deserialize`] such that user of the type no longer have to use the `serde_as` system.
+///
+/// # Examples
+///
+/// ```rust
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// # use serde_with::{serde_as, DisplayFromStr};
+/// #
+/// #[serde_as]
+/// #[derive(Deserialize, Serialize)]
+/// struct A {
+/// #[serde_as(as = "DisplayFromStr")]
+/// mime: mime::Mime,
+/// #[serde_as(as = "DisplayFromStr")]
+/// number: u32,
+/// }
+///
+/// let v: A = serde_json::from_value(json!({
+/// "mime": "text/plain",
+/// "number": "159",
+/// })).unwrap();
+/// assert_eq!(mime::TEXT_PLAIN, v.mime);
+/// assert_eq!(159, v.number);
+///
+/// let x = A {
+/// mime: mime::STAR_STAR,
+/// number: 777,
+/// };
+/// assert_eq!(json!({ "mime": "*/*", "number": "777" }), serde_json::to_value(&x).unwrap());
+/// # }
+/// ```
+///
+/// [`Display`]: std::fmt::Display
+/// [`FromStr`]: std::str::FromStr
+pub struct DisplayFromStr;
+
+/// 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
+///
+/// ```
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// # use serde_with::{serde_as, NoneAsEmptyString};
+/// #
+/// #[serde_as]
+/// #[derive(Deserialize, Serialize)]
+/// struct A {
+/// #[serde_as(as = "NoneAsEmptyString")]
+/// tags: Option<String>,
+/// }
+///
+/// let v: A = serde_json::from_value(json!({ "tags": "" })).unwrap();
+/// assert_eq!(None, v.tags);
+///
+/// let v: A = serde_json::from_value(json!({ "tags": "Hi" })).unwrap();
+/// assert_eq!(Some("Hi".to_string()), v.tags);
+///
+/// let x = A {
+/// tags: Some("This is text".to_string()),
+/// };
+/// assert_eq!(json!({ "tags": "This is text" }), serde_json::to_value(&x).unwrap());
+///
+/// let x = A {
+/// tags: None,
+/// };
+/// assert_eq!(json!({ "tags": "" }), serde_json::to_value(&x).unwrap());
+/// # }
+/// ```
+///
+/// [`FromStr`]: std::str::FromStr
+pub struct NoneAsEmptyString;
+
+/// 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.
+/// During serialization this wrapper does nothing.
+/// The serialization behavior of the underlying type is preserved.
+/// The type must implement [`Default`] for this conversion to work.
+///
+/// # Examples
+///
+/// ```
+/// # #[cfg(feature = "macros")] {
+/// # use serde::Deserialize;
+/// # use serde_with::{serde_as, DefaultOnError};
+/// #
+/// #[serde_as]
+/// #[derive(Deserialize, Debug)]
+/// struct A {
+/// #[serde_as(deserialize_as = "DefaultOnError")]
+/// 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);
+///
+/// // Map is of invalid type
+/// let a: A = dbg!(serde_json::from_str(r#"{"value": {}}"#)).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:
+///
+/// ```
+/// # #[cfg(feature = "macros")] {
+/// # use serde::Deserialize;
+/// # use serde_with::{serde_as, DefaultOnError};
+/// #
+/// #[serde_as]
+/// #[derive(Deserialize)]
+/// struct B {
+/// #[serde_as(deserialize_as = "DefaultOnError")]
+/// #[serde(default)]
+/// value: u32,
+/// }
+///
+/// let b: B = serde_json::from_str(r#"{ }"#).unwrap();
+/// assert_eq!(0, b.value);
+/// # }
+/// ```
+///
+/// `DefaultOnError` can be combined with other conversion methods.
+/// In this example, we deserialize a `Vec`, each element is deserialized from a string.
+/// If the string does not parse as a number, then we get the default value of 0.
+///
+/// ```rust
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// # use serde_with::{serde_as, DefaultOnError, DisplayFromStr};
+/// #
+/// #[serde_as]
+/// #[derive(Serialize, Deserialize)]
+/// struct C {
+/// #[serde_as(as = "Vec<DefaultOnError<DisplayFromStr>>")]
+/// value: Vec<u32>,
+/// };
+///
+/// let c: C = serde_json::from_value(json!({
+/// "value": ["1", "2", "a3", "", {}, "6"]
+/// })).unwrap();
+/// assert_eq!(vec![1, 2, 0, 0, 0, 6], c.value);
+/// # }
+/// ```
+#[cfg(feature = "alloc")]
+pub struct DefaultOnError<T = Same>(PhantomData<T>);
+
+/// Deserialize [`Default`] from `null` values
+///
+/// Instead of erroring on `null` values, it simply deserializes the [`Default`] variant of the type.
+/// During serialization this wrapper does nothing.
+/// The serialization behavior of the underlying type is preserved.
+/// The type must implement [`Default`] for this conversion to work.
+///
+/// # Examples
+///
+/// ```
+/// # #[cfg(feature = "macros")] {
+/// # use serde::Deserialize;
+/// # use serde_with::{serde_as, DefaultOnNull};
+/// #
+/// #[serde_as]
+/// #[derive(Deserialize, Debug)]
+/// struct A {
+/// #[serde_as(deserialize_as = "DefaultOnNull")]
+/// value: u32,
+/// }
+///
+/// let a: A = serde_json::from_str(r#"{"value": 123}"#).unwrap();
+/// assert_eq!(123, a.value);
+///
+/// // null values are deserialized into the default, here 0
+/// let a: A = serde_json::from_str(r#"{"value": null}"#).unwrap();
+/// assert_eq!(0, a.value);
+/// # }
+/// ```
+///
+/// `DefaultOnNull` can be combined with other conversion methods.
+/// In this example, we deserialize a `Vec`, each element is deserialized from a string.
+/// If we encounter null, then we get the default value of 0.
+///
+/// ```rust
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// # use serde_with::{serde_as, DefaultOnNull, DisplayFromStr};
+/// #
+/// #[serde_as]
+/// #[derive(Serialize, Deserialize)]
+/// struct C {
+/// #[serde_as(as = "Vec<DefaultOnNull<DisplayFromStr>>")]
+/// value: Vec<u32>,
+/// };
+///
+/// let c: C = serde_json::from_value(json!({
+/// "value": ["1", "2", null, null, "5"]
+/// })).unwrap();
+/// assert_eq!(vec![1, 2, 0, 0, 5], c.value);
+/// # }
+/// ```
+pub struct DefaultOnNull<T = Same>(PhantomData<T>);
+
+/// Deserialize from bytes or string
+///
+/// Any Rust [`String`] can be converted into bytes, i.e., `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
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// # use serde_with::{serde_as, BytesOrString};
+/// #
+/// #[serde_as]
+/// #[derive(Deserialize, Serialize)]
+/// struct A {
+/// #[serde_as(as = "BytesOrString")]
+/// bytes_or_string: Vec<u8>,
+/// }
+///
+/// // Here we deserialize from a byte array ...
+/// let j = json!({
+/// "bytes_or_string": [
+/// 0,
+/// 1,
+/// 2,
+/// 3
+/// ]
+/// });
+///
+/// let a: A = serde_json::from_value(j.clone()).unwrap();
+/// assert_eq!(vec![0, 1, 2, 3], a.bytes_or_string);
+///
+/// // and serialization works too.
+/// assert_eq!(j, serde_json::to_value(&a).unwrap());
+///
+/// // But we also support deserializing from a String
+/// let j = json!({
+/// "bytes_or_string": "✨Works!"
+/// });
+///
+/// let a: A = serde_json::from_value(j).unwrap();
+/// assert_eq!("✨Works!".as_bytes(), &*a.bytes_or_string);
+/// # }
+/// ```
+/// [`String`]: std::string::String
+#[cfg(feature = "alloc")]
+pub struct BytesOrString;
+
+/// De/Serialize Durations as number of seconds.
+///
+/// De/serialize durations as number of seconds with subsecond precision.
+/// Subsecond precision is *only* supported for [`DurationSecondsWithFrac`], but not for [`DurationSeconds`].
+/// You can configure the serialization format between integers, floats, and stringified numbers with the `FORMAT` specifier and configure the deserialization with the `STRICTNESS` specifier.
+///
+/// The `STRICTNESS` specifier can either be [`formats::Strict`] or [`formats::Flexible`] and defaults to [`formats::Strict`].
+/// [`formats::Strict`] means that deserialization only supports the type given in `FORMAT`, e.g., if `FORMAT` is `u64` deserialization from a `f64` will error.
+/// [`formats::Flexible`] means that deserialization will perform a best effort to extract the correct duration and allows deserialization from any type.
+/// For example, deserializing `DurationSeconds<f64, Flexible>` will discard any subsecond precision during deserialization from `f64` and will parse a `String` as an integer number.
+///
+/// This type also supports [`chrono::Duration`] with the `chrono_0_4`-[feature flag].
+/// This type also supports [`time::Duration`][::time_0_3::Duration] with the `time_0_3`-[feature flag].
+///
+/// This table lists the available `FORMAT`s for the different duration types.
+/// The `FORMAT` specifier defaults to `u64`/`f64`.
+///
+/// | Duration Type | Converter | Available `FORMAT`s |
+/// | --------------------- | ------------------------- | ------------------------ |
+/// | `std::time::Duration` | `DurationSeconds` | *`u64`*, `f64`, `String` |
+/// | `std::time::Duration` | `DurationSecondsWithFrac` | *`f64`*, `String` |
+/// | `chrono::Duration` | `DurationSeconds` | `i64`, `f64`, `String` |
+/// | `chrono::Duration` | `DurationSecondsWithFrac` | *`f64`*, `String` |
+/// | `time::Duration` | `DurationSeconds` | `i64`, `f64`, `String` |
+/// | `time::Duration` | `DurationSecondsWithFrac` | *`f64`*, `String` |
+///
+/// # Examples
+///
+/// ```rust
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// # use serde_with::{serde_as, DurationSeconds};
+/// use std::time::Duration;
+///
+/// #[serde_as]
+/// # #[derive(Debug, PartialEq)]
+/// #[derive(Deserialize, Serialize)]
+/// struct Durations {
+/// #[serde_as(as = "DurationSeconds<u64>")]
+/// d_u64: Duration,
+/// #[serde_as(as = "DurationSeconds<f64>")]
+/// d_f64: Duration,
+/// #[serde_as(as = "DurationSeconds<String>")]
+/// d_string: Duration,
+/// };
+///
+/// // Serialization
+/// // See how the values get rounded, since subsecond precision is not allowed.
+///
+/// let d = Durations {
+/// d_u64: Duration::new(12345, 0), // Create from seconds and nanoseconds
+/// d_f64: Duration::new(12345, 500_000_000),
+/// d_string: Duration::new(12345, 999_999_999),
+/// };
+/// // Observe the different data types
+/// let expected = json!({
+/// "d_u64": 12345,
+/// "d_f64": 12346.0,
+/// "d_string": "12346",
+/// });
+/// assert_eq!(expected, serde_json::to_value(&d).unwrap());
+///
+/// // Deserialization works too
+/// // Subsecond precision in numbers will be rounded away
+///
+/// let json = json!({
+/// "d_u64": 12345,
+/// "d_f64": 12345.5,
+/// "d_string": "12346",
+/// });
+/// let expected = Durations {
+/// d_u64: Duration::new(12345, 0), // Create from seconds and nanoseconds
+/// d_f64: Duration::new(12346, 0),
+/// d_string: Duration::new(12346, 0),
+/// };
+/// assert_eq!(expected, serde_json::from_value(json).unwrap());
+/// # }
+/// ```
+///
+/// [`chrono::Duration`] is also supported when using the `chrono_0_4` feature.
+/// It is a signed duration, thus can be de/serialized as an `i64` instead of a `u64`.
+///
+/// ```rust
+/// # #[cfg(all(feature = "macros", feature = "chrono_0_4"))] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// # use serde_with::{serde_as, DurationSeconds};
+/// # use chrono_0_4::Duration;
+/// # /* Ugliness to make the docs look nicer since I want to hide the rename of the chrono crate
+/// use chrono::Duration;
+/// # */
+///
+/// #[serde_as]
+/// # #[derive(Debug, PartialEq)]
+/// #[derive(Deserialize, Serialize)]
+/// struct Durations {
+/// #[serde_as(as = "DurationSeconds<i64>")]
+/// d_i64: Duration,
+/// #[serde_as(as = "DurationSeconds<f64>")]
+/// d_f64: Duration,
+/// #[serde_as(as = "DurationSeconds<String>")]
+/// d_string: Duration,
+/// };
+///
+/// // Serialization
+/// // See how the values get rounded, since subsecond precision is not allowed.
+///
+/// let d = Durations {
+/// d_i64: Duration::seconds(-12345),
+/// d_f64: Duration::seconds(-12345) + Duration::milliseconds(500),
+/// d_string: Duration::seconds(12345) + Duration::nanoseconds(999_999_999),
+/// };
+/// // Observe the different data types
+/// let expected = json!({
+/// "d_i64": -12345,
+/// "d_f64": -12345.0,
+/// "d_string": "12346",
+/// });
+/// assert_eq!(expected, serde_json::to_value(&d).unwrap());
+///
+/// // Deserialization works too
+/// // Subsecond precision in numbers will be rounded away
+///
+/// let json = json!({
+/// "d_i64": -12345,
+/// "d_f64": -12345.5,
+/// "d_string": "12346",
+/// });
+/// let expected = Durations {
+/// d_i64: Duration::seconds(-12345),
+/// d_f64: Duration::seconds(-12346),
+/// d_string: Duration::seconds(12346),
+/// };
+/// assert_eq!(expected, serde_json::from_value(json).unwrap());
+/// # }
+/// ```
+///
+/// [`chrono::Duration`]: ::chrono_0_4::Duration
+/// [feature flag]: https://docs.rs/serde_with/3.0.0/serde_with/guide/feature_flags/index.html
+pub struct DurationSeconds<
+ FORMAT: formats::Format = u64,
+ STRICTNESS: formats::Strictness = formats::Strict,
+>(PhantomData<(FORMAT, STRICTNESS)>);
+
+/// De/Serialize Durations as number of seconds.
+///
+/// De/serialize durations as number of seconds with subsecond precision.
+/// Subsecond precision is *only* supported for [`DurationSecondsWithFrac`], but not for [`DurationSeconds`].
+/// You can configure the serialization format between integers, floats, and stringified numbers with the `FORMAT` specifier and configure the deserialization with the `STRICTNESS` specifier.
+///
+/// The `STRICTNESS` specifier can either be [`formats::Strict`] or [`formats::Flexible`] and defaults to [`formats::Strict`].
+/// [`formats::Strict`] means that deserialization only supports the type given in `FORMAT`, e.g., if `FORMAT` is `u64` deserialization from a `f64` will error.
+/// [`formats::Flexible`] means that deserialization will perform a best effort to extract the correct duration and allows deserialization from any type.
+/// For example, deserializing `DurationSeconds<f64, Flexible>` will discard any subsecond precision during deserialization from `f64` and will parse a `String` as an integer number.
+///
+/// This type also supports [`chrono::Duration`] with the `chrono`-[feature flag].
+/// This type also supports [`time::Duration`][::time_0_3::Duration] with the `time_0_3`-[feature flag].
+///
+/// This table lists the available `FORMAT`s for the different duration types.
+/// The `FORMAT` specifier defaults to `u64`/`f64`.
+///
+/// | Duration Type | Converter | Available `FORMAT`s |
+/// | --------------------- | ------------------------- | ------------------------ |
+/// | `std::time::Duration` | `DurationSeconds` | *`u64`*, `f64`, `String` |
+/// | `std::time::Duration` | `DurationSecondsWithFrac` | *`f64`*, `String` |
+/// | `chrono::Duration` | `DurationSeconds` | `i64`, `f64`, `String` |
+/// | `chrono::Duration` | `DurationSecondsWithFrac` | *`f64`*, `String` |
+/// | `time::Duration` | `DurationSeconds` | `i64`, `f64`, `String` |
+/// | `time::Duration` | `DurationSecondsWithFrac` | *`f64`*, `String` |
+///
+/// # Examples
+///
+/// ```rust
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// # use serde_with::{serde_as, DurationSecondsWithFrac};
+/// use std::time::Duration;
+///
+/// #[serde_as]
+/// # #[derive(Debug, PartialEq)]
+/// #[derive(Deserialize, Serialize)]
+/// struct Durations {
+/// #[serde_as(as = "DurationSecondsWithFrac<f64>")]
+/// d_f64: Duration,
+/// #[serde_as(as = "DurationSecondsWithFrac<String>")]
+/// d_string: Duration,
+/// };
+///
+/// // Serialization
+/// // See how the values get rounded, since subsecond precision is not allowed.
+///
+/// let d = Durations {
+/// d_f64: Duration::new(12345, 500_000_000), // Create from seconds and nanoseconds
+/// d_string: Duration::new(12345, 999_999_000),
+/// };
+/// // Observe the different data types
+/// let expected = json!({
+/// "d_f64": 12345.5,
+/// "d_string": "12345.999999",
+/// });
+/// assert_eq!(expected, serde_json::to_value(&d).unwrap());
+///
+/// // Deserialization works too
+/// // Subsecond precision in numbers will be rounded away
+///
+/// let json = json!({
+/// "d_f64": 12345.5,
+/// "d_string": "12345.987654",
+/// });
+/// let expected = Durations {
+/// d_f64: Duration::new(12345, 500_000_000), // Create from seconds and nanoseconds
+/// d_string: Duration::new(12345, 987_654_000),
+/// };
+/// assert_eq!(expected, serde_json::from_value(json).unwrap());
+/// # }
+/// ```
+///
+/// [`chrono::Duration`] is also supported when using the `chrono_0_4` feature.
+/// It is a signed duration, thus can be de/serialized as an `i64` instead of a `u64`.
+///
+/// ```rust
+/// # #[cfg(all(feature = "macros", feature = "chrono_0_4"))] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// # use serde_with::{serde_as, DurationSecondsWithFrac};
+/// # use chrono_0_4::Duration;
+/// # /* Ugliness to make the docs look nicer since I want to hide the rename of the chrono crate
+/// use chrono::Duration;
+/// # */
+///
+/// #[serde_as]
+/// # #[derive(Debug, PartialEq)]
+/// #[derive(Deserialize, Serialize)]
+/// struct Durations {
+/// #[serde_as(as = "DurationSecondsWithFrac<f64>")]
+/// d_f64: Duration,
+/// #[serde_as(as = "DurationSecondsWithFrac<String>")]
+/// d_string: Duration,
+/// };
+///
+/// // Serialization
+///
+/// let d = Durations {
+/// d_f64: Duration::seconds(-12345) + Duration::milliseconds(500),
+/// d_string: Duration::seconds(12345) + Duration::nanoseconds(999_999_000),
+/// };
+/// // Observe the different data types
+/// let expected = json!({
+/// "d_f64": -12344.5,
+/// "d_string": "12345.999999",
+/// });
+/// assert_eq!(expected, serde_json::to_value(&d).unwrap());
+///
+/// // Deserialization works too
+///
+/// let json = json!({
+/// "d_f64": -12344.5,
+/// "d_string": "12345.987",
+/// });
+/// let expected = Durations {
+/// d_f64: Duration::seconds(-12345) + Duration::milliseconds(500),
+/// d_string: Duration::seconds(12345) + Duration::milliseconds(987),
+/// };
+/// assert_eq!(expected, serde_json::from_value(json).unwrap());
+/// # }
+/// ```
+///
+/// [`chrono::Duration`]: ::chrono_0_4::Duration
+/// [feature flag]: https://docs.rs/serde_with/3.0.0/serde_with/guide/feature_flags/index.html
+pub struct DurationSecondsWithFrac<
+ FORMAT: formats::Format = f64,
+ STRICTNESS: formats::Strictness = formats::Strict,
+>(PhantomData<(FORMAT, STRICTNESS)>);
+
+/// Equivalent to [`DurationSeconds`] with milli-seconds as base unit.
+///
+/// This type is equivalent to [`DurationSeconds`] except that each unit represents 1 milli-second instead of 1 second for [`DurationSeconds`].
+pub struct DurationMilliSeconds<
+ FORMAT: formats::Format = u64,
+ STRICTNESS: formats::Strictness = formats::Strict,
+>(PhantomData<(FORMAT, STRICTNESS)>);
+
+/// Equivalent to [`DurationSecondsWithFrac`] with milli-seconds as base unit.
+///
+/// This type is equivalent to [`DurationSecondsWithFrac`] except that each unit represents 1 milli-second instead of 1 second for [`DurationSecondsWithFrac`].
+pub struct DurationMilliSecondsWithFrac<
+ FORMAT: formats::Format = f64,
+ STRICTNESS: formats::Strictness = formats::Strict,
+>(PhantomData<(FORMAT, STRICTNESS)>);
+
+/// Equivalent to [`DurationSeconds`] with micro-seconds as base unit.
+///
+/// This type is equivalent to [`DurationSeconds`] except that each unit represents 1 micro-second instead of 1 second for [`DurationSeconds`].
+pub struct DurationMicroSeconds<
+ FORMAT: formats::Format = u64,
+ STRICTNESS: formats::Strictness = formats::Strict,
+>(PhantomData<(FORMAT, STRICTNESS)>);
+
+/// Equivalent to [`DurationSecondsWithFrac`] with micro-seconds as base unit.
+///
+/// This type is equivalent to [`DurationSecondsWithFrac`] except that each unit represents 1 micro-second instead of 1 second for [`DurationSecondsWithFrac`].
+pub struct DurationMicroSecondsWithFrac<
+ FORMAT: formats::Format = f64,
+ STRICTNESS: formats::Strictness = formats::Strict,
+>(PhantomData<(FORMAT, STRICTNESS)>);
+
+/// Equivalent to [`DurationSeconds`] with nano-seconds as base unit.
+///
+/// This type is equivalent to [`DurationSeconds`] except that each unit represents 1 nano-second instead of 1 second for [`DurationSeconds`].
+pub struct DurationNanoSeconds<
+ FORMAT: formats::Format = u64,
+ STRICTNESS: formats::Strictness = formats::Strict,
+>(PhantomData<(FORMAT, STRICTNESS)>);
+
+/// Equivalent to [`DurationSecondsWithFrac`] with nano-seconds as base unit.
+///
+/// This type is equivalent to [`DurationSecondsWithFrac`] except that each unit represents 1 nano-second instead of 1 second for [`DurationSecondsWithFrac`].
+pub struct DurationNanoSecondsWithFrac<
+ FORMAT: formats::Format = f64,
+ STRICTNESS: formats::Strictness = formats::Strict,
+>(PhantomData<(FORMAT, STRICTNESS)>);
+
+/// De/Serialize timestamps as seconds since the UNIX epoch
+///
+/// De/serialize timestamps as seconds since the UNIX epoch.
+/// Subsecond precision is *only* supported for [`TimestampSecondsWithFrac`], but not for [`TimestampSeconds`].
+/// You can configure the serialization format between integers, floats, and stringified numbers with the `FORMAT` specifier and configure the deserialization with the `STRICTNESS` specifier.
+///
+/// The `STRICTNESS` specifier can either be [`formats::Strict`] or [`formats::Flexible`] and defaults to [`formats::Strict`].
+/// [`formats::Strict`] means that deserialization only supports the type given in `FORMAT`, e.g., if `FORMAT` is `i64` deserialization from a `f64` will error.
+/// [`formats::Flexible`] means that deserialization will perform a best effort to extract the correct timestamp and allows deserialization from any type.
+/// For example, deserializing `TimestampSeconds<f64, Flexible>` will discard any subsecond precision during deserialization from `f64` and will parse a `String` as an integer number.
+///
+/// This type also supports [`chrono::DateTime`] with the `chrono_0_4`-[feature flag].
+/// This type also supports [`time::OffsetDateTime`][::time_0_3::OffsetDateTime] and [`time::PrimitiveDateTime`][::time_0_3::PrimitiveDateTime] with the `time_0_3`-[feature flag].
+///
+/// This table lists the available `FORMAT`s for the different timestamp types.
+/// The `FORMAT` specifier defaults to `i64` or `f64`.
+///
+/// | Timestamp Type | Converter | Available `FORMAT`s |
+/// | ------------------------- | -------------------------- | ------------------------ |
+/// | `std::time::SystemTime` | `TimestampSeconds` | *`i64`*, `f64`, `String` |
+/// | `std::time::SystemTime` | `TimestampSecondsWithFrac` | *`f64`*, `String` |
+/// | `chrono::DateTime<Utc>` | `TimestampSeconds` | *`i64`*, `f64`, `String` |
+/// | `chrono::DateTime<Utc>` | `TimestampSecondsWithFrac` | *`f64`*, `String` |
+/// | `chrono::DateTime<Local>` | `TimestampSeconds` | *`i64`*, `f64`, `String` |
+/// | `chrono::DateTime<Local>` | `TimestampSecondsWithFrac` | *`f64`*, `String` |
+/// | `chrono::NaiveDateTime` | `TimestampSeconds` | *`i64`*, `f64`, `String` |
+/// | `chrono::NaiveDateTime` | `TimestampSecondsWithFrac` | *`f64`*, `String` |
+/// | `time::OffsetDateTime` | `TimestampSeconds` | *`i64`*, `f64`, `String` |
+/// | `time::OffsetDateTime` | `TimestampSecondsWithFrac` | *`f64`*, `String` |
+/// | `time::PrimitiveDateTime` | `TimestampSeconds` | *`i64`*, `f64`, `String` |
+/// | `time::PrimitiveDateTime` | `TimestampSecondsWithFrac` | *`f64`*, `String` |
+///
+/// # Examples
+///
+/// ```rust
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// # use serde_with::{serde_as, TimestampSeconds};
+/// use std::time::{Duration, SystemTime};
+///
+/// #[serde_as]
+/// # #[derive(Debug, PartialEq)]
+/// #[derive(Deserialize, Serialize)]
+/// struct Timestamps {
+/// #[serde_as(as = "TimestampSeconds<i64>")]
+/// st_i64: SystemTime,
+/// #[serde_as(as = "TimestampSeconds<f64>")]
+/// st_f64: SystemTime,
+/// #[serde_as(as = "TimestampSeconds<String>")]
+/// st_string: SystemTime,
+/// };
+///
+/// // Serialization
+/// // See how the values get rounded, since subsecond precision is not allowed.
+///
+/// let ts = Timestamps {
+/// st_i64: SystemTime::UNIX_EPOCH.checked_add(Duration::new(12345, 0)).unwrap(),
+/// st_f64: SystemTime::UNIX_EPOCH.checked_add(Duration::new(12345, 500_000_000)).unwrap(),
+/// st_string: SystemTime::UNIX_EPOCH.checked_add(Duration::new(12345, 999_999_999)).unwrap(),
+/// };
+/// // Observe the different data types
+/// let expected = json!({
+/// "st_i64": 12345,
+/// "st_f64": 12346.0,
+/// "st_string": "12346",
+/// });
+/// assert_eq!(expected, serde_json::to_value(&ts).unwrap());
+///
+/// // Deserialization works too
+/// // Subsecond precision in numbers will be rounded away
+///
+/// let json = json!({
+/// "st_i64": 12345,
+/// "st_f64": 12345.5,
+/// "st_string": "12346",
+/// });
+/// let expected = Timestamps {
+/// st_i64: SystemTime::UNIX_EPOCH.checked_add(Duration::new(12345, 0)).unwrap(),
+/// st_f64: SystemTime::UNIX_EPOCH.checked_add(Duration::new(12346, 0)).unwrap(),
+/// st_string: SystemTime::UNIX_EPOCH.checked_add(Duration::new(12346, 0)).unwrap(),
+/// };
+/// assert_eq!(expected, serde_json::from_value(json).unwrap());
+/// # }
+/// ```
+///
+/// [`chrono::DateTime<Utc>`] and [`chrono::DateTime<Local>`] are also supported when using the `chrono` feature.
+/// Like [`SystemTime`], it is a signed timestamp, thus can be de/serialized as an `i64`.
+///
+/// ```rust
+/// # #[cfg(all(feature = "macros", feature = "chrono_0_4"))] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// # use serde_with::{serde_as, TimestampSeconds};
+/// # use chrono_0_4::{DateTime, Local, TimeZone, Utc};
+/// # /* Ugliness to make the docs look nicer since I want to hide the rename of the chrono crate
+/// use chrono::{DateTime, Local, TimeZone, Utc};
+/// # */
+///
+/// #[serde_as]
+/// # #[derive(Debug, PartialEq)]
+/// #[derive(Deserialize, Serialize)]
+/// struct Timestamps {
+/// #[serde_as(as = "TimestampSeconds<i64>")]
+/// dt_i64: DateTime<Utc>,
+/// #[serde_as(as = "TimestampSeconds<f64>")]
+/// dt_f64: DateTime<Local>,
+/// #[serde_as(as = "TimestampSeconds<String>")]
+/// dt_string: DateTime<Utc>,
+/// };
+///
+/// // Serialization
+/// // See how the values get rounded, since subsecond precision is not allowed.
+///
+/// let ts = Timestamps {
+/// dt_i64: Utc.timestamp(-12345, 0),
+/// dt_f64: Local.timestamp(-12345, 500_000_000),
+/// dt_string: Utc.timestamp(12345, 999_999_999),
+/// };
+/// // Observe the different data types
+/// let expected = json!({
+/// "dt_i64": -12345,
+/// "dt_f64": -12345.0,
+/// "dt_string": "12346",
+/// });
+/// assert_eq!(expected, serde_json::to_value(&ts).unwrap());
+///
+/// // Deserialization works too
+/// // Subsecond precision in numbers will be rounded away
+///
+/// let json = json!({
+/// "dt_i64": -12345,
+/// "dt_f64": -12345.5,
+/// "dt_string": "12346",
+/// });
+/// let expected = Timestamps {
+/// dt_i64: Utc.timestamp(-12345, 0),
+/// dt_f64: Local.timestamp(-12346, 0),
+/// dt_string: Utc.timestamp(12346, 0),
+/// };
+/// assert_eq!(expected, serde_json::from_value(json).unwrap());
+/// # }
+/// ```
+///
+/// [`SystemTime`]: std::time::SystemTime
+/// [`chrono::DateTime<Local>`]: ::chrono_0_4::DateTime
+/// [`chrono::DateTime<Utc>`]: ::chrono_0_4::DateTime
+/// [feature flag]: https://docs.rs/serde_with/3.0.0/serde_with/guide/feature_flags/index.html
+pub struct TimestampSeconds<
+ FORMAT: formats::Format = i64,
+ STRICTNESS: formats::Strictness = formats::Strict,
+>(PhantomData<(FORMAT, STRICTNESS)>);
+
+/// De/Serialize timestamps as seconds since the UNIX epoch
+///
+/// De/serialize timestamps as seconds since the UNIX epoch.
+/// Subsecond precision is *only* supported for [`TimestampSecondsWithFrac`], but not for [`TimestampSeconds`].
+/// You can configure the serialization format between integers, floats, and stringified numbers with the `FORMAT` specifier and configure the deserialization with the `STRICTNESS` specifier.
+///
+/// The `STRICTNESS` specifier can either be [`formats::Strict`] or [`formats::Flexible`] and defaults to [`formats::Strict`].
+/// [`formats::Strict`] means that deserialization only supports the type given in `FORMAT`, e.g., if `FORMAT` is `i64` deserialization from a `f64` will error.
+/// [`formats::Flexible`] means that deserialization will perform a best effort to extract the correct timestamp and allows deserialization from any type.
+/// For example, deserializing `TimestampSeconds<f64, Flexible>` will discard any subsecond precision during deserialization from `f64` and will parse a `String` as an integer number.
+///
+/// This type also supports [`chrono::DateTime`] and [`chrono::NaiveDateTime`][NaiveDateTime] with the `chrono`-[feature flag].
+/// This type also supports [`time::OffsetDateTime`][::time_0_3::OffsetDateTime] and [`time::PrimitiveDateTime`][::time_0_3::PrimitiveDateTime] with the `time_0_3`-[feature flag].
+///
+/// This table lists the available `FORMAT`s for the different timestamp types.
+/// The `FORMAT` specifier defaults to `i64` or `f64`.
+///
+/// | Timestamp Type | Converter | Available `FORMAT`s |
+/// | ------------------------- | -------------------------- | ------------------------ |
+/// | `std::time::SystemTime` | `TimestampSeconds` | *`i64`*, `f64`, `String` |
+/// | `std::time::SystemTime` | `TimestampSecondsWithFrac` | *`f64`*, `String` |
+/// | `chrono::DateTime<Utc>` | `TimestampSeconds` | *`i64`*, `f64`, `String` |
+/// | `chrono::DateTime<Utc>` | `TimestampSecondsWithFrac` | *`f64`*, `String` |
+/// | `chrono::DateTime<Local>` | `TimestampSeconds` | *`i64`*, `f64`, `String` |
+/// | `chrono::DateTime<Local>` | `TimestampSecondsWithFrac` | *`f64`*, `String` |
+/// | `chrono::NaiveDateTime` | `TimestampSeconds` | *`i64`*, `f64`, `String` |
+/// | `chrono::NaiveDateTime` | `TimestampSecondsWithFrac` | *`f64`*, `String` |
+/// | `time::OffsetDateTime` | `TimestampSeconds` | *`i64`*, `f64`, `String` |
+/// | `time::OffsetDateTime` | `TimestampSecondsWithFrac` | *`f64`*, `String` |
+/// | `time::PrimitiveDateTime` | `TimestampSeconds` | *`i64`*, `f64`, `String` |
+/// | `time::PrimitiveDateTime` | `TimestampSecondsWithFrac` | *`f64`*, `String` |
+///
+/// # Examples
+///
+/// ```rust
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// # use serde_with::{serde_as, TimestampSecondsWithFrac};
+/// use std::time::{Duration, SystemTime};
+///
+/// #[serde_as]
+/// # #[derive(Debug, PartialEq)]
+/// #[derive(Deserialize, Serialize)]
+/// struct Timestamps {
+/// #[serde_as(as = "TimestampSecondsWithFrac<f64>")]
+/// st_f64: SystemTime,
+/// #[serde_as(as = "TimestampSecondsWithFrac<String>")]
+/// st_string: SystemTime,
+/// };
+///
+/// // Serialization
+/// // See how the values get rounded, since subsecond precision is not allowed.
+///
+/// let ts = Timestamps {
+/// st_f64: SystemTime::UNIX_EPOCH.checked_add(Duration::new(12345, 500_000_000)).unwrap(),
+/// st_string: SystemTime::UNIX_EPOCH.checked_add(Duration::new(12345, 999_999_000)).unwrap(),
+/// };
+/// // Observe the different data types
+/// let expected = json!({
+/// "st_f64": 12345.5,
+/// "st_string": "12345.999999",
+/// });
+/// assert_eq!(expected, serde_json::to_value(&ts).unwrap());
+///
+/// // Deserialization works too
+/// // Subsecond precision in numbers will be rounded away
+///
+/// let json = json!({
+/// "st_f64": 12345.5,
+/// "st_string": "12345.987654",
+/// });
+/// let expected = Timestamps {
+/// st_f64: SystemTime::UNIX_EPOCH.checked_add(Duration::new(12345, 500_000_000)).unwrap(),
+/// st_string: SystemTime::UNIX_EPOCH.checked_add(Duration::new(12345, 987_654_000)).unwrap(),
+/// };
+/// assert_eq!(expected, serde_json::from_value(json).unwrap());
+/// # }
+/// ```
+///
+/// [`chrono::DateTime<Utc>`] and [`chrono::DateTime<Local>`] are also supported when using the `chrono_0_4` feature.
+/// Like [`SystemTime`], it is a signed timestamp, thus can be de/serialized as an `i64`.
+///
+/// ```rust
+/// # #[cfg(all(feature = "macros", feature = "chrono_0_4"))] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// # use serde_with::{serde_as, TimestampSecondsWithFrac};
+/// # use chrono_0_4::{DateTime, Local, TimeZone, Utc};
+/// # /* Ugliness to make the docs look nicer since I want to hide the rename of the chrono crate
+/// use chrono::{DateTime, Local, TimeZone, Utc};
+/// # */
+///
+/// #[serde_as]
+/// # #[derive(Debug, PartialEq)]
+/// #[derive(Deserialize, Serialize)]
+/// struct Timestamps {
+/// #[serde_as(as = "TimestampSecondsWithFrac<f64>")]
+/// dt_f64: DateTime<Utc>,
+/// #[serde_as(as = "TimestampSecondsWithFrac<String>")]
+/// dt_string: DateTime<Local>,
+/// };
+///
+/// // Serialization
+///
+/// let ts = Timestamps {
+/// dt_f64: Utc.timestamp(-12345, 500_000_000),
+/// dt_string: Local.timestamp(12345, 999_999_000),
+/// };
+/// // Observe the different data types
+/// let expected = json!({
+/// "dt_f64": -12344.5,
+/// "dt_string": "12345.999999",
+/// });
+/// assert_eq!(expected, serde_json::to_value(&ts).unwrap());
+///
+/// // Deserialization works too
+///
+/// let json = json!({
+/// "dt_f64": -12344.5,
+/// "dt_string": "12345.987",
+/// });
+/// let expected = Timestamps {
+/// dt_f64: Utc.timestamp(-12345, 500_000_000),
+/// dt_string: Local.timestamp(12345, 987_000_000),
+/// };
+/// assert_eq!(expected, serde_json::from_value(json).unwrap());
+/// # }
+/// ```
+///
+/// [`SystemTime`]: std::time::SystemTime
+/// [`chrono::DateTime`]: ::chrono_0_4::DateTime
+/// [`chrono::DateTime<Local>`]: ::chrono_0_4::DateTime
+/// [`chrono::DateTime<Utc>`]: ::chrono_0_4::DateTime
+/// [NaiveDateTime]: ::chrono_0_4::NaiveDateTime
+/// [feature flag]: https://docs.rs/serde_with/3.0.0/serde_with/guide/feature_flags/index.html
+pub struct TimestampSecondsWithFrac<
+ FORMAT: formats::Format = f64,
+ STRICTNESS: formats::Strictness = formats::Strict,
+>(PhantomData<(FORMAT, STRICTNESS)>);
+
+/// Equivalent to [`TimestampSeconds`] with milli-seconds as base unit.
+///
+/// This type is equivalent to [`TimestampSeconds`] except that each unit represents 1 milli-second instead of 1 second for [`TimestampSeconds`].
+pub struct TimestampMilliSeconds<
+ FORMAT: formats::Format = i64,
+ STRICTNESS: formats::Strictness = formats::Strict,
+>(PhantomData<(FORMAT, STRICTNESS)>);
+
+/// Equivalent to [`TimestampSecondsWithFrac`] with milli-seconds as base unit.
+///
+/// This type is equivalent to [`TimestampSecondsWithFrac`] except that each unit represents 1 milli-second instead of 1 second for [`TimestampSecondsWithFrac`].
+pub struct TimestampMilliSecondsWithFrac<
+ FORMAT: formats::Format = f64,
+ STRICTNESS: formats::Strictness = formats::Strict,
+>(PhantomData<(FORMAT, STRICTNESS)>);
+
+/// Equivalent to [`TimestampSeconds`] with micro-seconds as base unit.
+///
+/// This type is equivalent to [`TimestampSeconds`] except that each unit represents 1 micro-second instead of 1 second for [`TimestampSeconds`].
+pub struct TimestampMicroSeconds<
+ FORMAT: formats::Format = i64,
+ STRICTNESS: formats::Strictness = formats::Strict,
+>(PhantomData<(FORMAT, STRICTNESS)>);
+
+/// Equivalent to [`TimestampSecondsWithFrac`] with micro-seconds as base unit.
+///
+/// This type is equivalent to [`TimestampSecondsWithFrac`] except that each unit represents 1 micro-second instead of 1 second for [`TimestampSecondsWithFrac`].
+pub struct TimestampMicroSecondsWithFrac<
+ FORMAT: formats::Format = f64,
+ STRICTNESS: formats::Strictness = formats::Strict,
+>(PhantomData<(FORMAT, STRICTNESS)>);
+
+/// Equivalent to [`TimestampSeconds`] with nano-seconds as base unit.
+///
+/// This type is equivalent to [`TimestampSeconds`] except that each unit represents 1 nano-second instead of 1 second for [`TimestampSeconds`].
+pub struct TimestampNanoSeconds<
+ FORMAT: formats::Format = i64,
+ STRICTNESS: formats::Strictness = formats::Strict,
+>(PhantomData<(FORMAT, STRICTNESS)>);
+
+/// Equivalent to [`TimestampSecondsWithFrac`] with nano-seconds as base unit.
+///
+/// This type is equivalent to [`TimestampSecondsWithFrac`] except that each unit represents 1 nano-second instead of 1 second for [`TimestampSecondsWithFrac`].
+pub struct TimestampNanoSecondsWithFrac<
+ FORMAT: formats::Format = f64,
+ STRICTNESS: formats::Strictness = formats::Strict,
+>(PhantomData<(FORMAT, STRICTNESS)>);
+
+/// Optimized handling of owned and borrowed byte representations.
+///
+/// Serialization of byte sequences like `&[u8]` or `Vec<u8>` is quite inefficient since each value will be serialized individually.
+/// This converter type optimizes the serialization and deserialization.
+///
+/// This is a port of the [`serde_bytes`] crate making it compatible with the `serde_as`-annotation, which allows it to be used in more cases than provided by [`serde_bytes`].
+///
+/// The type provides de/serialization for these types:
+///
+/// * `[u8; N]`, not possible using `serde_bytes`
+/// * `&[u8; N]`, not possible using `serde_bytes`
+/// * `&[u8]`
+/// * `Box<[u8; N]>`, not possible using `serde_bytes`
+/// * `Box<[u8]>`
+/// * `Vec<u8>`
+/// * `Cow<'_, [u8]>`
+/// * `Cow<'_, [u8; N]>`, not possible using `serde_bytes`
+///
+/// [`serde_bytes`]: https://crates.io/crates/serde_bytes
+///
+/// # Examples
+///
+/// ```
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_with::{serde_as, Bytes};
+/// # use std::borrow::Cow;
+/// #
+/// #[serde_as]
+/// # #[derive(Debug, PartialEq)]
+/// #[derive(Deserialize, Serialize)]
+/// struct Test<'a> {
+/// # #[cfg(FALSE)]
+/// #[serde_as(as = "Bytes")]
+/// array: [u8; 15],
+/// #[serde_as(as = "Bytes")]
+/// boxed: Box<[u8]>,
+/// #[serde_as(as = "Bytes")]
+/// #[serde(borrow)]
+/// cow: Cow<'a, [u8]>,
+/// # #[cfg(FALSE)]
+/// #[serde_as(as = "Bytes")]
+/// #[serde(borrow)]
+/// cow_array: Cow<'a, [u8; 15]>,
+/// #[serde_as(as = "Bytes")]
+/// vec: Vec<u8>,
+/// }
+///
+/// let value = Test {
+/// # #[cfg(FALSE)]
+/// array: b"0123456789ABCDE".clone(),
+/// boxed: b"...".to_vec().into_boxed_slice(),
+/// cow: Cow::Borrowed(b"FooBar"),
+/// # #[cfg(FALSE)]
+/// cow_array: Cow::Borrowed(&[42u8; 15]),
+/// vec: vec![0x41, 0x61, 0x21],
+/// };
+/// let expected = r#"(
+/// array: "MDEyMzQ1Njc4OUFCQ0RF",
+/// boxed: "Li4u",
+/// cow: "Rm9vQmFy",
+/// cow_array: "KioqKioqKioqKioqKioq",
+/// vec: "QWEh",
+/// )"#;
+/// # drop(expected);
+/// # // Create a fake expected value that doesn't use const generics
+/// # let expected = r#"(
+/// # boxed: "Li4u",
+/// # cow: "Rm9vQmFy",
+/// # vec: "QWEh",
+/// # )"#;
+///
+/// # let pretty_config = ron::ser::PrettyConfig::new()
+/// # .new_line("\n".into());
+/// assert_eq!(expected, ron::ser::to_string_pretty(&value, pretty_config).unwrap());
+/// assert_eq!(value, ron::from_str(&expected).unwrap());
+/// # }
+/// ```
+///
+/// Fully borrowed types can also be used but you'll need a Deserializer that
+/// supports Serde's 0-copy deserialization:
+///
+/// ```
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_with::{serde_as, Bytes};
+/// # use std::borrow::Cow;
+/// #
+/// #[serde_as]
+/// # #[derive(Debug, PartialEq)]
+/// #[derive(Deserialize, Serialize)]
+/// struct TestBorrows<'a> {
+/// # #[cfg(FALSE)]
+/// #[serde_as(as = "Bytes")]
+/// #[serde(borrow)]
+/// array_buf: &'a [u8; 15],
+/// #[serde_as(as = "Bytes")]
+/// #[serde(borrow)]
+/// buf: &'a [u8],
+/// }
+///
+/// let value = TestBorrows {
+/// # #[cfg(FALSE)]
+/// array_buf: &[10u8; 15],
+/// buf: &[20u8, 21u8, 22u8],
+/// };
+/// let expected = r#"(
+/// array_buf: "CgoKCgoKCgoKCgoKCgoK",
+/// buf: "FBUW",
+/// )"#;
+/// # drop(expected);
+/// # // Create a fake expected value that doesn't use const generics
+/// # let expected = r#"(
+/// # buf: "FBUW",
+/// # )"#;
+///
+/// # let pretty_config = ron::ser::PrettyConfig::new()
+/// # .new_line("\n".into());
+/// assert_eq!(expected, ron::ser::to_string_pretty(&value, pretty_config).unwrap());
+/// // RON doesn't support borrowed deserialization of byte arrays
+/// # }
+/// ```
+///
+/// ## Alternative to [`BytesOrString`]
+///
+/// The [`Bytes`] can replace [`BytesOrString`].
+/// [`Bytes`] is implemented for more types, which makes it better.
+/// The serialization behavior of [`Bytes`] differs from [`BytesOrString`], therefore only `deserialize_as` should be used.
+///
+/// ```rust
+/// # #[cfg(feature = "macros")] {
+/// # use serde::Deserialize;
+/// # use serde_json::json;
+/// # use serde_with::{serde_as, Bytes};
+/// #
+/// #[serde_as]
+/// # #[derive(Debug, PartialEq)]
+/// #[derive(Deserialize, serde::Serialize)]
+/// struct Test {
+/// #[serde_as(deserialize_as = "Bytes")]
+/// from_bytes: Vec<u8>,
+/// #[serde_as(deserialize_as = "Bytes")]
+/// from_str: Vec<u8>,
+/// }
+///
+/// // Different serialized values ...
+/// let j = json!({
+/// "from_bytes": [70,111,111,45,66,97,114],
+/// "from_str": "Foo-Bar",
+/// });
+///
+/// // can be deserialized ...
+/// let test = Test {
+/// from_bytes: b"Foo-Bar".to_vec(),
+/// from_str: b"Foo-Bar".to_vec(),
+/// };
+/// assert_eq!(test, serde_json::from_value(j).unwrap());
+///
+/// // and serialization will always be a byte sequence
+/// # assert_eq!(json!(
+/// {
+/// "from_bytes": [70,111,111,45,66,97,114],
+/// "from_str": [70,111,111,45,66,97,114],
+/// }
+/// # ), serde_json::to_value(&test).unwrap());
+/// # }
+/// ```
+pub struct Bytes;
+
+/// Deserialize one or many elements
+///
+/// Sometimes it is desirable to have a shortcut in writing 1-element lists in a config file.
+/// Usually, this is done by either writing a list or the list element itself.
+/// This distinction is not semantically important on the Rust side, thus both forms should deserialize into the same `Vec`.
+///
+/// The `OneOrMany` adapter achieves exactly this use case.
+/// The serialization behavior can be tweaked to either always serialize as a list using `PreferMany` or to serialize as the inner element if possible using `PreferOne`.
+/// By default, `PreferOne` is assumed, which can also be omitted like `OneOrMany<_>`.
+///
+/// # Examples
+///
+/// ```rust
+/// # #[cfg(feature = "macros")] {
+/// # use serde::Deserialize;
+/// # use serde_json::json;
+/// # use serde_with::{serde_as, OneOrMany};
+/// # use serde_with::formats::{PreferOne, PreferMany};
+/// #
+/// #[serde_as]
+/// # #[derive(Debug, PartialEq)]
+/// #[derive(Deserialize, serde::Serialize)]
+/// struct Data {
+/// #[serde_as(deserialize_as = "OneOrMany<_, PreferOne>")]
+/// countries: Vec<String>,
+/// #[serde_as(deserialize_as = "OneOrMany<_, PreferMany>")]
+/// cities: Vec<String>,
+/// }
+///
+/// // The adapter allows deserializing a `Vec` from either
+/// // a single element
+/// let j = json!({
+/// "countries": "Spain",
+/// "cities": "Berlin",
+/// });
+/// assert!(serde_json::from_value::<Data>(j).is_ok());
+///
+/// // or from a list.
+/// let j = json!({
+/// "countries": ["Germany", "France"],
+/// "cities": ["Amsterdam"],
+/// });
+/// assert!(serde_json::from_value::<Data>(j).is_ok());
+///
+/// // For serialization you can choose how a single element should be encoded.
+/// // Either directly, with `PreferOne` (default), or as a list with `PreferMany`.
+/// let data = Data {
+/// countries: vec!["Spain".to_string()],
+/// cities: vec!["Berlin".to_string()],
+/// };
+/// let j = json!({
+/// "countries": "Spain",
+/// "cities": ["Berlin"],
+/// });
+/// assert_eq!(data, serde_json::from_value(j).unwrap());
+/// # }
+/// ```
+#[cfg(feature = "alloc")]
+pub struct OneOrMany<T, FORMAT: formats::Format = formats::PreferOne>(PhantomData<(T, FORMAT)>);
+
+/// Try multiple deserialization options until one succeeds.
+///
+/// This adapter allows you to specify a list of deserialization options.
+/// They are tried in order and the first one working is applied.
+/// Serialization always picks the first option.
+///
+/// `PickFirst` has one type parameter which must be instantiated with a tuple of two, three, or four elements.
+/// For example, `PickFirst<(_, DisplayFromStr)>` on a field of type `u32` allows deserializing from a number or from a string via the `FromStr` trait.
+/// The value will be serialized as a number, since that is what the first type `_` indicates.
+///
+/// # Examples
+///
+/// Deserialize a number from either a number or a string.
+///
+/// ```rust
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// # use serde_with::{serde_as, DisplayFromStr, PickFirst};
+/// #
+/// #[serde_as]
+/// # #[derive(Debug, PartialEq)]
+/// #[derive(Deserialize, Serialize)]
+/// struct Data {
+/// #[serde_as(as = "PickFirst<(_, DisplayFromStr)>")]
+/// as_number: u32,
+/// #[serde_as(as = "PickFirst<(DisplayFromStr, _)>")]
+/// as_string: u32,
+/// }
+/// let data = Data {
+/// as_number: 123,
+/// as_string: 456
+/// };
+///
+/// // Both fields can be deserialized from numbers:
+/// let j = json!({
+/// "as_number": 123,
+/// "as_string": 456,
+/// });
+/// assert_eq!(data, serde_json::from_value(j).unwrap());
+///
+/// // or from a string:
+/// let j = json!({
+/// "as_number": "123",
+/// "as_string": "456",
+/// });
+/// assert_eq!(data, serde_json::from_value(j).unwrap());
+///
+/// // For serialization the first type in the tuple determines the behavior.
+/// // The `as_number` field will use the normal `Serialize` behavior and produce a number,
+/// // while `as_string` used `Display` to produce a string.
+/// let expected = json!({
+/// "as_number": 123,
+/// "as_string": "456",
+/// });
+/// assert_eq!(expected, serde_json::to_value(&data).unwrap());
+/// # }
+/// ```
+#[cfg(feature = "alloc")]
+pub struct PickFirst<T>(PhantomData<T>);
+
+/// Serialize value by converting to/from a proxy type with serde support.
+///
+/// This adapter serializes a type `O` by converting it into a second type `T` and serializing `T`.
+/// Deserializing works analogue, by deserializing a `T` and then converting into `O`.
+///
+/// ```rust
+/// # #[cfg(FALSE)] {
+/// struct S {
+/// #[serde_as(as = "FromInto<T>")]
+/// value: O,
+/// }
+/// # }
+/// ```
+///
+/// For serialization `O` needs to be `O: Into<T> + Clone`.
+/// For deserialization the opposite `T: Into<O>` is required.
+/// The `Clone` bound is required since `serialize` operates on a reference but `Into` implementations on references are uncommon.
+///
+/// **Note**: [`TryFromInto`] is the more generalized version of this adapter which uses the [`TryInto`](std::convert::TryInto) trait instead.
+///
+/// # Example
+///
+/// ```rust
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// # use serde_with::{serde_as, FromInto};
+/// #
+/// #[derive(Clone, Debug, PartialEq)]
+/// struct Rgb {
+/// red: u8,
+/// green: u8,
+/// blue: u8,
+/// }
+///
+/// # /*
+/// impl From<(u8, u8, u8)> for Rgb { ... }
+/// impl From<Rgb> for (u8, u8, u8) { ... }
+/// # */
+/// #
+/// # impl From<(u8, u8, u8)> for Rgb {
+/// # fn from(v: (u8, u8, u8)) -> Self {
+/// # Rgb {
+/// # red: v.0,
+/// # green: v.1,
+/// # blue: v.2,
+/// # }
+/// # }
+/// # }
+/// #
+/// # impl From<Rgb> for (u8, u8, u8) {
+/// # fn from(v: Rgb) -> Self {
+/// # (v.red, v.green, v.blue)
+/// # }
+/// # }
+///
+/// #[serde_as]
+/// # #[derive(Debug, PartialEq)]
+/// #[derive(Deserialize, Serialize)]
+/// struct Color {
+/// #[serde_as(as = "FromInto<(u8, u8, u8)>")]
+/// rgb: Rgb,
+/// }
+/// let color = Color {
+/// rgb: Rgb {
+/// red: 128,
+/// green: 64,
+/// blue: 32,
+/// },
+/// };
+///
+/// // Define our expected JSON form
+/// let j = json!({
+/// "rgb": [128, 64, 32],
+/// });
+/// // Ensure serialization and deserialization produce the expected results
+/// assert_eq!(j, serde_json::to_value(&color).unwrap());
+/// assert_eq!(color, serde_json::from_value(j).unwrap());
+/// # }
+/// ```
+pub struct FromInto<T>(PhantomData<T>);
+
+/// Serialize value by converting to/from a proxy type with serde support.
+///
+/// This adapter serializes a type `O` by converting it into a second type `T` and serializing `T`.
+/// Deserializing works analogue, by deserializing a `T` and then converting into `O`.
+///
+/// ```rust
+/// # #[cfg(FALSE)] {
+/// struct S {
+/// #[serde_as(as = "TryFromInto<T>")]
+/// value: O,
+/// }
+/// # }
+/// ```
+///
+/// For serialization `O` needs to be `O: TryInto<T> + Clone`.
+/// For deserialization the opposite `T: TryInto<O>` is required.
+/// The `Clone` bound is required since `serialize` operates on a reference but `TryInto` implementations on references are uncommon.
+/// In both cases the `TryInto::Error` type must implement [`Display`](std::fmt::Display).
+///
+/// **Note**: [`FromInto`] is the more specialized version of this adapter which uses the infallible [`Into`] trait instead.
+/// [`TryFromInto`] is strictly more general and can also be used where [`FromInto`] is applicable.
+/// The example shows a use case, when only the deserialization behavior is fallible, but not serializing.
+///
+/// # Example
+///
+/// ```rust
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// # use serde_with::{serde_as, TryFromInto};
+/// # use std::convert::TryFrom;
+/// #
+/// #[derive(Clone, Debug, PartialEq)]
+/// enum Boollike {
+/// True,
+/// False,
+/// }
+///
+/// # /*
+/// impl From<Boollike> for u8 { ... }
+/// # */
+/// #
+/// impl TryFrom<u8> for Boollike {
+/// type Error = String;
+/// fn try_from(v: u8) -> Result<Self, Self::Error> {
+/// match v {
+/// 0 => Ok(Boollike::False),
+/// 1 => Ok(Boollike::True),
+/// _ => Err(format!("Boolikes can only be constructed from 0 or 1 but found {}", v))
+/// }
+/// }
+/// }
+/// #
+/// # impl From<Boollike> for u8 {
+/// # fn from(v: Boollike) -> Self {
+/// # match v {
+/// # Boollike::True => 1,
+/// # Boollike::False => 0,
+/// # }
+/// # }
+/// # }
+///
+/// #[serde_as]
+/// # #[derive(Debug, PartialEq)]
+/// #[derive(Deserialize, Serialize)]
+/// struct Data {
+/// #[serde_as(as = "TryFromInto<u8>")]
+/// b: Boollike,
+/// }
+/// let data = Data {
+/// b: Boollike::True,
+/// };
+///
+/// // Define our expected JSON form
+/// let j = json!({
+/// "b": 1,
+/// });
+/// // Ensure serialization and deserialization produce the expected results
+/// assert_eq!(j, serde_json::to_value(&data).unwrap());
+/// assert_eq!(data, serde_json::from_value(j).unwrap());
+///
+/// // Numbers besides 0 or 1 should be an error
+/// let j = json!({
+/// "b": 2,
+/// });
+/// assert_eq!("Boolikes can only be constructed from 0 or 1 but found 2", serde_json::from_value::<Data>(j).unwrap_err().to_string());
+/// # }
+/// ```
+pub struct TryFromInto<T>(PhantomData<T>);
+
+/// Borrow `Cow` data during deserialization when possible.
+///
+/// The types `Cow<'a, [u8]>`, `Cow<'a, [u8; N]>`, and `Cow<'a, str>` can borrow from the input data during deserialization.
+/// serde supports this, by annotating the fields with `#[serde(borrow)]`. but does not support borrowing on nested types.
+/// This gap is filled by this `BorrowCow` adapter.
+///
+/// Using this adapter with `Cow<'a, [u8]>`/`Cow<'a, [u8; N]>` will serialize the value as a sequence of `u8` values.
+/// This *might* not allow to borrow the data during deserialization.
+/// For a different format, which is also more efficient, use the [`Bytes`] adapter, which is also implemented for `Cow`.
+///
+/// When combined with the [`serde_as`] attribute, the `#[serde(borrow)]` annotation will be added automatically.
+/// If the annotation is wrong or too broad, for example because of multiple lifetime parameters, a manual annotation is required.
+///
+/// # Examples
+///
+/// ```rust
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_with::{serde_as, BorrowCow};
+/// # use std::borrow::Cow;
+/// #
+/// #[serde_as]
+/// # #[derive(Debug, PartialEq)]
+/// #[derive(Deserialize, Serialize)]
+/// struct Data<'a, 'b, 'c> {
+/// #[serde_as(as = "BorrowCow")]
+/// str: Cow<'a, str>,
+/// #[serde_as(as = "BorrowCow")]
+/// slice: Cow<'b, [u8]>,
+///
+/// #[serde_as(as = "Option<[BorrowCow; 1]>")]
+/// nested: Option<[Cow<'c, str>; 1]>,
+/// }
+/// let data = Data {
+/// str: "foobar".into(),
+/// slice: b"foobar"[..].into(),
+/// nested: Some(["HelloWorld".into()]),
+/// };
+///
+/// // Define our expected JSON form
+/// let j = r#"{
+/// "str": "foobar",
+/// "slice": [
+/// 102,
+/// 111,
+/// 111,
+/// 98,
+/// 97,
+/// 114
+/// ],
+/// "nested": [
+/// "HelloWorld"
+/// ]
+/// }"#;
+/// // Ensure serialization and deserialization produce the expected results
+/// assert_eq!(j, serde_json::to_string_pretty(&data).unwrap());
+/// assert_eq!(data, serde_json::from_str(j).unwrap());
+///
+/// // Cow borrows from the input data
+/// let deserialized: Data<'_, '_, '_> = serde_json::from_str(j).unwrap();
+/// assert!(matches!(deserialized.str, Cow::Borrowed(_)));
+/// assert!(matches!(deserialized.nested, Some([Cow::Borrowed(_)])));
+/// // JSON does not allow borrowing bytes, so `slice` does not borrow
+/// assert!(matches!(deserialized.slice, Cow::Owned(_)));
+/// # }
+/// ```
+#[cfg(feature = "alloc")]
+pub struct BorrowCow;
+
+/// Deserialize a sequence into `Vec<T>`, skipping elements which fail to deserialize.
+///
+/// The serialization behavior is identical to `Vec<T>`. This is an alternative to `Vec<T>`
+/// which is resilient against unexpected data.
+///
+/// # Examples
+///
+/// ```rust
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_with::{serde_as, VecSkipError};
+/// #
+/// # #[derive(Debug, PartialEq)]
+/// #[derive(Deserialize, Serialize)]
+/// # #[non_exhaustive]
+/// enum Color {
+/// Red,
+/// Green,
+/// Blue,
+/// }
+/// # use Color::*;
+/// #[serde_as]
+/// # #[derive(Debug, PartialEq)]
+/// #[derive(Deserialize, Serialize)]
+/// struct Palette(#[serde_as(as = "VecSkipError<_>")] Vec<Color>);
+///
+/// let data = Palette(vec![Blue, Green,]);
+/// let source_json = r#"["Blue", "Yellow", "Green"]"#;
+/// let data_json = r#"["Blue","Green"]"#;
+/// // Ensure serialization and deserialization produce the expected results
+/// assert_eq!(data_json, serde_json::to_string(&data).unwrap());
+/// assert_eq!(data, serde_json::from_str(source_json).unwrap());
+/// # }
+/// ```
+#[cfg(feature = "alloc")]
+pub struct VecSkipError<T>(PhantomData<T>);
+
+/// Deserialize a boolean from a number
+///
+/// Deserialize a number (of `u8`) and turn it into a boolean.
+/// The adapter supports a [`Strict`](crate::formats::Strict) and [`Flexible`](crate::formats::Flexible) format.
+/// In `Strict` mode, the number must be `0` or `1`.
+/// All other values produce an error.
+/// In `Flexible` mode, the number any non-zero value is converted to `true`.
+///
+/// During serialization only `0` or `1` are ever emitted.
+///
+/// # Examples
+///
+/// ```rust
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// # use serde_with::{serde_as, BoolFromInt};
+/// #
+/// #[serde_as]
+/// # #[derive(Debug, PartialEq)]
+/// #[derive(Deserialize, Serialize)]
+/// struct Data(#[serde_as(as = "BoolFromInt")] bool);
+///
+/// let data = Data(true);
+/// let j = json!(1);
+/// // Ensure serialization and deserialization produce the expected results
+/// assert_eq!(j, serde_json::to_value(&data).unwrap());
+/// assert_eq!(data, serde_json::from_value(j).unwrap());
+///
+/// // false maps to 0
+/// let data = Data(false);
+/// let j = json!(0);
+/// assert_eq!(j, serde_json::to_value(&data).unwrap());
+/// assert_eq!(data, serde_json::from_value(j).unwrap());
+//
+/// #[serde_as]
+/// # #[derive(Debug, PartialEq)]
+/// #[derive(Deserialize, Serialize)]
+/// struct Flexible(#[serde_as(as = "BoolFromInt<serde_with::formats::Flexible>")] bool);
+///
+/// // Flexible turns any non-zero number into true
+/// let data = Flexible(true);
+/// let j = json!(100);
+/// assert_eq!(data, serde_json::from_value(j).unwrap());
+/// # }
+/// ```
+pub struct BoolFromInt<S: formats::Strictness = formats::Strict>(PhantomData<S>);
+
+/// De/Serialize a delimited collection using [`Display`] and [`FromStr`] implementation
+///
+/// `StringWithSeparator` takes a second type, which needs to implement [`Display`]+[`FromStr`] and constitutes the inner type of the collection.
+/// 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
+///
+/// ```
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// #
+/// # use serde_with::{serde_as, StringWithSeparator};
+/// use serde_with::formats::{CommaSeparator, SpaceSeparator};
+/// use std::collections::BTreeSet;
+///
+/// #[serde_as]
+/// #[derive(Deserialize, Serialize)]
+/// struct A {
+/// #[serde_as(as = "StringWithSeparator::<SpaceSeparator, String>")]
+/// tags: Vec<String>,
+/// #[serde_as(as = "StringWithSeparator::<CommaSeparator, String>")]
+/// 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()
+/// );
+/// # }
+/// ```
+///
+/// [`Display`]: core::fmt::Display
+/// [`FromStr`]: core::str::FromStr
+/// [`Separator`]: crate::formats::Separator
+/// [`serde_as`]: crate::guide::serde_as
+pub struct StringWithSeparator<Sep, T>(PhantomData<(Sep, T)>);
+
+/// This serializes a list of tuples into a map
+///
+/// Normally, you want to use a [`HashMap`] or a [`BTreeMap`] when deserializing a map.
+/// However, sometimes this is not possible due to type constraints, e.g., if the type implements neither [`Hash`] nor [`Ord`].
+/// Another use case is deserializing a map with duplicate keys.
+///
+/// # Examples
+///
+/// `Wrapper` does not implement [`Hash`] nor [`Ord`], thus prohibiting the use [`HashMap`] or [`BTreeMap`].
+/// The JSON also contains a duplicate key.
+///
+/// [`BTreeMap`]: std::collections::BTreeMap
+/// [`HashMap`]: std::collections::HashMap
+/// [`Vec`]: std::vec::Vec
+///
+/// ```rust
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// # use serde_with::{serde_as, Map};
+/// #
+/// #[serde_as]
+/// #[derive(Debug, Deserialize, Serialize, Default)]
+/// struct S {
+/// #[serde_as(as = "Map<_, _>")]
+/// s: Vec<(Wrapper<i32>, String)>,
+/// }
+///
+/// #[derive(Clone, Debug, Serialize, Deserialize)]
+/// #[serde(transparent)]
+/// struct Wrapper<T>(T);
+///
+/// let data = S {
+/// s: vec![
+/// (Wrapper(1), "a".to_string()),
+/// (Wrapper(2), "b".to_string()),
+/// (Wrapper(3), "c".to_string()),
+/// (Wrapper(2), "d".to_string()),
+/// ],
+/// };
+///
+/// let json = r#"{
+/// "s": {
+/// "1": "a",
+/// "2": "b",
+/// "3": "c",
+/// "2": "d"
+/// }
+/// }"#;
+/// assert_eq!(json, serde_json::to_string_pretty(&data).unwrap());
+/// # }
+/// ```
+pub struct Map<K, V>(PhantomData<(K, V)>);
+
+/// De/Serialize a Map into a list of tuples
+///
+/// Some formats, like JSON, have limitations on the types of keys for maps.
+/// In case of JSON, keys are restricted to strings.
+/// Rust features more powerful keys, for example tuples, which can not be serialized to JSON.
+///
+/// This helper serializes the Map into a list of tuples, which do not have the same type restrictions.
+///
+/// # Examples
+///
+/// ```rust
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Deserialize, Serialize};
+/// # use serde_json::json;
+/// # use serde_with::{serde_as, Seq};
+/// # use std::collections::BTreeMap;
+/// #
+/// #[serde_as]
+/// # #[derive(Debug, PartialEq)]
+/// #[derive(Deserialize, Serialize)]
+/// struct A {
+/// #[serde_as(as = "Seq<(_, _)>")]
+/// s: BTreeMap<(String, u32), u32>,
+/// }
+///
+/// // This converts the Rust type
+/// let data = A {
+/// s: BTreeMap::from([
+/// (("Hello".to_string(), 123), 0),
+/// (("World".to_string(), 456), 1),
+/// ]),
+/// };
+///
+/// // into this JSON
+/// let value = json!({
+/// "s": [
+/// [["Hello", 123], 0],
+/// [["World", 456], 1]
+/// ]
+/// });
+///
+/// assert_eq!(value, serde_json::to_value(&data).unwrap());
+/// assert_eq!(data, serde_json::from_value(value).unwrap());
+/// # }
+/// ```
+pub struct Seq<V>(PhantomData<V>);
+
+/// 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
+/// # #[cfg(feature = "macros")] {
+/// # use serde::Deserialize;
+/// # use std::collections::HashMap;
+/// # use serde_with::{serde_as, MapPreventDuplicates};
+/// #
+/// #[serde_as]
+/// # #[derive(Debug, Eq, PartialEq)]
+/// #[derive(Deserialize)]
+/// struct Doc {
+/// #[serde_as(as = "MapPreventDuplicates<_, _>")]
+/// 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());
+/// # }
+/// ```
+#[cfg(feature = "alloc")]
+pub struct MapPreventDuplicates<K, V>(PhantomData<(K, V)>);
+
+/// Ensure that the last value is taken, if duplicate values exist
+///
+/// By default serde has a first-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
+#[cfg(feature = "alloc")]
+pub struct MapFirstKeyWins<K, V>(PhantomData<(K, V)>);
+
+/// 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
+/// # #[cfg(feature = "macros")] {
+/// # use std::collections::HashSet;
+/// # use serde::Deserialize;
+/// # use serde_with::{serde_as, SetPreventDuplicates};
+/// #
+/// #[serde_as]
+/// # #[derive(Debug, Eq, PartialEq)]
+/// #[derive(Deserialize)]
+/// struct Doc {
+/// #[serde_as(as = "SetPreventDuplicates<_>")]
+/// 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());
+/// # }
+/// ```
+#[cfg(feature = "alloc")]
+pub struct SetPreventDuplicates<T>(PhantomData<T>);
+
+/// Ensure that the last value is taken, if duplicate values exist
+///
+/// By default serde has a first-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
+#[cfg(feature = "alloc")]
+pub struct SetLastValueWins<T>(PhantomData<T>);
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..acfca714b8
--- /dev/null
+++ b/third_party/rust/serde_with/src/rust.rs
@@ -0,0 +1,712 @@
+//! De/Serialization for Rust's builtin and std types
+
+use crate::prelude::*;
+
+/// 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.
+///
+/// Note: This cannot be made compatible to `serde_as`, since skipping of values is only available on the field level.
+/// A hypothetical `DoubleOption<T>` with a `SerializeAs` implementation would allow writing something like this.
+/// This cannot work, since there is no way to tell the `Vec` to skip the inner `DoubleOption` if it is `None`.
+///
+/// ```rust
+/// # #[cfg(FALSE)] {
+/// # struct Foobar {
+/// #[serde_as(as = "Vec<DoubleOption<_>>")]
+/// data: Vec<Option<Option<i32>>>,
+/// # }
+/// # }
+/// ```
+///
+/// # Examples
+///
+/// ```rust
+/// # use serde::{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());
+/// ```
+#[allow(clippy::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
+/// # use serde::{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()
+/// # .new_line("\n".into());
+/// 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()
+/// # .new_line("\n".into());
+/// 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.
+///
+/// # Converting to serde_as
+///
+/// The same functionality can be more clearly expressed using the `serde_as` macro and [`SetPreventDuplicates`].
+/// The `_` is a placeholder which works for any type which implements [`Serialize`]/[`Deserialize`].
+///
+/// ```rust
+/// # #[cfg(FALSE)] {
+/// #[serde_as]
+/// #[derive(Deserialize, Serialize)]
+/// struct A {
+/// #[serde_as(as = "SetPreventDuplicates<_, _>")]
+/// s: HashSet<usize>,
+/// }
+/// # }
+/// ```
+///
+/// [`HashSet`]: std::collections::HashSet
+/// [`BTreeSet`]: std::collections::HashSet
+///
+/// # Example
+///
+/// ```rust
+/// # use std::collections::HashSet;
+/// # use serde::Deserialize;
+/// #
+/// # #[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());
+/// ```
+#[cfg(feature = "alloc")]
+pub mod sets_duplicate_value_is_error {
+ use super::*;
+ use crate::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(DeError::custom("invalid entry: found duplicate value"));
+ };
+ }
+
+ Ok(values)
+ }
+ }
+
+ let visitor = SeqVisitor {
+ marker: PhantomData,
+ set_item_type: PhantomData,
+ };
+ deserializer.deserialize_seq(visitor)
+ }
+
+ /// Serialize the set with the default serializer
+ pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ T: Serialize,
+ S: Serializer,
+ {
+ value.serialize(serializer)
+ }
+}
+
+/// 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.
+///
+/// # Converting to serde_as
+///
+/// The same functionality can be more clearly expressed using the `serde_as` macro and [`MapPreventDuplicates`].
+/// The `_` is a placeholder which works for any type which implements [`Serialize`]/[`Deserialize`].
+///
+/// ```rust
+/// # #[cfg(FALSE)] {
+/// #[serde_as]
+/// #[derive(Deserialize, Serialize)]
+/// struct A {
+/// #[serde_as(as = "MapPreventDuplicates<_, _>")]
+/// s: HashMap<usize, usize>,
+/// }
+/// # }
+/// ```
+///
+/// [`HashMap`]: std::collections::HashMap
+/// [`BTreeMap`]: std::collections::HashMap
+///
+/// # Example
+///
+/// ```rust
+/// # use serde::Deserialize;
+/// # 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());
+/// ```
+#[cfg(feature = "alloc")]
+pub mod maps_duplicate_key_is_error {
+ use super::*;
+ use crate::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(DeError::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)
+ }
+
+ /// Serialize the map with the default serializer
+ pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ T: Serialize,
+ S: Serializer,
+ {
+ value.serialize(serializer)
+ }
+}
+
+/// Ensure that the last value is taken, if duplicate values exist
+///
+/// By default serde has a first-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.
+///
+/// # Converting to serde_as
+///
+/// The same functionality can be more clearly expressed using the `serde_as` macro and [`SetLastValueWins`].
+/// The `_` is a placeholder which works for any type which implements [`Serialize`]/[`Deserialize`].
+///
+/// ```rust
+/// # #[cfg(FALSE)] {
+/// #[serde_as]
+/// #[derive(Deserialize, Serialize)]
+/// struct A {
+/// #[serde_as(as = "SetLastValueWins<_, _>")]
+/// s: HashSet<usize>,
+/// }
+/// # }
+/// ```
+///
+/// [`HashSet`]: std::collections::HashSet
+/// [`BTreeSet`]: std::collections::HashSet
+#[cfg(feature = "alloc")]
+pub mod sets_last_value_wins {
+ use super::*;
+ use crate::duplicate_key_impls::DuplicateInsertsLastWinsSet;
+
+ /// Deserialize a set and keep the last of equal values
+ pub fn deserialize<'de, D, T, V>(deserializer: D) -> Result<T, D::Error>
+ where
+ T: DuplicateInsertsLastWinsSet<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: DuplicateInsertsLastWinsSet<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.replace(value);
+ }
+
+ Ok(values)
+ }
+ }
+
+ let visitor = SeqVisitor {
+ marker: PhantomData,
+ set_item_type: PhantomData,
+ };
+ deserializer.deserialize_seq(visitor)
+ }
+
+ /// Serialize the set with the default serializer
+ pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ T: Serialize,
+ S: Serializer,
+ {
+ value.serialize(serializer)
+ }
+}
+
+/// 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
+///
+/// # Converting to serde_as
+///
+/// The same functionality can be more clearly expressed using the `serde_as` macro and [`MapFirstKeyWins`].
+/// The `_` is a placeholder which works for any type which implements [`Serialize`]/[`Deserialize`].
+///
+/// ```rust
+/// # #[cfg(FALSE)] {
+/// #[serde_as]
+/// #[derive(Deserialize, Serialize)]
+/// struct A {
+/// #[serde_as(as = "MapFirstKeyWins<_, _>")]
+/// s: HashMap<usize, usize>,
+/// }
+/// # }
+/// ```
+///
+/// # Example
+///
+/// ```rust
+/// # use serde::Deserialize;
+/// # 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());
+/// ```
+#[cfg(feature = "alloc")]
+pub mod maps_first_key_wins {
+ use super::*;
+ use crate::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)
+ }
+
+ /// Serialize the map with the default serializer
+ pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ T: Serialize,
+ S: Serializer,
+ {
+ value.serialize(serializer)
+ }
+}
+
+/// Deserialize any value, ignore it, and return the default value for the type being deserialized.
+///
+/// This function can be used in two different ways:
+///
+/// 1. It is useful for instance to create an enum with a catch-all variant that will accept any incoming data.
+/// 2. [`untagged`] enum representations do not allow the `other` annotation as the fallback enum variant.
+/// With this function you can emulate an `other` variant, which can deserialize any data carrying enum.
+///
+/// **Note:** Using this function will prevent deserializing data-less enum variants.
+/// If this is a problem depends on the data format.
+/// For example, deserializing `"Bar"` as an enum in JSON would fail, since it carries no data.
+///
+/// # Examples
+///
+/// ## Deserializing a heterogeneous collection of XML nodes
+///
+/// When [`serde-xml-rs`] deserializes an XML tag to an enum, it always maps the tag
+/// name to the enum variant name, and the tag attributes and children to the enum contents.
+/// This means that in order for an enum variant to accept any XML tag, it both has to use
+/// `#[serde(other)]` to accept any tag name, and `#[serde(deserialize_with = "deserialize_ignore_any")]`
+/// to accept any attributes and children.
+///
+/// ```rust
+/// # use serde::Deserialize;
+/// use serde_with::rust::deserialize_ignore_any;
+///
+/// # #[derive(Debug, PartialEq)]
+/// #[derive(Deserialize)]
+/// #[serde(rename_all = "lowercase")]
+/// enum Item {
+/// Foo(String),
+/// Bar(String),
+/// #[serde(other, deserialize_with = "deserialize_ignore_any")]
+/// Other,
+/// }
+///
+/// // Deserialize this XML
+/// # let items: Vec<Item> = serde_xml_rs::from_str(
+/// r"
+/// <foo>a</foo>
+/// <bar>b</bar>
+/// <foo>c</foo>
+/// <unknown>d</unknown>
+/// "
+/// # ).unwrap();
+///
+/// // into these Items
+/// # let expected =
+/// vec![
+/// Item::Foo(String::from("a")),
+/// Item::Bar(String::from("b")),
+/// Item::Foo(String::from("c")),
+/// Item::Other,
+/// ]
+/// # ;
+/// # assert_eq!(expected, items);
+/// ```
+///
+/// ## Simulating an `other` enum variant in an `untagged` enum
+///
+/// ```rust
+/// # use serde::Deserialize;
+/// # use serde_json::json;
+/// use serde_with::rust::deserialize_ignore_any;
+///
+/// # #[derive(Debug, PartialEq)]
+/// #[derive(Deserialize)]
+/// #[serde(untagged)]
+/// enum Item {
+/// Foo{x: u8},
+/// #[serde(deserialize_with = "deserialize_ignore_any")]
+/// Other,
+/// }
+///
+/// // Deserialize this JSON
+/// # let items: Vec<Item> = serde_json::from_value(
+/// json!([
+/// {"y": 1},
+/// {"x": 1},
+/// ])
+/// # ).unwrap();
+///
+/// // into these Items
+/// # let expected =
+/// vec![Item::Other, Item::Foo{x: 1}]
+/// # ;
+/// # assert_eq!(expected, items);
+/// ```
+///
+/// [`serde-xml-rs`]: https://docs.rs/serde-xml-rs
+/// [`untagged`]: https://serde.rs/enum-representations.html#untagged
+pub fn deserialize_ignore_any<'de, D: Deserializer<'de>, T: Default>(
+ deserializer: D,
+) -> Result<T, D::Error> {
+ serde::de::IgnoredAny::deserialize(deserializer).map(|_| T::default())
+}
diff --git a/third_party/rust/serde_with/src/ser/duplicates.rs b/third_party/rust/serde_with/src/ser/duplicates.rs
new file mode 100644
index 0000000000..d70f48dfd0
--- /dev/null
+++ b/third_party/rust/serde_with/src/ser/duplicates.rs
@@ -0,0 +1,70 @@
+use super::impls::{foreach_map, foreach_set};
+use crate::{
+ prelude::*, MapFirstKeyWins, MapPreventDuplicates, SetLastValueWins, SetPreventDuplicates,
+};
+#[cfg(feature = "indexmap_1")]
+use indexmap_1::{IndexMap, IndexSet};
+
+macro_rules! set_duplicate_handling {
+ ($tyorig:ident < T $(, $typaram:ident : $bound:ident)* >) => {
+ impl<T, TAs $(, $typaram)*> SerializeAs<$tyorig<T $(, $typaram)*>> for SetPreventDuplicates<TAs>
+ where
+ TAs: SerializeAs<T>,
+ $($typaram: ?Sized + $bound,)*
+ {
+ fn serialize_as<S>(value: &$tyorig<T $(, $typaram)*>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ <$tyorig<TAs $(, $typaram)*>>::serialize_as(value, serializer)
+ }
+ }
+
+ impl<T, TAs $(, $typaram)*> SerializeAs<$tyorig<T $(, $typaram)*>> for SetLastValueWins<TAs>
+ where
+ TAs: SerializeAs<T>,
+ $($typaram: ?Sized + $bound,)*
+ {
+ fn serialize_as<S>(value: &$tyorig<T $(, $typaram)*>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ <$tyorig<TAs $(, $typaram)*>>::serialize_as(value, serializer)
+ }
+ }
+ }
+}
+foreach_set!(set_duplicate_handling);
+
+macro_rules! map_duplicate_handling {
+ ($tyorig:ident < K, V $(, $typaram:ident : $bound:ident)* >) => {
+ impl<K, KAs, V, VAs $(, $typaram)*> SerializeAs<$tyorig<K, V $(, $typaram)*>> for MapPreventDuplicates<KAs, VAs>
+ where
+ KAs: SerializeAs<K>,
+ VAs: SerializeAs<V>,
+ $($typaram: ?Sized + $bound,)*
+ {
+ fn serialize_as<S>(value: &$tyorig<K, V $(, $typaram)*>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ <$tyorig<KAs, VAs $(, $typaram)*>>::serialize_as(value, serializer)
+ }
+ }
+
+ impl<K, KAs, V, VAs $(, $typaram)*> SerializeAs<$tyorig<K, V $(, $typaram)*>> for MapFirstKeyWins<KAs, VAs>
+ where
+ KAs: SerializeAs<K>,
+ VAs: SerializeAs<V>,
+ $($typaram: ?Sized + $bound,)*
+ {
+ fn serialize_as<S>(value: &$tyorig<K, V $(, $typaram)*>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ <$tyorig<KAs, VAs $(, $typaram)*>>::serialize_as(value, serializer)
+ }
+ }
+ }
+}
+foreach_map!(map_duplicate_handling);
diff --git a/third_party/rust/serde_with/src/ser/impls.rs b/third_party/rust/serde_with/src/ser/impls.rs
new file mode 100644
index 0000000000..0075a8b853
--- /dev/null
+++ b/third_party/rust/serde_with/src/ser/impls.rs
@@ -0,0 +1,919 @@
+use crate::{formats, formats::Strictness, prelude::*};
+#[cfg(feature = "indexmap_1")]
+use indexmap_1::{IndexMap, IndexSet};
+
+///////////////////////////////////////////////////////////////////////////////
+// Helper macro used internally
+
+#[cfg(feature = "alloc")]
+type BoxedSlice<T> = Box<[T]>;
+type Slice<T> = [T];
+
+macro_rules! foreach_map {
+ ($m:ident) => {
+ #[cfg(feature = "alloc")]
+ $m!(BTreeMap<K, V>);
+ #[cfg(feature = "std")]
+ $m!(HashMap<K, V, H: Sized>);
+ #[cfg(all(feature = "indexmap_1"))]
+ $m!(IndexMap<K, V, H: Sized>);
+ };
+}
+pub(crate) use foreach_map;
+
+macro_rules! foreach_set {
+ ($m:ident, $T:tt) => {
+ #[cfg(feature = "alloc")]
+ $m!(BTreeSet<$T>);
+ #[cfg(feature = "std")]
+ $m!(HashSet<$T, H: Sized>);
+ #[cfg(all(feature = "indexmap_1"))]
+ $m!(IndexSet<$T, H: Sized>);
+ };
+ ($m:ident) => {
+ foreach_set!($m, T);
+ };
+}
+pub(crate) use foreach_set;
+
+macro_rules! foreach_seq {
+ ($m:ident, $T:tt) => {
+ foreach_set!($m, $T);
+
+ $m!(Slice<$T>);
+
+ #[cfg(feature = "alloc")]
+ $m!(BinaryHeap<$T>);
+ #[cfg(feature = "alloc")]
+ $m!(BoxedSlice<$T>);
+ #[cfg(feature = "alloc")]
+ $m!(LinkedList<$T>);
+ #[cfg(feature = "alloc")]
+ $m!(Vec<$T>);
+ #[cfg(feature = "alloc")]
+ $m!(VecDeque<$T>);
+ };
+ ($m:ident) => {
+ foreach_seq!($m, T);
+ };
+}
+pub(crate) use foreach_seq;
+
+///////////////////////////////////////////////////////////////////////////////
+// region: Simple Wrapper types (e.g., Box, Option)
+
+impl<'a, T, U> SerializeAs<&'a T> for &'a U
+where
+ U: SerializeAs<T>,
+ T: ?Sized,
+ U: ?Sized,
+{
+ fn serialize_as<S>(source: &&'a T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ SerializeAsWrap::<T, U>::new(source).serialize(serializer)
+ }
+}
+
+impl<'a, T, U> SerializeAs<&'a mut T> for &'a mut U
+where
+ U: SerializeAs<T>,
+ T: ?Sized,
+ U: ?Sized,
+{
+ fn serialize_as<S>(source: &&'a mut T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ SerializeAsWrap::<T, U>::new(source).serialize(serializer)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<T, U> SerializeAs<Box<T>> for Box<U>
+where
+ U: SerializeAs<T>,
+{
+ fn serialize_as<S>(source: &Box<T>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ SerializeAsWrap::<T, U>::new(source).serialize(serializer)
+ }
+}
+
+impl<T, U> SerializeAs<Option<T>> for Option<U>
+where
+ U: SerializeAs<T>,
+{
+ fn serialize_as<S>(source: &Option<T>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ match *source {
+ Some(ref value) => serializer.serialize_some(&SerializeAsWrap::<T, U>::new(value)),
+ None => serializer.serialize_none(),
+ }
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<T, U> SerializeAs<Rc<T>> for Rc<U>
+where
+ U: SerializeAs<T>,
+{
+ fn serialize_as<S>(source: &Rc<T>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ SerializeAsWrap::<T, U>::new(source).serialize(serializer)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<T, U> SerializeAs<RcWeak<T>> for RcWeak<U>
+where
+ U: SerializeAs<T>,
+{
+ fn serialize_as<S>(source: &RcWeak<T>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ SerializeAsWrap::<Option<Rc<T>>, Option<Rc<U>>>::new(&source.upgrade())
+ .serialize(serializer)
+ }
+}
+
+#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
+impl<T, U> SerializeAs<Arc<T>> for Arc<U>
+where
+ U: SerializeAs<T>,
+{
+ fn serialize_as<S>(source: &Arc<T>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ SerializeAsWrap::<T, U>::new(source).serialize(serializer)
+ }
+}
+
+#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
+impl<T, U> SerializeAs<ArcWeak<T>> for ArcWeak<U>
+where
+ U: SerializeAs<T>,
+{
+ fn serialize_as<S>(source: &ArcWeak<T>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ SerializeAsWrap::<Option<Arc<T>>, Option<Arc<U>>>::new(&source.upgrade())
+ .serialize(serializer)
+ }
+}
+
+impl<T, U> SerializeAs<Cell<T>> for Cell<U>
+where
+ U: SerializeAs<T>,
+ T: Copy,
+{
+ fn serialize_as<S>(source: &Cell<T>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ SerializeAsWrap::<T, U>::new(&source.get()).serialize(serializer)
+ }
+}
+
+impl<T, U> SerializeAs<RefCell<T>> for RefCell<U>
+where
+ U: SerializeAs<T>,
+{
+ fn serialize_as<S>(source: &RefCell<T>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ match source.try_borrow() {
+ Ok(source) => SerializeAsWrap::<T, U>::new(&*source).serialize(serializer),
+ Err(_) => Err(S::Error::custom("already mutably borrowed")),
+ }
+ }
+}
+
+#[cfg(feature = "std")]
+impl<T, U> SerializeAs<Mutex<T>> for Mutex<U>
+where
+ U: SerializeAs<T>,
+{
+ fn serialize_as<S>(source: &Mutex<T>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ match source.lock() {
+ Ok(source) => SerializeAsWrap::<T, U>::new(&*source).serialize(serializer),
+ Err(_) => Err(S::Error::custom("lock poison error while serializing")),
+ }
+ }
+}
+
+#[cfg(feature = "std")]
+impl<T, U> SerializeAs<RwLock<T>> for RwLock<U>
+where
+ U: SerializeAs<T>,
+{
+ fn serialize_as<S>(source: &RwLock<T>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ match source.read() {
+ Ok(source) => SerializeAsWrap::<T, U>::new(&*source).serialize(serializer),
+ Err(_) => Err(S::Error::custom("lock poison error while serializing")),
+ }
+ }
+}
+
+impl<T, TAs, E, EAs> SerializeAs<Result<T, E>> for Result<TAs, EAs>
+where
+ TAs: SerializeAs<T>,
+ EAs: SerializeAs<E>,
+{
+ fn serialize_as<S>(source: &Result<T, E>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ source
+ .as_ref()
+ .map(SerializeAsWrap::<T, TAs>::new)
+ .map_err(SerializeAsWrap::<E, EAs>::new)
+ .serialize(serializer)
+ }
+}
+
+impl<T, As, const N: usize> SerializeAs<[T; N]> for [As; N]
+where
+ As: SerializeAs<T>,
+{
+ fn serialize_as<S>(array: &[T; N], serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ let mut arr = serializer.serialize_tuple(N)?;
+ for elem in array {
+ arr.serialize_element(&SerializeAsWrap::<T, As>::new(elem))?;
+ }
+ arr.end()
+ }
+}
+
+// endregion
+///////////////////////////////////////////////////////////////////////////////
+// region: Collection Types (e.g., Maps, Sets, Vec)
+
+macro_rules! seq_impl {
+ ($ty:ident < T $(: $tbound1:ident $(+ $tbound2:ident)*)* $(, $typaram:ident : $bound:ident )* >) => {
+ impl<T, U $(, $typaram)*> SerializeAs<$ty<T $(, $typaram)*>> for $ty<U $(, $typaram)*>
+ where
+ U: SerializeAs<T>,
+ $(T: ?Sized + $tbound1 $(+ $tbound2)*,)*
+ $($typaram: ?Sized + $bound,)*
+ {
+ fn serialize_as<S>(source: &$ty<T $(, $typaram)*>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serializer.collect_seq(source.iter().map(|item| SerializeAsWrap::<T, U>::new(item)))
+ }
+ }
+ }
+}
+foreach_seq!(seq_impl);
+
+#[cfg(feature = "alloc")]
+macro_rules! map_impl {
+ ($ty:ident < K, V $(, $typaram:ident : $bound:ident)* >) => {
+ impl<K, KU, V, VU $(, $typaram)*> SerializeAs<$ty<K, V $(, $typaram)*>> for $ty<KU, VU $(, $typaram)*>
+ where
+ KU: SerializeAs<K>,
+ VU: SerializeAs<V>,
+ $($typaram: ?Sized + $bound,)*
+ {
+ fn serialize_as<S>(source: &$ty<K, V $(, $typaram)*>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serializer.collect_map(source.iter().map(|(k, v)| (SerializeAsWrap::<K, KU>::new(k), SerializeAsWrap::<V, VU>::new(v))))
+ }
+ }
+ }
+}
+foreach_map!(map_impl);
+
+macro_rules! tuple_impl {
+ ($len:literal $($n:tt $t:ident $tas:ident)+) => {
+ impl<$($t, $tas,)+> SerializeAs<($($t,)+)> for ($($tas,)+)
+ where
+ $($tas: SerializeAs<$t>,)+
+ {
+ fn serialize_as<S>(tuple: &($($t,)+), serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ use serde::ser::SerializeTuple;
+ let mut tup = serializer.serialize_tuple($len)?;
+ $(
+ tup.serialize_element(&SerializeAsWrap::<$t, $tas>::new(&tuple.$n))?;
+ )+
+ tup.end()
+ }
+ }
+ };
+}
+
+tuple_impl!(1 0 T0 As0);
+tuple_impl!(2 0 T0 As0 1 T1 As1);
+tuple_impl!(3 0 T0 As0 1 T1 As1 2 T2 As2);
+tuple_impl!(4 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3);
+tuple_impl!(5 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4);
+tuple_impl!(6 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5);
+tuple_impl!(7 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6);
+tuple_impl!(8 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7);
+tuple_impl!(9 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7 8 T8 As8);
+tuple_impl!(10 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7 8 T8 As8 9 T9 As9);
+tuple_impl!(11 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7 8 T8 As8 9 T9 As9 10 T10 As10);
+tuple_impl!(12 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7 8 T8 As8 9 T9 As9 10 T10 As10 11 T11 As11);
+tuple_impl!(13 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7 8 T8 As8 9 T9 As9 10 T10 As10 11 T11 As11 12 T12 As12);
+tuple_impl!(14 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7 8 T8 As8 9 T9 As9 10 T10 As10 11 T11 As11 12 T12 As12 13 T13 As13);
+tuple_impl!(15 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7 8 T8 As8 9 T9 As9 10 T10 As10 11 T11 As11 12 T12 As12 13 T13 As13 14 T14 As14);
+tuple_impl!(16 0 T0 As0 1 T1 As1 2 T2 As2 3 T3 As3 4 T4 As4 5 T5 As5 6 T6 As6 7 T7 As7 8 T8 As8 9 T9 As9 10 T10 As10 11 T11 As11 12 T12 As12 13 T13 As13 14 T14 As14 15 T15 As15);
+
+#[cfg(feature = "alloc")]
+macro_rules! map_as_tuple_seq_intern {
+ ($tyorig:ident < K, V $(, $typaram:ident : $bound:ident)* >, $ty:ident <(K, V)>) => {
+ impl<K, KAs, V, VAs $(, $typaram)*> SerializeAs<$tyorig<K, V $(, $typaram)*>> for $ty<(KAs, VAs)>
+ where
+ KAs: SerializeAs<K>,
+ VAs: SerializeAs<V>,
+ $($typaram: ?Sized + $bound,)*
+ {
+ fn serialize_as<S>(source: &$tyorig<K, V $(, $typaram)*>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serializer.collect_seq(source.iter().map(|(k, v)| {
+ (
+ SerializeAsWrap::<K, KAs>::new(k),
+ SerializeAsWrap::<V, VAs>::new(v),
+ )
+ }))
+ }
+ }
+ };
+}
+#[cfg(feature = "alloc")]
+macro_rules! map_as_tuple_seq {
+ ($tyorig:ident < K, V $(, $typaram:ident : $bound:ident)* >) => {
+ map_as_tuple_seq_intern!($tyorig<K, V $(, $typaram: $bound)* >, Seq<(K, V)>);
+ #[cfg(feature = "alloc")]
+ map_as_tuple_seq_intern!($tyorig<K, V $(, $typaram: $bound)* >, Vec<(K, V)>);
+ }
+}
+foreach_map!(map_as_tuple_seq);
+
+macro_rules! tuple_seq_as_map_impl_intern {
+ ($tyorig:ident < (K, V) $(, $typaram:ident : $bound:ident)* >, $ty:ident <K, V>) => {
+ #[allow(clippy::implicit_hasher)]
+ impl<K, KAs, V, VAs $(, $typaram)*> SerializeAs<$tyorig<(K, V) $(, $typaram)*>> for $ty<KAs, VAs>
+ where
+ KAs: SerializeAs<K>,
+ VAs: SerializeAs<V>,
+ $($typaram: ?Sized + $bound,)*
+ {
+ fn serialize_as<S>(source: &$tyorig<(K, V) $(, $typaram)*>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serializer.collect_map(source.iter().map(|(k, v)| {
+ (
+ SerializeAsWrap::<K, KAs>::new(k),
+ SerializeAsWrap::<V, VAs>::new(v),
+ )
+ }))
+ }
+ }
+ };
+}
+macro_rules! tuple_seq_as_map_impl {
+ ($tyorig:ident < (K, V) $(, $typaram:ident : $bound:ident)* >) => {
+ tuple_seq_as_map_impl_intern!($tyorig<(K, V) $(, $typaram: $bound)* >, Map<K, V>);
+ #[cfg(feature = "alloc")]
+ tuple_seq_as_map_impl_intern!($tyorig<(K, V) $(, $typaram: $bound)* >, BTreeMap<K, V>);
+ #[cfg(feature = "std")]
+ tuple_seq_as_map_impl_intern!($tyorig<(K, V) $(, $typaram: $bound)* >, HashMap<K, V>);
+ }
+}
+foreach_seq!(tuple_seq_as_map_impl, (K, V));
+tuple_seq_as_map_impl!(Option<(K, V)>);
+
+macro_rules! tuple_seq_as_map_arr {
+ ($tyorig:ty, $ty:ident <K, V>) => {
+ #[allow(clippy::implicit_hasher)]
+ impl<K, KAs, V, VAs, const N: usize> SerializeAs<$tyorig> for $ty<KAs, VAs>
+ where
+ KAs: SerializeAs<K>,
+ VAs: SerializeAs<V>,
+ {
+ fn serialize_as<S>(source: &$tyorig, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serializer.collect_map(source.iter().map(|(k, v)| {
+ (
+ SerializeAsWrap::<K, KAs>::new(k),
+ SerializeAsWrap::<V, VAs>::new(v),
+ )
+ }))
+ }
+ }
+ };
+}
+tuple_seq_as_map_arr!([(K, V); N], Map<K, V>);
+#[cfg(feature = "alloc")]
+tuple_seq_as_map_arr!([(K, V); N], BTreeMap<K, V>);
+#[cfg(feature = "std")]
+tuple_seq_as_map_arr!([(K, V); N], HashMap<K, V>);
+
+// endregion
+///////////////////////////////////////////////////////////////////////////////
+// region: Conversion types which cause different serialization behavior
+
+impl<T> SerializeAs<T> for Same
+where
+ T: Serialize + ?Sized,
+{
+ fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ source.serialize(serializer)
+ }
+}
+
+impl<T> SerializeAs<T> for DisplayFromStr
+where
+ T: Display,
+{
+ fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serializer.collect_str(source)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<T, U> SerializeAs<Vec<T>> for VecSkipError<U>
+where
+ U: SerializeAs<T>,
+{
+ fn serialize_as<S>(source: &Vec<T>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ Vec::<U>::serialize_as(source, serializer)
+ }
+}
+
+impl<T> SerializeAs<Option<T>> for NoneAsEmptyString
+where
+ T: Display,
+{
+ fn serialize_as<S>(source: &Option<T>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ if let Some(value) = source {
+ serializer.collect_str(value)
+ } else {
+ serializer.serialize_str("")
+ }
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<T, TAs> SerializeAs<T> for DefaultOnError<TAs>
+where
+ TAs: SerializeAs<T>,
+{
+ fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ TAs::serialize_as(source, serializer)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl SerializeAs<Vec<u8>> for BytesOrString {
+ fn serialize_as<S>(source: &Vec<u8>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ source.serialize(serializer)
+ }
+}
+
+impl<SEPARATOR, I, T> SerializeAs<I> for StringWithSeparator<SEPARATOR, T>
+where
+ SEPARATOR: formats::Separator,
+ for<'x> &'x I: IntoIterator<Item = &'x T>,
+ T: Display,
+ // This set of bounds is enough to make the function compile but has inference issues
+ // making it unusable at the moment.
+ // https://github.com/rust-lang/rust/issues/89196#issuecomment-932024770
+ // for<'x> &'x I: IntoIterator,
+ // for<'x> <&'x I as IntoIterator>::Item: Display,
+{
+ fn serialize_as<S>(source: &I, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ pub(crate) struct DisplayWithSeparator<'a, I, SEPARATOR>(&'a I, PhantomData<SEPARATOR>);
+
+ impl<'a, I, SEPARATOR> DisplayWithSeparator<'a, I, SEPARATOR> {
+ pub(crate) fn new(iter: &'a I) -> Self {
+ Self(iter, PhantomData)
+ }
+ }
+
+ impl<'a, I, SEPARATOR> Display for DisplayWithSeparator<'a, I, SEPARATOR>
+ where
+ SEPARATOR: formats::Separator,
+ &'a I: IntoIterator,
+ <&'a I as IntoIterator>::Item: Display,
+ {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut iter = self.0.into_iter();
+
+ if let Some(first) = iter.next() {
+ first.fmt(f)?;
+ }
+ for elem in iter {
+ f.write_str(SEPARATOR::separator())?;
+ elem.fmt(f)?;
+ }
+
+ Ok(())
+ }
+ }
+
+ serializer.collect_str(&DisplayWithSeparator::<I, SEPARATOR>::new(source))
+ }
+}
+
+macro_rules! use_signed_duration {
+ (
+ $main_trait:ident $internal_trait:ident =>
+ {
+ $ty:ty =>
+ $({
+ $format:ty, $strictness:ty =>
+ $($tbound:ident: $bound:ident $(,)?)*
+ })*
+ }
+ ) => {
+ $(
+ impl<$($tbound,)*> SerializeAs<$ty> for $main_trait<$format, $strictness>
+ where
+ $($tbound: $bound,)*
+ {
+ fn serialize_as<S>(source: &$ty, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ $internal_trait::<$format, $strictness>::serialize_as(
+ &DurationSigned::from(source),
+ serializer,
+ )
+ }
+ }
+ )*
+ };
+ (
+ $( $main_trait:ident $internal_trait:ident, )+ => $rest:tt
+ ) => {
+ $( use_signed_duration!($main_trait $internal_trait => $rest); )+
+ };
+}
+
+use_signed_duration!(
+ DurationSeconds DurationSeconds,
+ DurationMilliSeconds DurationMilliSeconds,
+ DurationMicroSeconds DurationMicroSeconds,
+ DurationNanoSeconds DurationNanoSeconds,
+ => {
+ Duration =>
+ {u64, STRICTNESS => STRICTNESS: Strictness}
+ {f64, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+#[cfg(feature = "alloc")]
+use_signed_duration!(
+ DurationSeconds DurationSeconds,
+ DurationMilliSeconds DurationMilliSeconds,
+ DurationMicroSeconds DurationMicroSeconds,
+ DurationNanoSeconds DurationNanoSeconds,
+ => {
+ Duration =>
+ {String, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+use_signed_duration!(
+ DurationSecondsWithFrac DurationSecondsWithFrac,
+ DurationMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ DurationMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ DurationNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ Duration =>
+ {f64, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+#[cfg(feature = "alloc")]
+use_signed_duration!(
+ DurationSecondsWithFrac DurationSecondsWithFrac,
+ DurationMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ DurationMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ DurationNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ Duration =>
+ {String, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+
+#[cfg(feature = "std")]
+use_signed_duration!(
+ TimestampSeconds DurationSeconds,
+ TimestampMilliSeconds DurationMilliSeconds,
+ TimestampMicroSeconds DurationMicroSeconds,
+ TimestampNanoSeconds DurationNanoSeconds,
+ => {
+ SystemTime =>
+ {i64, STRICTNESS => STRICTNESS: Strictness}
+ {f64, STRICTNESS => STRICTNESS: Strictness}
+ {String, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+#[cfg(feature = "std")]
+use_signed_duration!(
+ TimestampSecondsWithFrac DurationSecondsWithFrac,
+ TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ SystemTime =>
+ {f64, STRICTNESS => STRICTNESS: Strictness}
+ {String, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+
+impl<T, U> SerializeAs<T> for DefaultOnNull<U>
+where
+ U: SerializeAs<T>,
+{
+ fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serializer.serialize_some(&SerializeAsWrap::<T, U>::new(source))
+ }
+}
+
+impl SerializeAs<&[u8]> for Bytes {
+ fn serialize_as<S>(bytes: &&[u8], serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serializer.serialize_bytes(bytes)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl SerializeAs<Vec<u8>> for Bytes {
+ fn serialize_as<S>(bytes: &Vec<u8>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serializer.serialize_bytes(bytes)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl SerializeAs<Box<[u8]>> for Bytes {
+ fn serialize_as<S>(bytes: &Box<[u8]>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serializer.serialize_bytes(bytes)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'a> SerializeAs<Cow<'a, [u8]>> for Bytes {
+ fn serialize_as<S>(bytes: &Cow<'a, [u8]>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serializer.serialize_bytes(bytes)
+ }
+}
+
+impl<const N: usize> SerializeAs<[u8; N]> for Bytes {
+ fn serialize_as<S>(bytes: &[u8; N], serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serializer.serialize_bytes(bytes)
+ }
+}
+
+impl<const N: usize> SerializeAs<&[u8; N]> for Bytes {
+ fn serialize_as<S>(bytes: &&[u8; N], serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serializer.serialize_bytes(*bytes)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<const N: usize> SerializeAs<Box<[u8; N]>> for Bytes {
+ fn serialize_as<S>(bytes: &Box<[u8; N]>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serializer.serialize_bytes(&**bytes)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'a, const N: usize> SerializeAs<Cow<'a, [u8; N]>> for Bytes {
+ fn serialize_as<S>(bytes: &Cow<'a, [u8; N]>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serializer.serialize_bytes(bytes.as_ref())
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<T, U> SerializeAs<Vec<T>> for OneOrMany<U, formats::PreferOne>
+where
+ U: SerializeAs<T>,
+{
+ fn serialize_as<S>(source: &Vec<T>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ match source.len() {
+ 1 => SerializeAsWrap::<T, U>::new(source.iter().next().expect("Cannot be empty"))
+ .serialize(serializer),
+ _ => SerializeAsWrap::<Vec<T>, Vec<U>>::new(source).serialize(serializer),
+ }
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<T, U> SerializeAs<Vec<T>> for OneOrMany<U, formats::PreferMany>
+where
+ U: SerializeAs<T>,
+{
+ fn serialize_as<S>(source: &Vec<T>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ SerializeAsWrap::<Vec<T>, Vec<U>>::new(source).serialize(serializer)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<T, TAs1> SerializeAs<T> for PickFirst<(TAs1,)>
+where
+ TAs1: SerializeAs<T>,
+{
+ fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ SerializeAsWrap::<T, TAs1>::new(source).serialize(serializer)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<T, TAs1, TAs2> SerializeAs<T> for PickFirst<(TAs1, TAs2)>
+where
+ TAs1: SerializeAs<T>,
+{
+ fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ SerializeAsWrap::<T, TAs1>::new(source).serialize(serializer)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<T, TAs1, TAs2, TAs3> SerializeAs<T> for PickFirst<(TAs1, TAs2, TAs3)>
+where
+ TAs1: SerializeAs<T>,
+{
+ fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ SerializeAsWrap::<T, TAs1>::new(source).serialize(serializer)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<T, TAs1, TAs2, TAs3, TAs4> SerializeAs<T> for PickFirst<(TAs1, TAs2, TAs3, TAs4)>
+where
+ TAs1: SerializeAs<T>,
+{
+ fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ SerializeAsWrap::<T, TAs1>::new(source).serialize(serializer)
+ }
+}
+
+impl<T, U> SerializeAs<T> for FromInto<U>
+where
+ T: Into<U> + Clone,
+ U: Serialize,
+{
+ fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ source.clone().into().serialize(serializer)
+ }
+}
+
+impl<T, U> SerializeAs<T> for TryFromInto<U>
+where
+ T: TryInto<U> + Clone,
+ <T as TryInto<U>>::Error: Display,
+ U: Serialize,
+{
+ fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ source
+ .clone()
+ .try_into()
+ .map_err(S::Error::custom)?
+ .serialize(serializer)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'a> SerializeAs<Cow<'a, str>> for BorrowCow {
+ fn serialize_as<S>(source: &Cow<'a, str>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serializer.serialize_str(source)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'a> SerializeAs<Cow<'a, [u8]>> for BorrowCow {
+ fn serialize_as<S>(value: &Cow<'a, [u8]>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serializer.collect_seq(value.iter())
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'a, const N: usize> SerializeAs<Cow<'a, [u8; N]>> for BorrowCow {
+ fn serialize_as<S>(value: &Cow<'a, [u8; N]>, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serializer.collect_seq(value.iter())
+ }
+}
+
+impl<STRICTNESS: Strictness> SerializeAs<bool> for BoolFromInt<STRICTNESS> {
+ fn serialize_as<S>(source: &bool, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ serializer.serialize_u8(*source as u8)
+ }
+}
+
+// endregion
diff --git a/third_party/rust/serde_with/src/ser/mod.rs b/third_party/rust/serde_with/src/ser/mod.rs
new file mode 100644
index 0000000000..657f8ad8eb
--- /dev/null
+++ b/third_party/rust/serde_with/src/ser/mod.rs
@@ -0,0 +1,173 @@
+//! Module for [`SerializeAs`][] implementations
+//!
+//! The module contains the [`SerializeAs`][] trait and helper code.
+//! Additionally, it contains implementations of [`SerializeAs`][] for types defined in the Rust Standard Library or this crate.
+//!
+//! You can find more details on how to implement this trait for your types in the documentation of the [`SerializeAs`][] trait and details about the usage in the [user guide][].
+//!
+//! [user guide]: crate::guide
+
+#[cfg(feature = "alloc")]
+mod duplicates;
+mod impls;
+
+use crate::prelude::*;
+
+/// A **data structure** that can be serialized into any data format supported by Serde, analogue to [`Serialize`].
+///
+/// The trait is analogue to the [`serde::Serialize`][`Serialize`] trait, with the same meaning of input and output arguments.
+/// It can and should be implemented using the same code structure as the [`Serialize`] trait.
+/// As such, the same advice for [implementing `Serialize`][impl-serialize] applies here.
+///
+/// # Differences to [`Serialize`]
+///
+/// The trait is only required for container-like types or types implementing specific conversion functions.
+/// Container-like types are [`Vec`], [`BTreeMap`], but also [`Option`] and [`Box`].
+/// Conversion types serialize into a different serde data type.
+/// For example, [`DisplayFromStr`] uses the [`Display`] trait to serialize a String and [`DurationSeconds`] converts a [`Duration`] into either String or integer values.
+///
+/// This code shows how to implement [`Serialize`] for [`Box`]:
+///
+/// ```rust,ignore
+/// impl<T> Serialize for Box<T>
+/// where
+/// T: Serialize,
+/// {
+/// #[inline]
+/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+/// where
+/// S: Serializer,
+/// {
+/// (**self).serialize(serializer)
+/// }
+/// }
+/// ```
+///
+/// and this code shows how to do the same using [`SerializeAs`][]:
+///
+/// ```rust,ignore
+/// impl<T, U> SerializeAs<Box<T>> for Box<U>
+/// where
+/// U: SerializeAs<T>,
+/// {
+/// fn serialize_as<S>(source: &Box<T>, serializer: S) -> Result<S::Ok, S::Error>
+/// where
+/// S: Serializer,
+/// {
+/// SerializeAsWrap::<T, U>::new(source).serialize(serializer)
+/// }
+/// }
+/// ```
+///
+/// It uses two type parameters, `T` and `U` instead of only one and performs the serialization step using the `SerializeAsWrap` type.
+/// The `T` type is the on the Rust side before serialization, whereas the `U` type determines how the value will be serialized.
+/// These two changes are usually enough to make a container type implement [`SerializeAs`][].
+///
+/// [`SerializeAsWrap`] is a piece of glue code which turns [`SerializeAs`] into a serde compatible datatype, by converting all calls to `serialize` into `serialize_as`.
+/// This allows us to implement [`SerializeAs`] such that it can be applied recursively throughout the whole data structure.
+/// This is mostly important for container types, such as `Vec` or `BTreeMap`.
+/// In a `BTreeMap` this allows us to specify two different serialization behaviors, one for key and one for value, using the [`SerializeAs`] trait.
+///
+/// ## Implementing a converter Type
+///
+/// This shows a simplified implementation for [`DisplayFromStr`].
+///
+/// ```rust
+/// # #[cfg(all(feature = "macros"))] {
+/// # use serde_with::{serde_as, SerializeAs};
+/// # use std::fmt::Display;
+/// struct DisplayFromStr;
+///
+/// impl<T> SerializeAs<T> for DisplayFromStr
+/// where
+/// T: Display,
+/// {
+/// fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
+/// where
+/// S: serde::Serializer,
+/// {
+/// serializer.collect_str(&source)
+/// }
+/// }
+/// #
+/// # #[serde_as]
+/// # #[derive(serde::Serialize)]
+/// # struct S (#[serde_as(as = "DisplayFromStr")] bool);
+/// #
+/// # assert_eq!(r#""false""#, serde_json::to_string(&S(false)).unwrap());
+/// # }
+/// ```
+///
+/// [`Box`]: std::boxed::Box
+/// [`BTreeMap`]: std::collections::BTreeMap
+/// [`Display`]: std::fmt::Display
+/// [`Duration`]: std::time::Duration
+/// [`Vec`]: std::vec::Vec
+/// [impl-serialize]: https://serde.rs/impl-serialize.html
+pub trait SerializeAs<T: ?Sized> {
+ /// Serialize this value into the given Serde serializer.
+ fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer;
+}
+
+/// Helper type to implement [`SerializeAs`] for container-like types.
+pub struct SerializeAsWrap<'a, T: ?Sized, U: ?Sized> {
+ value: &'a T,
+ marker: PhantomData<U>,
+}
+
+impl<'a, T, U> SerializeAsWrap<'a, T, U>
+where
+ T: ?Sized,
+ U: ?Sized,
+{
+ /// Create new instance with provided value.
+ pub fn new(value: &'a T) -> Self {
+ Self {
+ value,
+ marker: PhantomData,
+ }
+ }
+}
+
+impl<'a, T, U> Serialize for SerializeAsWrap<'a, T, U>
+where
+ T: ?Sized,
+ U: ?Sized,
+ U: SerializeAs<T>,
+{
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ U::serialize_as(self.value, serializer)
+ }
+}
+
+impl<'a, T, U> From<&'a T> for SerializeAsWrap<'a, T, U>
+where
+ T: ?Sized,
+ U: ?Sized,
+ U: SerializeAs<T>,
+{
+ fn from(value: &'a T) -> Self {
+ Self::new(value)
+ }
+}
+
+impl<T: ?Sized> As<T> {
+ /// Serialize type `T` using [`SerializeAs`][]
+ ///
+ /// The function signature is compatible with [serde's with-annotation][with-annotation].
+ ///
+ /// [with-annotation]: https://serde.rs/field-attrs.html#with
+ pub fn serialize<S, I>(value: &I, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ T: SerializeAs<I>,
+ I: ?Sized,
+ {
+ T::serialize_as(value, serializer)
+ }
+}
diff --git a/third_party/rust/serde_with/src/serde_conv.rs b/third_party/rust/serde_with/src/serde_conv.rs
new file mode 100644
index 0000000000..ebf4c81ac5
--- /dev/null
+++ b/third_party/rust/serde_with/src/serde_conv.rs
@@ -0,0 +1,150 @@
+/// Create new conversion adapters from functions
+///
+/// The macro lets you create a new converter, which is usable for serde's with-attribute and `#[serde_as]`.
+/// Its main use case is to write simple converters for types, which are not serializable.
+/// Another use-case is to change the serialization behavior if the implemented `Serialize`/`Deserialize` trait is insufficient.
+///
+/// The macro takes four arguments:
+///
+/// 1. The name of the converter type.
+/// The type can be prefixed with a visibility modifies like `pub` or `pub(crate)`.
+/// By default, the type is not marked as public (`pub(self)`).
+/// 2. The type `T` we want to extend with custom behavior.
+/// 3. A function or macro taking a `&T` and returning a serializable type.
+/// 4. A function or macro taking a deserializable type and returning a `Result<T, E>`.
+/// The error type `E` must implement `Display`.
+///
+/// # Example
+///
+/// In this example, we write custom serialization behavior for a `Rgb` type.
+/// We want to serialize it as a `[u8; 3]`.
+///
+/// ```rust
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Serialize, Deserialize};
+/// # use serde_with::serde_as;
+///
+/// #[derive(Clone, Copy, Debug, PartialEq)]
+/// struct Rgb {
+/// red: u8,
+/// green: u8,
+/// blue: u8,
+/// }
+///
+/// serde_with::serde_conv!(
+/// RgbAsArray,
+/// Rgb,
+/// |rgb: &Rgb| [rgb.red, rgb.green, rgb.blue],
+/// |value: [u8; 3]| -> Result<_, std::convert::Infallible> {
+/// Ok(Rgb {
+/// red: value[0],
+/// green: value[1],
+/// blue: value[2],
+/// })
+/// }
+/// );
+///
+/// //////////////////////////////////////////////////
+///
+/// // We define some colors to be used later
+///
+/// let green = Rgb {red: 0, green: 255, blue: 0};
+/// let orange = Rgb {red: 255, green: 128, blue: 0};
+/// let pink = Rgb {red: 255, green: 0, blue: 255};
+///
+/// //////////////////////////////////////////////////
+///
+/// // We can now use the `RgbAsArray` adapter with `serde_as`.
+///
+/// #[serde_as]
+/// #[derive(Debug, PartialEq, Serialize, Deserialize)]
+/// struct Colors {
+/// #[serde_as(as = "RgbAsArray")]
+/// one_rgb: Rgb,
+/// #[serde_as(as = "Vec<RgbAsArray>")]
+/// rgbs_in_vec: Vec<Rgb>,
+/// }
+///
+/// let data = Colors {
+/// one_rgb: orange,
+/// rgbs_in_vec: vec![green, pink],
+/// };
+/// let json = serde_json::json!({
+/// "one_rgb": [255, 128, 0],
+/// "rgbs_in_vec": [
+/// [0, 255, 0],
+/// [255, 0, 255]
+/// ]
+/// });
+///
+/// assert_eq!(json, serde_json::to_value(&data).unwrap());
+/// assert_eq!(data, serde_json::from_value(json).unwrap());
+///
+/// //////////////////////////////////////////////////
+///
+/// // The types generated by `serde_conv` is also compatible with serde's with attribute
+///
+/// #[derive(Debug, PartialEq, Serialize, Deserialize)]
+/// struct ColorsWith {
+/// #[serde(with = "RgbAsArray")]
+/// rgb_with: Rgb,
+/// }
+///
+/// let data = ColorsWith {
+/// rgb_with: pink,
+/// };
+/// let json = serde_json::json!({
+/// "rgb_with": [255, 0, 255]
+/// });
+///
+/// assert_eq!(json, serde_json::to_value(&data).unwrap());
+/// assert_eq!(data, serde_json::from_value(json).unwrap());
+/// # }
+/// ```
+#[macro_export]
+macro_rules! serde_conv {
+ ($m:ident, $t:ty, $ser:expr, $de:expr) => {$crate::serde_conv!(pub(self) $m, $t, $ser, $de);};
+ ($vis:vis $m:ident, $t:ty, $ser:expr, $de:expr) => {
+ #[allow(non_camel_case_types)]
+ $vis struct $m;
+
+ const _:() = {
+ #[allow(clippy::ptr_arg)]
+ impl $m {
+ $vis fn serialize<S>(x: &$t, serializer: S) -> $crate::__private__::Result<S::Ok, S::Error>
+ where
+ S: $crate::serde::Serializer,
+ {
+ let y = $ser(x);
+ $crate::serde::Serialize::serialize(&y, serializer)
+ }
+
+ $vis fn deserialize<'de, D>(deserializer: D) -> $crate::__private__::Result<$t, D::Error>
+ where
+ D: $crate::serde::Deserializer<'de>,
+ {
+ let y = $crate::serde::Deserialize::deserialize(deserializer)?;
+ $de(y).map_err($crate::serde::de::Error::custom)
+ }
+ }
+
+ impl $crate::SerializeAs<$t> for $m {
+ fn serialize_as<S>(x: &$t, serializer: S) -> $crate::__private__::Result<S::Ok, S::Error>
+ where
+ S: $crate::serde::Serializer,
+ {
+ Self::serialize(x, serializer)
+ }
+ }
+
+ impl<'de> $crate::DeserializeAs<'de, $t> for $m {
+ fn deserialize_as<D>(deserializer: D) -> $crate::__private__::Result<$t, D::Error>
+ where
+ D: $crate::serde::Deserializer<'de>,
+ {
+ Self::deserialize(deserializer)
+ }
+ }
+ };
+ };
+}
diff --git a/third_party/rust/serde_with/src/time_0_3.rs b/third_party/rust/serde_with/src/time_0_3.rs
new file mode 100644
index 0000000000..823959fd0b
--- /dev/null
+++ b/third_party/rust/serde_with/src/time_0_3.rs
@@ -0,0 +1,625 @@
+//! De/Serialization of [time v0.3][time] types
+//!
+//! This modules is only available if using the `time_0_3` feature of the crate.
+//!
+//! [time]: https://docs.rs/time/0.3/
+
+use crate::{
+ formats::{Flexible, Format, Strict, Strictness},
+ prelude::*,
+};
+#[cfg(feature = "std")]
+use ::time_0_3::format_description::well_known::{
+ iso8601::EncodedConfig, Iso8601, Rfc2822, Rfc3339,
+};
+use ::time_0_3::{Duration as Time03Duration, OffsetDateTime, PrimitiveDateTime};
+
+/// Create a [`PrimitiveDateTime`] for the Unix Epoch
+fn unix_epoch_primitive() -> PrimitiveDateTime {
+ PrimitiveDateTime::new(
+ ::time_0_3::Date::from_ordinal_date(1970, 1).unwrap(),
+ ::time_0_3::Time::from_hms_nano(0, 0, 0, 0).unwrap(),
+ )
+}
+
+/// Convert a [`time::Duration`][time_0_3::Duration] into a [`DurationSigned`]
+fn duration_into_duration_signed(dur: &Time03Duration) -> DurationSigned {
+ let std_dur = Duration::new(
+ dur.whole_seconds().unsigned_abs(),
+ dur.subsec_nanoseconds().unsigned_abs(),
+ );
+
+ DurationSigned::with_duration(
+ // A duration of 0 is not positive, so check for negative value.
+ if dur.is_negative() {
+ Sign::Negative
+ } else {
+ Sign::Positive
+ },
+ std_dur,
+ )
+}
+
+/// Convert a [`DurationSigned`] into a [`time_0_3::Duration`]
+fn duration_from_duration_signed<'de, D>(sdur: DurationSigned) -> Result<Time03Duration, D::Error>
+where
+ D: Deserializer<'de>,
+{
+ let mut dur: Time03Duration = match sdur.duration.try_into() {
+ Ok(dur) => dur,
+ Err(msg) => {
+ return Err(DeError::custom(format_args!(
+ "Duration is outside of the representable range: {msg}"
+ )))
+ }
+ };
+ if sdur.sign.is_negative() {
+ dur = -dur;
+ }
+ Ok(dur)
+}
+
+macro_rules! use_duration_signed_ser {
+ (
+ $main_trait:ident $internal_trait:ident =>
+ {
+ $ty:ty; $converter:ident =>
+ $({
+ $format:ty, $strictness:ty =>
+ $($tbound:ident: $bound:ident $(,)?)*
+ })*
+ }
+ ) => {
+ $(
+ impl<$($tbound ,)*> SerializeAs<$ty> for $main_trait<$format, $strictness>
+ where
+ $($tbound: $bound,)*
+ {
+ fn serialize_as<S>(source: &$ty, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ let dur: DurationSigned = $converter(source);
+ $internal_trait::<$format, $strictness>::serialize_as(
+ &dur,
+ serializer,
+ )
+ }
+ }
+ )*
+ };
+ (
+ $( $main_trait:ident $internal_trait:ident, )+ => $rest:tt
+ ) => {
+ $( use_duration_signed_ser!($main_trait $internal_trait => $rest); )+
+ };
+}
+
+fn offset_datetime_to_duration(source: &OffsetDateTime) -> DurationSigned {
+ duration_into_duration_signed(&(*source - OffsetDateTime::UNIX_EPOCH))
+}
+
+fn primitive_datetime_to_duration(source: &PrimitiveDateTime) -> DurationSigned {
+ duration_into_duration_signed(&(*source - unix_epoch_primitive()))
+}
+
+use_duration_signed_ser!(
+ DurationSeconds DurationSeconds,
+ DurationMilliSeconds DurationMilliSeconds,
+ DurationMicroSeconds DurationMicroSeconds,
+ DurationNanoSeconds DurationNanoSeconds,
+ => {
+ Time03Duration; duration_into_duration_signed =>
+ {i64, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+#[cfg(feature = "alloc")]
+use_duration_signed_ser!(
+ DurationSeconds DurationSeconds,
+ DurationMilliSeconds DurationMilliSeconds,
+ DurationMicroSeconds DurationMicroSeconds,
+ DurationNanoSeconds DurationNanoSeconds,
+ => {
+ Time03Duration; duration_into_duration_signed =>
+ {String, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+#[cfg(feature = "std")]
+use_duration_signed_ser!(
+ DurationSeconds DurationSeconds,
+ DurationMilliSeconds DurationMilliSeconds,
+ DurationMicroSeconds DurationMicroSeconds,
+ DurationNanoSeconds DurationNanoSeconds,
+ => {
+ Time03Duration; duration_into_duration_signed =>
+ {f64, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+use_duration_signed_ser!(
+ TimestampSeconds DurationSeconds,
+ TimestampMilliSeconds DurationMilliSeconds,
+ TimestampMicroSeconds DurationMicroSeconds,
+ TimestampNanoSeconds DurationNanoSeconds,
+ => {
+ OffsetDateTime; offset_datetime_to_duration =>
+ {i64, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+#[cfg(feature = "alloc")]
+use_duration_signed_ser!(
+ TimestampSeconds DurationSeconds,
+ TimestampMilliSeconds DurationMilliSeconds,
+ TimestampMicroSeconds DurationMicroSeconds,
+ TimestampNanoSeconds DurationNanoSeconds,
+ => {
+ OffsetDateTime; offset_datetime_to_duration =>
+ {String, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+#[cfg(feature = "std")]
+use_duration_signed_ser!(
+ TimestampSeconds DurationSeconds,
+ TimestampMilliSeconds DurationMilliSeconds,
+ TimestampMicroSeconds DurationMicroSeconds,
+ TimestampNanoSeconds DurationNanoSeconds,
+ => {
+ OffsetDateTime; offset_datetime_to_duration =>
+ {f64, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+use_duration_signed_ser!(
+ TimestampSeconds DurationSeconds,
+ TimestampMilliSeconds DurationMilliSeconds,
+ TimestampMicroSeconds DurationMicroSeconds,
+ TimestampNanoSeconds DurationNanoSeconds,
+ => {
+ PrimitiveDateTime; primitive_datetime_to_duration =>
+ {i64, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+#[cfg(feature = "alloc")]
+use_duration_signed_ser!(
+ TimestampSeconds DurationSeconds,
+ TimestampMilliSeconds DurationMilliSeconds,
+ TimestampMicroSeconds DurationMicroSeconds,
+ TimestampNanoSeconds DurationNanoSeconds,
+ => {
+ PrimitiveDateTime; primitive_datetime_to_duration =>
+ {String, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+#[cfg(feature = "std")]
+use_duration_signed_ser!(
+ TimestampSeconds DurationSeconds,
+ TimestampMilliSeconds DurationMilliSeconds,
+ TimestampMicroSeconds DurationMicroSeconds,
+ TimestampNanoSeconds DurationNanoSeconds,
+ => {
+ PrimitiveDateTime; primitive_datetime_to_duration =>
+ {f64, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+
+// Duration/Timestamp WITH FRACTIONS
+#[cfg(feature = "alloc")]
+use_duration_signed_ser!(
+ DurationSecondsWithFrac DurationSecondsWithFrac,
+ DurationMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ DurationMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ DurationNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ Time03Duration; duration_into_duration_signed =>
+ {String, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+#[cfg(feature = "std")]
+use_duration_signed_ser!(
+ DurationSecondsWithFrac DurationSecondsWithFrac,
+ DurationMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ DurationMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ DurationNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ Time03Duration; duration_into_duration_signed =>
+ {f64, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+#[cfg(feature = "alloc")]
+use_duration_signed_ser!(
+ TimestampSecondsWithFrac DurationSecondsWithFrac,
+ TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ OffsetDateTime; offset_datetime_to_duration =>
+ {String, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+#[cfg(feature = "std")]
+use_duration_signed_ser!(
+ TimestampSecondsWithFrac DurationSecondsWithFrac,
+ TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ OffsetDateTime; offset_datetime_to_duration =>
+ {f64, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+#[cfg(feature = "alloc")]
+use_duration_signed_ser!(
+ TimestampSecondsWithFrac DurationSecondsWithFrac,
+ TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ PrimitiveDateTime; primitive_datetime_to_duration =>
+ {String, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+#[cfg(feature = "std")]
+use_duration_signed_ser!(
+ TimestampSecondsWithFrac DurationSecondsWithFrac,
+ TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ PrimitiveDateTime; primitive_datetime_to_duration =>
+ {f64, STRICTNESS => STRICTNESS: Strictness}
+ }
+);
+
+macro_rules! use_duration_signed_de {
+ (
+ $main_trait:ident $internal_trait:ident =>
+ {
+ $ty:ty; $converter:ident =>
+ $({
+ $format:ty, $strictness:ty =>
+ $($tbound:ident: $bound:ident)*
+ })*
+ }
+ ) =>{
+ $(
+ impl<'de, $($tbound,)*> DeserializeAs<'de, $ty> for $main_trait<$format, $strictness>
+ where
+ $($tbound: $bound,)*
+ {
+ fn deserialize_as<D>(deserializer: D) -> Result<$ty, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let dur: DurationSigned = $internal_trait::<$format, $strictness>::deserialize_as(deserializer)?;
+ $converter::<D>(dur)
+ }
+ }
+ )*
+ };
+ (
+ $( $main_trait:ident $internal_trait:ident, )+ => $rest:tt
+ ) => {
+ $( use_duration_signed_de!($main_trait $internal_trait => $rest); )+
+ };
+}
+
+fn duration_to_offset_datetime<'de, D>(dur: DurationSigned) -> Result<OffsetDateTime, D::Error>
+where
+ D: Deserializer<'de>,
+{
+ Ok(OffsetDateTime::UNIX_EPOCH + duration_from_duration_signed::<D>(dur)?)
+}
+
+fn duration_to_primitive_datetime<'de, D>(
+ dur: DurationSigned,
+) -> Result<PrimitiveDateTime, D::Error>
+where
+ D: Deserializer<'de>,
+{
+ Ok(unix_epoch_primitive() + duration_from_duration_signed::<D>(dur)?)
+}
+
+// No subsecond precision
+use_duration_signed_de!(
+ DurationSeconds DurationSeconds,
+ DurationMilliSeconds DurationMilliSeconds,
+ DurationMicroSeconds DurationMicroSeconds,
+ DurationNanoSeconds DurationNanoSeconds,
+ => {
+ Time03Duration; duration_from_duration_signed =>
+ {i64, Strict =>}
+ {FORMAT, Flexible => FORMAT: Format}
+ }
+);
+#[cfg(feature = "alloc")]
+use_duration_signed_de!(
+ DurationSeconds DurationSeconds,
+ DurationMilliSeconds DurationMilliSeconds,
+ DurationMicroSeconds DurationMicroSeconds,
+ DurationNanoSeconds DurationNanoSeconds,
+ => {
+ Time03Duration; duration_from_duration_signed =>
+ {String, Strict =>}
+ }
+);
+#[cfg(feature = "std")]
+use_duration_signed_de!(
+ DurationSeconds DurationSeconds,
+ DurationMilliSeconds DurationMilliSeconds,
+ DurationMicroSeconds DurationMicroSeconds,
+ DurationNanoSeconds DurationNanoSeconds,
+ => {
+ Time03Duration; duration_from_duration_signed =>
+ {f64, Strict =>}
+ }
+);
+use_duration_signed_de!(
+ TimestampSeconds DurationSeconds,
+ TimestampMilliSeconds DurationMilliSeconds,
+ TimestampMicroSeconds DurationMicroSeconds,
+ TimestampNanoSeconds DurationNanoSeconds,
+ => {
+ OffsetDateTime; duration_to_offset_datetime =>
+ {i64, Strict =>}
+ {FORMAT, Flexible => FORMAT: Format}
+ }
+);
+#[cfg(feature = "alloc")]
+use_duration_signed_de!(
+ TimestampSeconds DurationSeconds,
+ TimestampMilliSeconds DurationMilliSeconds,
+ TimestampMicroSeconds DurationMicroSeconds,
+ TimestampNanoSeconds DurationNanoSeconds,
+ => {
+ OffsetDateTime; duration_to_offset_datetime =>
+ {String, Strict =>}
+ }
+);
+#[cfg(feature = "std")]
+use_duration_signed_de!(
+ TimestampSeconds DurationSeconds,
+ TimestampMilliSeconds DurationMilliSeconds,
+ TimestampMicroSeconds DurationMicroSeconds,
+ TimestampNanoSeconds DurationNanoSeconds,
+ => {
+ OffsetDateTime; duration_to_offset_datetime =>
+ {f64, Strict =>}
+ }
+);
+use_duration_signed_de!(
+ TimestampSeconds DurationSeconds,
+ TimestampMilliSeconds DurationMilliSeconds,
+ TimestampMicroSeconds DurationMicroSeconds,
+ TimestampNanoSeconds DurationNanoSeconds,
+ => {
+ PrimitiveDateTime; duration_to_primitive_datetime =>
+ {i64, Strict =>}
+ {FORMAT, Flexible => FORMAT: Format}
+ }
+);
+#[cfg(feature = "alloc")]
+use_duration_signed_de!(
+ TimestampSeconds DurationSeconds,
+ TimestampMilliSeconds DurationMilliSeconds,
+ TimestampMicroSeconds DurationMicroSeconds,
+ TimestampNanoSeconds DurationNanoSeconds,
+ => {
+ PrimitiveDateTime; duration_to_primitive_datetime =>
+ {String, Strict =>}
+ }
+);
+#[cfg(feature = "std")]
+use_duration_signed_de!(
+ TimestampSeconds DurationSeconds,
+ TimestampMilliSeconds DurationMilliSeconds,
+ TimestampMicroSeconds DurationMicroSeconds,
+ TimestampNanoSeconds DurationNanoSeconds,
+ => {
+ PrimitiveDateTime; duration_to_primitive_datetime =>
+ {f64, Strict =>}
+ }
+);
+
+// Duration/Timestamp WITH FRACTIONS
+use_duration_signed_de!(
+ DurationSecondsWithFrac DurationSecondsWithFrac,
+ DurationMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ DurationMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ DurationNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ Time03Duration; duration_from_duration_signed =>
+ {FORMAT, Flexible => FORMAT: Format}
+ }
+);
+#[cfg(feature = "alloc")]
+use_duration_signed_de!(
+ DurationSecondsWithFrac DurationSecondsWithFrac,
+ DurationMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ DurationMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ DurationNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ Time03Duration; duration_from_duration_signed =>
+ {String, Strict =>}
+ }
+);
+#[cfg(feature = "std")]
+use_duration_signed_de!(
+ DurationSecondsWithFrac DurationSecondsWithFrac,
+ DurationMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ DurationMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ DurationNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ Time03Duration; duration_from_duration_signed =>
+ {f64, Strict =>}
+ }
+);
+use_duration_signed_de!(
+ TimestampSecondsWithFrac DurationSecondsWithFrac,
+ TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ OffsetDateTime; duration_to_offset_datetime =>
+ {FORMAT, Flexible => FORMAT: Format}
+ }
+);
+#[cfg(feature = "alloc")]
+use_duration_signed_de!(
+ TimestampSecondsWithFrac DurationSecondsWithFrac,
+ TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ OffsetDateTime; duration_to_offset_datetime =>
+ {String, Strict =>}
+ }
+);
+#[cfg(feature = "std")]
+use_duration_signed_de!(
+ TimestampSecondsWithFrac DurationSecondsWithFrac,
+ TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ OffsetDateTime; duration_to_offset_datetime =>
+ {f64, Strict =>}
+ }
+);
+use_duration_signed_de!(
+ TimestampSecondsWithFrac DurationSecondsWithFrac,
+ TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ PrimitiveDateTime; duration_to_primitive_datetime =>
+ {FORMAT, Flexible => FORMAT: Format}
+ }
+);
+#[cfg(feature = "alloc")]
+use_duration_signed_de!(
+ TimestampSecondsWithFrac DurationSecondsWithFrac,
+ TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ PrimitiveDateTime; duration_to_primitive_datetime =>
+ {String, Strict =>}
+ }
+);
+#[cfg(feature = "std")]
+use_duration_signed_de!(
+ TimestampSecondsWithFrac DurationSecondsWithFrac,
+ TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
+ TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
+ TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
+ => {
+ PrimitiveDateTime; duration_to_primitive_datetime =>
+ {f64, Strict =>}
+ }
+);
+
+#[cfg(feature = "std")]
+impl SerializeAs<OffsetDateTime> for Rfc2822 {
+ fn serialize_as<S>(datetime: &OffsetDateTime, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ datetime
+ .format(&Rfc2822)
+ .map_err(S::Error::custom)?
+ .serialize(serializer)
+ }
+}
+
+#[cfg(feature = "std")]
+impl<'de> DeserializeAs<'de, OffsetDateTime> for Rfc2822 {
+ fn deserialize_as<D>(deserializer: D) -> Result<OffsetDateTime, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct Helper;
+ impl<'de> Visitor<'de> for Helper {
+ type Value = OffsetDateTime;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a RFC2822-formatted `OffsetDateTime`")
+ }
+
+ fn visit_str<E: DeError>(self, value: &str) -> Result<Self::Value, E> {
+ Self::Value::parse(value, &Rfc2822).map_err(E::custom)
+ }
+ }
+
+ deserializer.deserialize_str(Helper)
+ }
+}
+
+#[cfg(feature = "std")]
+impl SerializeAs<OffsetDateTime> for Rfc3339 {
+ fn serialize_as<S>(datetime: &OffsetDateTime, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ datetime
+ .format(&Rfc3339)
+ .map_err(S::Error::custom)?
+ .serialize(serializer)
+ }
+}
+
+#[cfg(feature = "std")]
+impl<'de> DeserializeAs<'de, OffsetDateTime> for Rfc3339 {
+ fn deserialize_as<D>(deserializer: D) -> Result<OffsetDateTime, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct Helper;
+ impl<'de> Visitor<'de> for Helper {
+ type Value = OffsetDateTime;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a RFC3339-formatted `OffsetDateTime`")
+ }
+
+ fn visit_str<E: DeError>(self, value: &str) -> Result<Self::Value, E> {
+ Self::Value::parse(value, &Rfc3339).map_err(E::custom)
+ }
+ }
+
+ deserializer.deserialize_str(Helper)
+ }
+}
+
+#[cfg(feature = "std")]
+impl<const CONFIG: EncodedConfig> SerializeAs<OffsetDateTime> for Iso8601<CONFIG> {
+ fn serialize_as<S>(datetime: &OffsetDateTime, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ datetime
+ .format(&Iso8601::<CONFIG>)
+ .map_err(S::Error::custom)?
+ .serialize(serializer)
+ }
+}
+
+#[cfg(feature = "std")]
+impl<'de, const CONFIG: EncodedConfig> DeserializeAs<'de, OffsetDateTime> for Iso8601<CONFIG> {
+ fn deserialize_as<D>(deserializer: D) -> Result<OffsetDateTime, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct Helper<const CONFIG: EncodedConfig>;
+ impl<'de, const CONFIG: EncodedConfig> Visitor<'de> for Helper<CONFIG> {
+ type Value = OffsetDateTime;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a ISO8601-formatted `OffsetDateTime`")
+ }
+
+ fn visit_str<E: DeError>(self, value: &str) -> Result<Self::Value, E> {
+ Self::Value::parse(value, &Iso8601::<CONFIG>).map_err(E::custom)
+ }
+ }
+
+ deserializer.deserialize_str(Helper::<CONFIG>)
+ }
+}
diff --git a/third_party/rust/serde_with/src/utils.rs b/third_party/rust/serde_with/src/utils.rs
new file mode 100644
index 0000000000..5bd48daf3b
--- /dev/null
+++ b/third_party/rust/serde_with/src/utils.rs
@@ -0,0 +1,194 @@
+pub(crate) mod duration;
+
+use crate::prelude::*;
+
+/// Re-Implementation of `serde::private::de::size_hint::cautious`
+#[cfg(feature = "alloc")]
+#[inline]
+pub(crate) fn size_hint_cautious(hint: Option<usize>) -> usize {
+ core::cmp::min(hint.unwrap_or(0), 4096)
+}
+
+/// Re-Implementation of `serde::private::de::size_hint::from_bounds`
+#[cfg(feature = "alloc")]
+#[inline]
+pub fn size_hint_from_bounds<I>(iter: &I) -> Option<usize>
+where
+ I: Iterator,
+{
+ fn _size_hint_from_bounds(bounds: (usize, Option<usize>)) -> Option<usize> {
+ match bounds {
+ (lower, Some(upper)) if lower == upper => Some(upper),
+ _ => None,
+ }
+ }
+ _size_hint_from_bounds(iter.size_hint())
+}
+
+pub(crate) const NANOS_PER_SEC: u32 = 1_000_000_000;
+// pub(crate) const NANOS_PER_MILLI: u32 = 1_000_000;
+// pub(crate) const NANOS_PER_MICRO: u32 = 1_000;
+// pub(crate) const MILLIS_PER_SEC: u64 = 1_000;
+// pub(crate) const MICROS_PER_SEC: u64 = 1_000_000;
+
+pub(crate) struct MapIter<'de, A, K, V> {
+ pub(crate) access: A,
+ marker: PhantomData<(&'de (), K, V)>,
+}
+
+impl<'de, A, K, V> MapIter<'de, A, K, V> {
+ pub(crate) fn new(access: A) -> Self
+ where
+ A: MapAccess<'de>,
+ {
+ Self {
+ access,
+ marker: PhantomData,
+ }
+ }
+}
+
+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> {
+ self.access.next_entry().transpose()
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ match self.access.size_hint() {
+ Some(size) => (size, Some(size)),
+ None => (0, None),
+ }
+ }
+}
+
+pub(crate) struct SeqIter<'de, A, T> {
+ access: A,
+ marker: PhantomData<(&'de (), T)>,
+}
+
+impl<'de, A, T> SeqIter<'de, A, T> {
+ pub(crate) fn new(access: A) -> Self
+ where
+ A: SeqAccess<'de>,
+ {
+ Self {
+ access,
+ marker: PhantomData,
+ }
+ }
+}
+
+impl<'de, A, T> Iterator for SeqIter<'de, A, T>
+where
+ A: SeqAccess<'de>,
+ T: Deserialize<'de>,
+{
+ type Item = Result<T, A::Error>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.access.next_element().transpose()
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ match self.access.size_hint() {
+ Some(size) => (size, Some(size)),
+ None => (0, None),
+ }
+ }
+}
+
+pub(crate) fn duration_as_secs_f64(dur: &Duration) -> f64 {
+ (dur.as_secs() as f64) + (dur.subsec_nanos() as f64) / (NANOS_PER_SEC as f64)
+}
+
+pub(crate) fn duration_signed_from_secs_f64(secs: f64) -> Result<DurationSigned, &'static str> {
+ const MAX_NANOS_F64: f64 = ((u64::max_value() as u128 + 1) * (NANOS_PER_SEC as u128)) as f64;
+ // TODO why are the seconds converted to nanoseconds first?
+ // Does it make sense to just truncate the value?
+ let mut nanos = secs * (NANOS_PER_SEC as f64);
+ if !nanos.is_finite() {
+ return Err("got non-finite value when converting float to duration");
+ }
+ if nanos >= MAX_NANOS_F64 {
+ return Err("overflow when converting float to duration");
+ }
+ let mut sign = self::duration::Sign::Positive;
+ if nanos < 0.0 {
+ nanos = -nanos;
+ sign = self::duration::Sign::Negative;
+ }
+ let nanos = nanos as u128;
+ Ok(self::duration::DurationSigned::new(
+ sign,
+ (nanos / (NANOS_PER_SEC as u128)) as u64,
+ (nanos % (NANOS_PER_SEC as u128)) as u32,
+ ))
+}
+
+/// Collect an array of a fixed size from an iterator.
+///
+/// # Safety
+/// The code follow exactly the pattern of initializing an array element-by-element from the standard library.
+/// <https://doc.rust-lang.org/nightly/std/mem/union.MaybeUninit.html#initializing-an-array-element-by-element>
+pub(crate) fn array_from_iterator<I, T, E, const N: usize>(
+ mut iter: I,
+ expected: &dyn Expected,
+) -> Result<[T; N], E>
+where
+ I: Iterator<Item = Result<T, E>>,
+ E: DeError,
+{
+ use core::mem::MaybeUninit;
+
+ fn drop_array_elems<T, const N: usize>(num: usize, mut arr: [MaybeUninit<T>; N]) {
+ arr[..num].iter_mut().for_each(|elem| {
+ // TODO This would be better with assume_init_drop nightly function
+ // https://github.com/rust-lang/rust/issues/63567
+ unsafe { core::ptr::drop_in_place(elem.as_mut_ptr()) };
+ });
+ }
+
+ // Create an uninitialized array of `MaybeUninit`. The `assume_init` is
+ // safe because the type we are claiming to have initialized here is a
+ // bunch of `MaybeUninit`s, which do not require initialization.
+ //
+ // TODO could be simplified with nightly maybe_uninit_uninit_array feature
+ // https://doc.rust-lang.org/nightly/std/mem/union.MaybeUninit.html#method.uninit_array
+
+ // Clippy is broken and has a false positive here
+ // https://github.com/rust-lang/rust-clippy/issues/10551
+ #[allow(clippy::uninit_assumed_init)]
+ let mut arr: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() };
+
+ // Dropping a `MaybeUninit` does nothing. Thus using raw pointer
+ // assignment instead of `ptr::write` does not cause the old
+ // uninitialized value to be dropped. Also if there is a panic during
+ // this loop, we have a memory leak, but there is no memory safety
+ // issue.
+ for (idx, elem) in arr[..].iter_mut().enumerate() {
+ *elem = match iter.next() {
+ Some(Ok(value)) => MaybeUninit::new(value),
+ Some(Err(err)) => {
+ drop_array_elems(idx, arr);
+ return Err(err);
+ }
+ None => {
+ drop_array_elems(idx, arr);
+ return Err(DeError::invalid_length(idx, expected));
+ }
+ };
+ }
+
+ // Everything is initialized. Transmute the array to the
+ // initialized type.
+ // A normal transmute is not possible because of:
+ // https://github.com/rust-lang/rust/issues/61956
+ Ok(unsafe { core::mem::transmute_copy::<_, [T; N]>(&arr) })
+}
diff --git a/third_party/rust/serde_with/src/utils/duration.rs b/third_party/rust/serde_with/src/utils/duration.rs
new file mode 100644
index 0000000000..832ea85984
--- /dev/null
+++ b/third_party/rust/serde_with/src/utils/duration.rs
@@ -0,0 +1,565 @@
+//! Internal Helper types
+
+use crate::{
+ formats::{Flexible, Format, Strict, Strictness},
+ prelude::*,
+};
+
+#[derive(Copy, Clone, PartialEq, Eq)]
+#[cfg_attr(test, derive(Debug))]
+pub(crate) enum Sign {
+ Positive,
+ Negative,
+}
+
+impl Sign {
+ #[allow(dead_code)]
+ pub(crate) fn is_positive(&self) -> bool {
+ *self == Sign::Positive
+ }
+
+ #[allow(dead_code)]
+ pub(crate) fn is_negative(&self) -> bool {
+ *self == Sign::Negative
+ }
+
+ pub(crate) fn apply<T>(&self, value: T) -> T
+ where
+ T: core::ops::Neg<Output = T>,
+ {
+ match *self {
+ Sign::Positive => value,
+ Sign::Negative => value.neg(),
+ }
+ }
+}
+
+#[derive(Copy, Clone)]
+pub(crate) struct DurationSigned {
+ pub(crate) sign: Sign,
+ pub(crate) duration: Duration,
+}
+
+impl DurationSigned {
+ pub(crate) fn new(sign: Sign, secs: u64, nanosecs: u32) -> Self {
+ Self {
+ sign,
+ duration: Duration::new(secs, nanosecs),
+ }
+ }
+
+ #[cfg(any(feature = "chrono_0_4", feature = "time_0_3"))]
+ pub(crate) fn with_duration(sign: Sign, duration: Duration) -> Self {
+ Self { sign, duration }
+ }
+
+ #[cfg(feature = "std")]
+ pub(crate) fn to_system_time<'de, D>(self) -> Result<SystemTime, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ match self.sign {
+ Sign::Positive => SystemTime::UNIX_EPOCH.checked_add(self.duration),
+ Sign::Negative => SystemTime::UNIX_EPOCH.checked_sub(self.duration),
+ }
+ .ok_or_else(|| DeError::custom("timestamp is outside the range for std::time::SystemTime"))
+ }
+
+ #[cfg(feature = "std")]
+ pub(crate) fn to_std_duration<'de, D>(self) -> Result<Duration, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ match self.sign {
+ Sign::Positive => Ok(self.duration),
+ Sign::Negative => Err(DeError::custom("std::time::Duration cannot be negative")),
+ }
+ }
+}
+
+impl From<&Duration> for DurationSigned {
+ fn from(&duration: &Duration) -> Self {
+ Self {
+ sign: Sign::Positive,
+ duration,
+ }
+ }
+}
+
+#[cfg(feature = "std")]
+impl From<&SystemTime> for DurationSigned {
+ fn from(time: &SystemTime) -> Self {
+ match time.duration_since(SystemTime::UNIX_EPOCH) {
+ Ok(dur) => DurationSigned {
+ sign: Sign::Positive,
+ duration: dur,
+ },
+ Err(err) => DurationSigned {
+ sign: Sign::Negative,
+ duration: err.duration(),
+ },
+ }
+ }
+}
+
+impl core::ops::Mul<u32> for DurationSigned {
+ type Output = DurationSigned;
+
+ fn mul(mut self, rhs: u32) -> Self::Output {
+ self.duration *= rhs;
+ self
+ }
+}
+
+impl core::ops::Div<u32> for DurationSigned {
+ type Output = DurationSigned;
+
+ fn div(mut self, rhs: u32) -> Self::Output {
+ self.duration /= rhs;
+ self
+ }
+}
+
+impl<STRICTNESS> SerializeAs<DurationSigned> for DurationSeconds<u64, STRICTNESS>
+where
+ STRICTNESS: Strictness,
+{
+ fn serialize_as<S>(source: &DurationSigned, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ if source.sign.is_negative() {
+ return Err(SerError::custom(
+ "cannot serialize a negative Duration as u64",
+ ));
+ }
+
+ let mut secs = source.duration.as_secs();
+
+ // Properly round the value
+ if source.duration.subsec_millis() >= 500 {
+ if source.sign.is_positive() {
+ secs += 1;
+ } else {
+ secs -= 1;
+ }
+ }
+ secs.serialize(serializer)
+ }
+}
+
+impl<STRICTNESS> SerializeAs<DurationSigned> for DurationSeconds<i64, STRICTNESS>
+where
+ STRICTNESS: Strictness,
+{
+ fn serialize_as<S>(source: &DurationSigned, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ let mut secs = source.sign.apply(source.duration.as_secs() as i64);
+
+ // Properly round the value
+ if source.duration.subsec_millis() >= 500 {
+ if source.sign.is_positive() {
+ secs += 1;
+ } else {
+ secs -= 1;
+ }
+ }
+ secs.serialize(serializer)
+ }
+}
+
+impl<STRICTNESS> SerializeAs<DurationSigned> for DurationSeconds<f64, STRICTNESS>
+where
+ STRICTNESS: Strictness,
+{
+ fn serialize_as<S>(source: &DurationSigned, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ let mut secs = source.sign.apply(source.duration.as_secs() as f64);
+
+ // Properly round the value
+ if source.duration.subsec_millis() >= 500 {
+ if source.sign.is_positive() {
+ secs += 1.;
+ } else {
+ secs -= 1.;
+ }
+ }
+ secs.serialize(serializer)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<STRICTNESS> SerializeAs<DurationSigned> for DurationSeconds<String, STRICTNESS>
+where
+ STRICTNESS: Strictness,
+{
+ fn serialize_as<S>(source: &DurationSigned, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ let mut secs = source.sign.apply(source.duration.as_secs() as i64);
+
+ // Properly round the value
+ if source.duration.subsec_millis() >= 500 {
+ if source.sign.is_positive() {
+ secs += 1;
+ } else {
+ secs -= 1;
+ }
+ }
+ secs.to_string().serialize(serializer)
+ }
+}
+
+impl<STRICTNESS> SerializeAs<DurationSigned> for DurationSecondsWithFrac<f64, STRICTNESS>
+where
+ STRICTNESS: Strictness,
+{
+ fn serialize_as<S>(source: &DurationSigned, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ source
+ .sign
+ .apply(utils::duration_as_secs_f64(&source.duration))
+ .serialize(serializer)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<STRICTNESS> SerializeAs<DurationSigned> for DurationSecondsWithFrac<String, STRICTNESS>
+where
+ STRICTNESS: Strictness,
+{
+ fn serialize_as<S>(source: &DurationSigned, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ source
+ .sign
+ .apply(utils::duration_as_secs_f64(&source.duration))
+ .to_string()
+ .serialize(serializer)
+ }
+}
+
+macro_rules! duration_impls {
+ ($($inner:ident { $($factor:literal => $outer:ident,)+ })+) => {
+ $($(
+
+ impl<FORMAT, STRICTNESS> SerializeAs<DurationSigned> for $outer<FORMAT, STRICTNESS>
+ where
+ FORMAT: Format,
+ STRICTNESS: Strictness,
+ $inner<FORMAT, STRICTNESS>: SerializeAs<DurationSigned>
+ {
+ fn serialize_as<S>(source: &DurationSigned, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ $inner::<FORMAT, STRICTNESS>::serialize_as(&(*source * $factor), serializer)
+ }
+ }
+
+ impl<'de, FORMAT, STRICTNESS> DeserializeAs<'de, DurationSigned> for $outer<FORMAT, STRICTNESS>
+ where
+ FORMAT: Format,
+ STRICTNESS: Strictness,
+ $inner<FORMAT, STRICTNESS>: DeserializeAs<'de, DurationSigned>,
+ {
+ fn deserialize_as<D>(deserializer: D) -> Result<DurationSigned, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let dur = $inner::<FORMAT, STRICTNESS>::deserialize_as(deserializer)?;
+ Ok(dur / $factor)
+ }
+ }
+
+ )+)+ };
+}
+duration_impls!(
+ DurationSeconds {
+ 1000u32 => DurationMilliSeconds,
+ 1_000_000u32 => DurationMicroSeconds,
+ 1_000_000_000u32 => DurationNanoSeconds,
+ }
+ DurationSecondsWithFrac {
+ 1000u32 => DurationMilliSecondsWithFrac,
+ 1_000_000u32 => DurationMicroSecondsWithFrac,
+ 1_000_000_000u32 => DurationNanoSecondsWithFrac,
+ }
+);
+
+struct DurationVisitorFlexible;
+impl<'de> Visitor<'de> for DurationVisitorFlexible {
+ type Value = DurationSigned;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("an integer, a float, or a string containing a number")
+ }
+
+ fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ if value >= 0 {
+ Ok(DurationSigned::new(Sign::Positive, value as u64, 0))
+ } else {
+ Ok(DurationSigned::new(Sign::Negative, (-value) as u64, 0))
+ }
+ }
+
+ fn visit_u64<E>(self, secs: u64) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ Ok(DurationSigned::new(Sign::Positive, secs, 0))
+ }
+
+ fn visit_f64<E>(self, secs: f64) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ utils::duration_signed_from_secs_f64(secs).map_err(DeError::custom)
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ match parse_float_into_time_parts(value) {
+ Ok((sign, seconds, subseconds)) => Ok(DurationSigned::new(sign, seconds, subseconds)),
+ Err(ParseFloatError::InvalidValue) => {
+ Err(DeError::invalid_value(Unexpected::Str(value), &self))
+ }
+ Err(ParseFloatError::Custom(msg)) => Err(DeError::custom(msg)),
+ }
+ }
+}
+
+impl<'de> DeserializeAs<'de, DurationSigned> for DurationSeconds<u64, Strict> {
+ fn deserialize_as<D>(deserializer: D) -> Result<DurationSigned, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ u64::deserialize(deserializer).map(|secs: u64| DurationSigned::new(Sign::Positive, secs, 0))
+ }
+}
+
+impl<'de> DeserializeAs<'de, DurationSigned> for DurationSeconds<i64, Strict> {
+ fn deserialize_as<D>(deserializer: D) -> Result<DurationSigned, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ i64::deserialize(deserializer).map(|mut secs: i64| {
+ let mut sign = Sign::Positive;
+ if secs.is_negative() {
+ secs = -secs;
+ sign = Sign::Negative;
+ }
+ DurationSigned::new(sign, secs as u64, 0)
+ })
+ }
+}
+
+// round() only works on std
+#[cfg(feature = "std")]
+impl<'de> DeserializeAs<'de, DurationSigned> for DurationSeconds<f64, Strict> {
+ fn deserialize_as<D>(deserializer: D) -> Result<DurationSigned, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let val = f64::deserialize(deserializer)?.round();
+ utils::duration_signed_from_secs_f64(val).map_err(DeError::custom)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'de> DeserializeAs<'de, DurationSigned> for DurationSeconds<String, Strict> {
+ fn deserialize_as<D>(deserializer: D) -> Result<DurationSigned, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct DurationDeserializationVisitor;
+
+ impl<'de> Visitor<'de> for DurationDeserializationVisitor {
+ type Value = DurationSigned;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(formatter, "a string containing a number")
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
+ where
+ E: DeError,
+ {
+ let mut secs: i64 = value.parse().map_err(DeError::custom)?;
+ let mut sign = Sign::Positive;
+ if secs.is_negative() {
+ secs = -secs;
+ sign = Sign::Negative;
+ }
+ Ok(DurationSigned::new(sign, secs as u64, 0))
+ }
+ }
+
+ deserializer.deserialize_str(DurationDeserializationVisitor)
+ }
+}
+
+impl<'de, FORMAT> DeserializeAs<'de, DurationSigned> for DurationSeconds<FORMAT, Flexible>
+where
+ FORMAT: Format,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<DurationSigned, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ deserializer.deserialize_any(DurationVisitorFlexible)
+ }
+}
+
+impl<'de> DeserializeAs<'de, DurationSigned> for DurationSecondsWithFrac<f64, Strict> {
+ fn deserialize_as<D>(deserializer: D) -> Result<DurationSigned, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let val = f64::deserialize(deserializer)?;
+ utils::duration_signed_from_secs_f64(val).map_err(DeError::custom)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'de> DeserializeAs<'de, DurationSigned> for DurationSecondsWithFrac<String, Strict> {
+ fn deserialize_as<D>(deserializer: D) -> Result<DurationSigned, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let value = String::deserialize(deserializer)?;
+ match parse_float_into_time_parts(&value) {
+ Ok((sign, seconds, subseconds)) => Ok(DurationSigned {
+ sign,
+ duration: Duration::new(seconds, subseconds),
+ }),
+ Err(ParseFloatError::InvalidValue) => Err(DeError::invalid_value(
+ Unexpected::Str(&value),
+ &"a string containing an integer or float",
+ )),
+ Err(ParseFloatError::Custom(msg)) => Err(DeError::custom(msg)),
+ }
+ }
+}
+
+impl<'de, FORMAT> DeserializeAs<'de, DurationSigned> for DurationSecondsWithFrac<FORMAT, Flexible>
+where
+ FORMAT: Format,
+{
+ fn deserialize_as<D>(deserializer: D) -> Result<DurationSigned, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ deserializer.deserialize_any(DurationVisitorFlexible)
+ }
+}
+
+#[cfg_attr(test, derive(Debug, PartialEq))]
+pub(crate) enum ParseFloatError {
+ InvalidValue,
+ #[cfg(not(feature = "alloc"))]
+ Custom(&'static str),
+ #[cfg(feature = "alloc")]
+ Custom(String),
+}
+
+fn parse_float_into_time_parts(mut value: &str) -> Result<(Sign, u64, u32), ParseFloatError> {
+ let sign = match value.chars().next() {
+ // Advance by the size of the parsed char
+ Some('+') => {
+ value = &value[1..];
+ Sign::Positive
+ }
+ Some('-') => {
+ value = &value[1..];
+ Sign::Negative
+ }
+ _ => Sign::Positive,
+ };
+
+ let partslen = value.split('.').count();
+ let mut parts = value.split('.');
+ match partslen {
+ 1 => {
+ let seconds = parts.next().expect("Float contains exactly one part");
+ if let Ok(seconds) = seconds.parse() {
+ Ok((sign, seconds, 0))
+ } else {
+ Err(ParseFloatError::InvalidValue)
+ }
+ }
+ 2 => {
+ let seconds = parts.next().expect("Float contains exactly one part");
+ if let Ok(seconds) = seconds.parse() {
+ let subseconds = parts.next().expect("Float contains exactly one part");
+ let subseclen = subseconds.chars().count() as u32;
+ if subseclen > 9 {
+ #[cfg(feature = "alloc")]
+ return Err(ParseFloatError::Custom(alloc::format!(
+ "Duration and Timestamps with no more than 9 digits precision, but '{value}' has more"
+ )));
+ #[cfg(not(feature = "alloc"))]
+ return Err(ParseFloatError::Custom(
+ "Duration and Timestamps with no more than 9 digits precision",
+ ));
+ }
+
+ if let Ok(mut subseconds) = subseconds.parse() {
+ // convert subseconds to nanoseconds (10^-9), require 9 places for nanoseconds
+ subseconds *= 10u32.pow(9 - subseclen);
+ Ok((sign, seconds, subseconds))
+ } else {
+ Err(ParseFloatError::InvalidValue)
+ }
+ } else {
+ Err(ParseFloatError::InvalidValue)
+ }
+ }
+
+ _ => Err(ParseFloatError::InvalidValue),
+ }
+}
+
+#[test]
+fn test_parse_float_into_time_parts() {
+ // Test normal behavior
+ assert_eq!(
+ Ok((Sign::Positive, 123, 456_000_000)),
+ parse_float_into_time_parts("+123.456")
+ );
+ assert_eq!(
+ Ok((Sign::Negative, 123, 987_000)),
+ parse_float_into_time_parts("-123.000987")
+ );
+ assert_eq!(
+ Ok((Sign::Positive, 18446744073709551615, 123_456_789)),
+ parse_float_into_time_parts("18446744073709551615.123456789")
+ );
+
+ // Test behavior around 0
+ assert_eq!(
+ Ok((Sign::Positive, 0, 456_000_000)),
+ parse_float_into_time_parts("+0.456")
+ );
+ assert_eq!(
+ Ok((Sign::Negative, 0, 987_000)),
+ parse_float_into_time_parts("-0.000987")
+ );
+ assert_eq!(
+ Ok((Sign::Positive, 0, 123_456_789)),
+ parse_float_into_time_parts("0.123456789")
+ );
+}
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..f5a5d41fc3
--- /dev/null
+++ b/third_party/rust/serde_with/src/with_prefix.rs
@@ -0,0 +1,604 @@
+use crate::prelude::*;
+
+/// Serialize with an added prefix on every field name and deserialize by
+/// trimming away the prefix.
+///
+/// You can set the visibility of the generated module by prefixing the module name with a module visibility.
+/// `with_prefix!(pub(crate) prefix_foo "foo_");` creates a module with `pub(crate)` visibility.
+/// The visibility is optional and by default `pub(self)`, i.e., private visibility is assumed.
+///
+/// **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
+/// # #[allow(dead_code)]
+/// struct Match {
+/// player1: Player,
+/// player2: Player,
+/// }
+///
+/// # #[allow(dead_code)]
+/// 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
+/// use serde::{Deserialize, Serialize};
+/// 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_");
+/// // You can also set the visibility of the generated prefix module, the default is private.
+/// with_prefix!(pub 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) => {$crate::with_prefix!(pub(self) $module $prefix);};
+ ($vis:vis $module:ident $prefix:expr) => {
+ $vis mod $module {
+ use $crate::serde::{Deserialize, Deserializer, Serialize, Serializer};
+ use $crate::with_prefix::WithPrefix;
+
+ #[allow(dead_code)]
+ pub fn serialize<T, S>(object: &T, serializer: S) -> $crate::__private__::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) -> $crate::__private__::Result<T, D::Error>
+ where
+ T: Deserialize<'de>,
+ D: Deserializer<'de>,
+ {
+ T::deserialize(WithPrefix {
+ delegate: deserializer,
+ prefix: $prefix,
+ })
+ }
+ }
+ };
+}
+
+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(SerError::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_i8(self, _v: i8) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_i16(self, _v: i16) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_i32(self, _v: i32) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_i64(self, _v: i64) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_u8(self, _v: u8) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_u16(self, _v: u16) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_u32(self, _v: u32) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_u64(self, _v: u64) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_f32(self, _v: f32) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_f64(self, _v: f64) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_char(self, _v: char) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::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(SerError::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(SerError::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
+ Err(SerError::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> {
+ self.serialize_str(variant)
+ }
+
+ fn serialize_newtype_struct<T>(
+ self,
+ _name: &'static str,
+ _value: &T,
+ ) -> Result<Self::Ok, Self::Error>
+ where
+ T: ?Sized + Serialize,
+ {
+ Err(SerError::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(SerError::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
+ Err(SerError::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
+ Err(SerError::custom("wrong type for with_prefix"))
+ }
+
+ fn serialize_tuple_struct(
+ self,
+ _name: &'static str,
+ _len: usize,
+ ) -> Result<Self::SerializeTupleStruct, Self::Error> {
+ Err(SerError::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(SerError::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(SerError::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,
+ {
+ let mut prefixed_key = String::with_capacity(self.prefix.len() + key.len());
+ prefixed_key.push_str(self.prefix);
+ prefixed_key.push_str(key);
+ self.delegate.serialize_entry(&prefixed_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 let Some(without_prefix) = s.strip_prefix(self.prefix) {
+ return seed
+ .deserialize(without_prefix.into_deserializer())
+ .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)
+ }
+}
+
+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: DeError,
+ {
+ 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 let Some(without_prefix) = s.strip_prefix(self.prefix) {
+ return seed
+ .deserialize(without_prefix.into_deserializer())
+ .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/base64.rs b/third_party/rust/serde_with/tests/base64.rs
new file mode 100644
index 0000000000..881ee0d2d2
--- /dev/null
+++ b/third_party/rust/serde_with/tests/base64.rs
@@ -0,0 +1,144 @@
+#![allow(
+ // clippy is broken and shows wrong warnings
+ // clippy on stable does not know yet about the lint name
+ unknown_lints,
+ // https://github.com/rust-lang/rust-clippy/issues/8867
+ clippy::derive_partial_eq_without_eq,
+ // This allows the tests to be written more uniform and not have to special case the last clone().
+ clippy::redundant_clone,
+)]
+
+mod utils;
+
+use crate::utils::{check_deserialization, check_error_deserialization, is_equal};
+use expect_test::expect;
+use serde::{Deserialize, Serialize};
+use serde_with::{
+ base64::{Base64, Bcrypt, BinHex, Crypt, ImapMutf7, Standard, UrlSafe},
+ formats::{Padded, Unpadded},
+ serde_as,
+};
+
+#[test]
+fn base64_vec() {
+ let check_equal = vec![vec![0, 1, 2, 13], vec![14, 5, 6, 7]];
+ let check_deser = vec![vec![0xaa, 0xbc, 0xff], vec![0xe0, 0x7d], vec![0xe0, 0x7d]];
+ let check_deser_from = r#"["qrz/","4H0=","4H0"]"#;
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ pub struct BDefault(#[serde_as(as = "Vec<Base64>")] Vec<Vec<u8>>);
+
+ is_equal(
+ BDefault(check_equal.clone()),
+ expect![[r#"
+ [
+ "AAECDQ==",
+ "DgUGBw=="
+ ]"#]],
+ );
+
+ // Check mixed padding deserialization
+ check_deserialization(BDefault(check_deser.clone()), check_deser_from);
+
+ check_error_deserialization::<BDefault>(
+ r#"["0"]"#,
+ expect!["Encoded text cannot have a 6-bit remainder. at line 1 column 4"],
+ );
+ check_error_deserialization::<BDefault>(
+ r#"["zz"]"#,
+ expect!["Invalid last symbol 122, offset 1. at line 1 column 5"],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ pub struct BPadded(#[serde_as(as = "Vec<Base64<Standard, Padded>>")] Vec<Vec<u8>>);
+
+ is_equal(
+ BPadded(check_equal.clone()),
+ expect![[r#"
+ [
+ "AAECDQ==",
+ "DgUGBw=="
+ ]"#]],
+ );
+ check_deserialization(BPadded(check_deser.clone()), check_deser_from);
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ pub struct BUnpadded(#[serde_as(as = "Vec<Base64<Standard, Unpadded>>")] Vec<Vec<u8>>);
+
+ is_equal(
+ BUnpadded(check_equal.clone()),
+ expect![[r#"
+ [
+ "AAECDQ",
+ "DgUGBw"
+ ]"#]],
+ );
+ check_deserialization(BUnpadded(check_deser.clone()), check_deser_from);
+}
+
+#[test]
+fn base64_different_charsets() {
+ let bytes = [
+ 0x69_u8, 0xb7, 0x1d, 0x79, 0xf8, 0x21, 0x8a, 0x39, 0x25, 0x9a, 0x7a, 0x29, 0xaa, 0xbb,
+ 0x2d, 0xba, 0xfc, 0x31, 0xcb, 0x30, 0x01, 0x08, 0x31, 0x05, 0x18, 0x72, 0x09, 0x28, 0xb3,
+ 0x0d, 0x38, 0xf4, 0x11, 0x49, 0x35, 0x15, 0x59, 0x76, 0x19, 0xd3, 0x5d, 0xb7, 0xe3, 0x9e,
+ 0xbb, 0xf3, 0xdf, 0xbf, 0x00,
+ ];
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ pub struct B64Standard(#[serde_as(as = "Base64<Standard, Padded>")] Vec<u8>);
+
+ is_equal(
+ B64Standard(bytes.to_vec()),
+ expect![[r#""abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/AA==""#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ pub struct B64UrlSafe(#[serde_as(as = "Base64<UrlSafe, Padded>")] Vec<u8>);
+
+ is_equal(
+ B64UrlSafe(bytes.to_vec()),
+ expect![[r#""abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_AA==""#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ pub struct B64Crypt(#[serde_as(as = "Base64<Crypt, Padded>")] Vec<u8>);
+
+ is_equal(
+ B64Crypt(bytes.to_vec()),
+ expect![[r#""OPQRSTUVWXYZabcdefghijklmn./0123456789ABCDEFGHIJKLMNopqrstuvwxyz..==""#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ pub struct B64Bcrypt(#[serde_as(as = "Base64<Bcrypt, Padded>")] Vec<u8>);
+
+ is_equal(
+ B64Bcrypt(bytes.to_vec()),
+ expect![[r#""YZabcdefghijklmnopqrstuvwx./ABCDEFGHIJKLMNOPQRSTUVWXyz0123456789..==""#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ pub struct B64ImapMutf7(#[serde_as(as = "Base64<ImapMutf7, Padded>")] Vec<u8>);
+
+ is_equal(
+ B64ImapMutf7(bytes.to_vec()),
+ expect![[r#""abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+,AA==""#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ pub struct B64BinHex(#[serde_as(as = "Base64<BinHex, Padded>")] Vec<u8>);
+
+ is_equal(
+ B64BinHex(bytes.to_vec()),
+ expect![[r##""CDEFGHIJKLMNPQRSTUVXYZ[`ab!\"#$%&'()*+,-0123456789@ABcdehijklmpqr!!==""##]],
+ );
+}
diff --git a/third_party/rust/serde_with/tests/chrono_0_4.rs b/third_party/rust/serde_with/tests/chrono_0_4.rs
new file mode 100644
index 0000000000..21855f404c
--- /dev/null
+++ b/third_party/rust/serde_with/tests/chrono_0_4.rs
@@ -0,0 +1,742 @@
+#![allow(
+ // clippy is broken and shows wrong warnings
+ // clippy on stable does not know yet about the lint name
+ unknown_lints,
+ // https://github.com/rust-lang/rust-clippy/issues/8867
+ clippy::derive_partial_eq_without_eq,
+)]
+
+extern crate alloc;
+
+mod utils;
+
+use crate::utils::{
+ check_deserialization, check_error_deserialization, check_serialization, is_equal,
+};
+use alloc::collections::BTreeMap;
+use chrono_0_4::{DateTime, Duration, Local, NaiveDateTime, Utc};
+use core::{iter::FromIterator, str::FromStr};
+use expect_test::expect;
+use serde::{Deserialize, Serialize};
+use serde_with::{
+ formats::Flexible, serde_as, DurationMicroSeconds, DurationMicroSecondsWithFrac,
+ DurationMilliSeconds, DurationMilliSecondsWithFrac, DurationNanoSeconds,
+ DurationNanoSecondsWithFrac, DurationSeconds, DurationSecondsWithFrac, TimestampMicroSeconds,
+ TimestampMicroSecondsWithFrac, TimestampMilliSeconds, TimestampMilliSecondsWithFrac,
+ TimestampNanoSeconds, TimestampNanoSecondsWithFrac, TimestampSeconds, TimestampSecondsWithFrac,
+};
+
+fn new_datetime(secs: i64, nsecs: u32) -> DateTime<Utc> {
+ DateTime::from_utc(NaiveDateTime::from_timestamp_opt(secs, nsecs).unwrap(), Utc)
+}
+
+#[test]
+fn json_datetime_from_any_to_string_deserialization() {
+ #[derive(Debug, PartialEq, Deserialize)]
+ struct S(
+ #[serde(with = "serde_with::chrono_0_4::datetime_utc_ts_seconds_from_any")] DateTime<Utc>,
+ );
+
+ // just integers
+ check_deserialization(
+ vec![
+ S(new_datetime(1_478_563_200, 0)),
+ S(new_datetime(0, 0)),
+ S(new_datetime(-86000, 0)),
+ ],
+ r#"[
+ 1478563200,
+ 0,
+ -86000
+ ]"#,
+ );
+
+ // floats, shows precision errors in subsecond part
+ check_deserialization(
+ vec![
+ S(new_datetime(1_478_563_200, 122_999_906)),
+ S(new_datetime(0, 0)),
+ S(new_datetime(-86000, 998_999_999)),
+ ],
+ r#"[
+ 1478563200.123,
+ 0.000,
+ -86000.999
+ ]"#,
+ );
+
+ // string representation of floats
+ check_deserialization(
+ vec![
+ S(new_datetime(1_478_563_200, 123_000_000)),
+ S(new_datetime(0, 0)),
+ S(new_datetime(-86000, 999_000_000)),
+ ],
+ r#"[
+ "1478563200.123",
+ "0.000",
+ "-86000.999"
+ ]"#,
+ );
+}
+
+#[test]
+fn test_chrono_naive_date_time() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ pub struct S(#[serde_as(as = "DateTime<Utc>")] NaiveDateTime);
+
+ is_equal(
+ S(NaiveDateTime::from_str("1994-11-05T08:15:30").unwrap()),
+ expect![[r#""1994-11-05T08:15:30Z""#]],
+ );
+}
+
+#[test]
+fn test_chrono_option_naive_date_time() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ pub struct S(#[serde_as(as = "Option<DateTime<Utc>>")] Option<NaiveDateTime>);
+
+ is_equal(
+ S(NaiveDateTime::from_str("1994-11-05T08:15:30").ok()),
+ expect![[r#""1994-11-05T08:15:30Z""#]],
+ );
+}
+
+#[test]
+fn test_chrono_vec_option_naive_date_time() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ pub struct S(#[serde_as(as = "Vec<Option<DateTime<Utc>>>")] Vec<Option<NaiveDateTime>>);
+
+ is_equal(
+ S(vec![
+ NaiveDateTime::from_str("1994-11-05T08:15:30").ok(),
+ NaiveDateTime::from_str("1994-11-05T08:15:31").ok(),
+ ]),
+ expect![[r#"
+ [
+ "1994-11-05T08:15:30Z",
+ "1994-11-05T08:15:31Z"
+ ]"#]],
+ );
+}
+
+#[test]
+fn test_chrono_btreemap_naive_date_time() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ pub struct S(#[serde_as(as = "BTreeMap<_, DateTime<Utc>>")] BTreeMap<i32, NaiveDateTime>);
+
+ is_equal(
+ S(BTreeMap::from_iter(vec![
+ (1, NaiveDateTime::from_str("1994-11-05T08:15:30").unwrap()),
+ (2, NaiveDateTime::from_str("1994-11-05T08:15:31").unwrap()),
+ ])),
+ expect![[r#"
+ {
+ "1": "1994-11-05T08:15:30Z",
+ "2": "1994-11-05T08:15:31Z"
+ }"#]],
+ );
+}
+
+#[test]
+fn test_chrono_duration_seconds() {
+ let zero = Duration::zero();
+ let one_second = Duration::seconds(1);
+ let half_second = Duration::nanoseconds(500_000_000);
+ let minus_one_second = zero - one_second;
+ let minus_half_second = zero - half_second;
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct StructIntStrict(#[serde_as(as = "DurationSeconds<i64>")] Duration);
+
+ is_equal(StructIntStrict(zero), expect![[r#"0"#]]);
+ is_equal(StructIntStrict(one_second), expect![[r#"1"#]]);
+ is_equal(StructIntStrict(minus_one_second), expect![[r#"-1"#]]);
+ check_serialization(StructIntStrict(half_second), expect![[r#"1"#]]);
+ check_serialization(StructIntStrict(minus_half_second), expect![[r#"-1"#]]);
+ check_error_deserialization::<StructIntStrict>(
+ r#""1""#,
+ expect![[r#"invalid type: string "1", expected i64 at line 1 column 3"#]],
+ );
+ check_error_deserialization::<StructIntStrict>(
+ r#"9223372036854775808"#,
+ expect![[
+ r#"invalid value: integer `9223372036854775808`, expected i64 at line 1 column 19"#
+ ]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct StructIntFlexible(#[serde_as(as = "DurationSeconds<i64, Flexible>")] Duration);
+
+ is_equal(StructIntFlexible(zero), expect![[r#"0"#]]);
+ is_equal(StructIntFlexible(one_second), expect![[r#"1"#]]);
+ check_serialization(StructIntFlexible(half_second), expect![[r#"1"#]]);
+ check_serialization(StructIntFlexible(minus_half_second), expect![[r#"-1"#]]);
+ check_deserialization(StructIntFlexible(half_second), r#""0.5""#);
+ check_deserialization(StructIntFlexible(minus_half_second), r#""-0.5""#);
+ check_deserialization(StructIntFlexible(one_second), r#""1""#);
+ check_deserialization(StructIntFlexible(minus_one_second), r#""-1""#);
+ check_deserialization(StructIntFlexible(zero), r#""0""#);
+ check_error_deserialization::<StructIntFlexible>(
+ r#""a""#,
+ expect![[
+ r#"invalid value: string "a", expected an integer, a float, or a string containing a number at line 1 column 3"#
+ ]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct Structf64Strict(#[serde_as(as = "DurationSeconds<f64>")] Duration);
+
+ is_equal(Structf64Strict(zero), expect![[r#"0.0"#]]);
+ is_equal(Structf64Strict(one_second), expect![[r#"1.0"#]]);
+ is_equal(Structf64Strict(minus_one_second), expect![[r#"-1.0"#]]);
+ check_serialization(Structf64Strict(half_second), expect![[r#"1.0"#]]);
+ check_serialization(Structf64Strict(minus_half_second), expect![[r#"-1.0"#]]);
+ check_deserialization(Structf64Strict(one_second), r#"0.5"#);
+ check_deserialization(Structf64Strict(minus_one_second), r#"-0.5"#);
+ check_error_deserialization::<Structf64Strict>(
+ r#""1""#,
+ expect![[r#"invalid type: string "1", expected f64 at line 1 column 3"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct Structf64Flexible(#[serde_as(as = "DurationSeconds<f64, Flexible>")] Duration);
+
+ is_equal(Structf64Flexible(zero), expect![[r#"0.0"#]]);
+ is_equal(Structf64Flexible(one_second), expect![[r#"1.0"#]]);
+ is_equal(Structf64Flexible(minus_one_second), expect![[r#"-1.0"#]]);
+ check_serialization(Structf64Flexible(half_second), expect![[r#"1.0"#]]);
+ check_serialization(Structf64Flexible(minus_half_second), expect![[r#"-1.0"#]]);
+ check_deserialization(Structf64Flexible(half_second), r#""0.5""#);
+ check_deserialization(Structf64Flexible(minus_half_second), r#""-0.5""#);
+ check_deserialization(Structf64Flexible(one_second), r#""1""#);
+ check_deserialization(Structf64Flexible(minus_one_second), r#""-1""#);
+ check_deserialization(Structf64Flexible(zero), r#""0""#);
+ check_error_deserialization::<Structf64Flexible>(
+ r#""a""#,
+ expect![[
+ r#"invalid value: string "a", expected an integer, a float, or a string containing a number at line 1 column 3"#
+ ]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct StructStringStrict(#[serde_as(as = "DurationSeconds<String>")] Duration);
+
+ is_equal(StructStringStrict(zero), expect![[r#""0""#]]);
+ is_equal(StructStringStrict(one_second), expect![[r#""1""#]]);
+ is_equal(StructStringStrict(minus_one_second), expect![[r#""-1""#]]);
+ check_serialization(StructStringStrict(half_second), expect![[r#""1""#]]);
+ check_serialization(StructStringStrict(minus_half_second), expect![[r#""-1""#]]);
+ check_error_deserialization::<StructStringStrict>(
+ r#"1"#,
+ expect![[
+ r#"invalid type: integer `1`, expected a string containing a number at line 1 column 1"#
+ ]],
+ );
+ check_error_deserialization::<StructStringStrict>(
+ r#"-1"#,
+ expect![[
+ r#"invalid type: integer `-1`, expected a string containing a number at line 1 column 2"#
+ ]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct StructStringFlexible(#[serde_as(as = "DurationSeconds<String, Flexible>")] Duration);
+
+ is_equal(StructStringFlexible(zero), expect![[r#""0""#]]);
+ is_equal(StructStringFlexible(one_second), expect![[r#""1""#]]);
+ is_equal(StructStringFlexible(minus_one_second), expect![[r#""-1""#]]);
+ check_serialization(StructStringFlexible(half_second), expect![[r#""1""#]]);
+ check_deserialization(StructStringFlexible(half_second), r#""0.5""#);
+ check_deserialization(StructStringFlexible(one_second), r#""1""#);
+ check_deserialization(StructStringFlexible(zero), r#""0""#);
+ check_error_deserialization::<StructStringFlexible>(
+ r#""a""#,
+ expect![[
+ r#"invalid value: string "a", expected an integer, a float, or a string containing a number at line 1 column 3"#
+ ]],
+ );
+}
+
+#[test]
+fn test_chrono_duration_seconds_with_frac() {
+ let zero = Duration::zero();
+ let one_second = Duration::seconds(1);
+ let half_second = Duration::nanoseconds(500_000_000);
+ let minus_one_second = zero - one_second;
+ let minus_half_second = zero - half_second;
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct Structf64Strict(#[serde_as(as = "DurationSecondsWithFrac<f64>")] Duration);
+
+ is_equal(Structf64Strict(zero), expect![[r#"0.0"#]]);
+ is_equal(Structf64Strict(one_second), expect![[r#"1.0"#]]);
+ is_equal(Structf64Strict(minus_one_second), expect![[r#"-1.0"#]]);
+ is_equal(Structf64Strict(half_second), expect![[r#"0.5"#]]);
+ is_equal(Structf64Strict(minus_half_second), expect![[r#"-0.5"#]]);
+ check_error_deserialization::<Structf64Strict>(
+ r#""1""#,
+ expect![[r#"invalid type: string "1", expected f64 at line 1 column 3"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct Structf64Flexible(#[serde_as(as = "DurationSecondsWithFrac<f64, Flexible>")] Duration);
+
+ is_equal(Structf64Flexible(zero), expect![[r#"0.0"#]]);
+ is_equal(Structf64Flexible(one_second), expect![[r#"1.0"#]]);
+ is_equal(Structf64Flexible(minus_one_second), expect![[r#"-1.0"#]]);
+ is_equal(Structf64Flexible(minus_half_second), expect![[r#"-0.5"#]]);
+ check_deserialization(Structf64Flexible(one_second), r#""1""#);
+ check_deserialization(Structf64Flexible(minus_one_second), r#""-1""#);
+ check_deserialization(Structf64Flexible(half_second), r#""0.5""#);
+ check_deserialization(Structf64Flexible(zero), r#""0""#);
+ check_error_deserialization::<Structf64Flexible>(
+ r#""a""#,
+ expect![[
+ r#"invalid value: string "a", expected an integer, a float, or a string containing a number at line 1 column 3"#
+ ]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct StructStringStrict(#[serde_as(as = "DurationSecondsWithFrac<String>")] Duration);
+
+ is_equal(StructStringStrict(zero), expect![[r#""0""#]]);
+ is_equal(StructStringStrict(one_second), expect![[r#""1""#]]);
+ is_equal(StructStringStrict(minus_one_second), expect![[r#""-1""#]]);
+ is_equal(StructStringStrict(half_second), expect![[r#""0.5""#]]);
+ is_equal(
+ StructStringStrict(minus_half_second),
+ expect![[r#""-0.5""#]],
+ );
+ is_equal(
+ StructStringStrict(minus_half_second),
+ expect![[r#""-0.5""#]],
+ );
+ check_error_deserialization::<StructStringStrict>(
+ r#"1"#,
+ expect![[r#"invalid type: integer `1`, expected a string at line 1 column 1"#]],
+ );
+ check_error_deserialization::<StructStringStrict>(
+ r#"-1"#,
+ expect![[r#"invalid type: integer `-1`, expected a string at line 1 column 2"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct StructStringFlexible(
+ #[serde_as(as = "DurationSecondsWithFrac<String, Flexible>")] Duration,
+ );
+
+ is_equal(StructStringFlexible(zero), expect![[r#""0""#]]);
+ is_equal(StructStringFlexible(one_second), expect![[r#""1""#]]);
+ is_equal(StructStringFlexible(minus_one_second), expect![[r#""-1""#]]);
+ is_equal(StructStringFlexible(half_second), expect![[r#""0.5""#]]);
+ is_equal(
+ StructStringFlexible(minus_half_second),
+ expect![[r#""-0.5""#]],
+ );
+ check_deserialization(StructStringFlexible(one_second), r#""1""#);
+ check_deserialization(StructStringFlexible(zero), r#""0""#);
+ check_error_deserialization::<StructStringFlexible>(
+ r#""a""#,
+ expect![[
+ r#"invalid value: string "a", expected an integer, a float, or a string containing a number at line 1 column 3"#
+ ]],
+ );
+}
+
+#[test]
+fn test_chrono_timestamp_seconds() {
+ let zero = DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp_opt(0, 0).unwrap(), Utc);
+ let one_second = zero + Duration::seconds(1);
+ let half_second = zero + Duration::nanoseconds(500_000_000);
+ let minus_one_second = zero - Duration::seconds(1);
+ let minus_half_second = zero - Duration::nanoseconds(500_000_000);
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct StructIntStrict(#[serde_as(as = "TimestampSeconds")] DateTime<Utc>);
+
+ is_equal(StructIntStrict(zero), expect![[r#"0"#]]);
+ is_equal(StructIntStrict(one_second), expect![[r#"1"#]]);
+ is_equal(StructIntStrict(minus_one_second), expect![[r#"-1"#]]);
+ check_serialization(StructIntStrict(half_second), expect![[r#"1"#]]);
+ check_serialization(StructIntStrict(minus_half_second), expect![[r#"-1"#]]);
+ check_error_deserialization::<StructIntStrict>(
+ r#""1""#,
+ expect![[r#"invalid type: string "1", expected i64 at line 1 column 3"#]],
+ );
+ check_error_deserialization::<StructIntStrict>(
+ r#"0.123"#,
+ expect![[r#"invalid type: floating point `0.123`, expected i64 at line 1 column 5"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct StructIntFlexible(#[serde_as(as = "TimestampSeconds<i64, Flexible>")] DateTime<Utc>);
+
+ is_equal(StructIntFlexible(zero), expect![[r#"0"#]]);
+ is_equal(StructIntFlexible(one_second), expect![[r#"1"#]]);
+ is_equal(StructIntFlexible(minus_one_second), expect![[r#"-1"#]]);
+ check_serialization(StructIntFlexible(half_second), expect![[r#"1"#]]);
+ check_serialization(StructIntFlexible(minus_half_second), expect![[r#"-1"#]]);
+ check_deserialization(StructIntFlexible(one_second), r#""1""#);
+ check_deserialization(StructIntFlexible(one_second), r#"1.0"#);
+ check_deserialization(StructIntFlexible(minus_half_second), r#""-0.5""#);
+ check_deserialization(StructIntFlexible(half_second), r#"0.5"#);
+ check_error_deserialization::<StructIntFlexible>(
+ r#""a""#,
+ expect![[
+ r#"invalid value: string "a", expected an integer, a float, or a string containing a number at line 1 column 3"#
+ ]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct Structf64Strict(#[serde_as(as = "TimestampSeconds<f64>")] DateTime<Utc>);
+
+ is_equal(Structf64Strict(zero), expect![[r#"0.0"#]]);
+ is_equal(Structf64Strict(one_second), expect![[r#"1.0"#]]);
+ is_equal(Structf64Strict(minus_one_second), expect![[r#"-1.0"#]]);
+ check_serialization(Structf64Strict(half_second), expect![[r#"1.0"#]]);
+ check_serialization(Structf64Strict(minus_half_second), expect![[r#"-1.0"#]]);
+ check_deserialization(Structf64Strict(one_second), r#"0.5"#);
+ check_error_deserialization::<Structf64Strict>(
+ r#""1""#,
+ expect![[r#"invalid type: string "1", expected f64 at line 1 column 3"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct Structf64Flexible(#[serde_as(as = "TimestampSeconds<f64, Flexible>")] DateTime<Utc>);
+
+ is_equal(Structf64Flexible(zero), expect![[r#"0.0"#]]);
+ is_equal(Structf64Flexible(one_second), expect![[r#"1.0"#]]);
+ is_equal(Structf64Flexible(minus_one_second), expect![[r#"-1.0"#]]);
+ check_serialization(Structf64Flexible(half_second), expect![[r#"1.0"#]]);
+ check_serialization(Structf64Flexible(minus_half_second), expect![[r#"-1.0"#]]);
+ check_deserialization(Structf64Flexible(one_second), r#""1""#);
+ check_deserialization(Structf64Flexible(one_second), r#"1.0"#);
+ check_deserialization(Structf64Flexible(minus_half_second), r#""-0.5""#);
+ check_deserialization(Structf64Flexible(half_second), r#"0.5"#);
+ check_error_deserialization::<Structf64Flexible>(
+ r#""a""#,
+ expect![[
+ r#"invalid value: string "a", expected an integer, a float, or a string containing a number at line 1 column 3"#
+ ]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct StructStringStrict(#[serde_as(as = "TimestampSeconds<String>")] DateTime<Utc>);
+
+ is_equal(StructStringStrict(zero), expect![[r#""0""#]]);
+ is_equal(StructStringStrict(one_second), expect![[r#""1""#]]);
+ is_equal(StructStringStrict(minus_one_second), expect![[r#""-1""#]]);
+ check_serialization(StructStringStrict(half_second), expect![[r#""1""#]]);
+ check_serialization(StructStringStrict(minus_half_second), expect![[r#""-1""#]]);
+ check_deserialization(StructStringStrict(one_second), r#""1""#);
+ check_error_deserialization::<StructStringStrict>(
+ r#""0.5""#,
+ expect![[r#"invalid digit found in string at line 1 column 5"#]],
+ );
+ check_error_deserialization::<StructStringStrict>(
+ r#""-0.5""#,
+ expect![[r#"invalid digit found in string at line 1 column 6"#]],
+ );
+ check_error_deserialization::<StructStringStrict>(
+ r#"1"#,
+ expect![[
+ r#"invalid type: integer `1`, expected a string containing a number at line 1 column 1"#
+ ]],
+ );
+ check_error_deserialization::<StructStringStrict>(
+ r#"0.0"#,
+ expect![[
+ r#"invalid type: floating point `0`, expected a string containing a number at line 1 column 3"#
+ ]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct StructStringFlexible(
+ #[serde_as(as = "TimestampSeconds<String, Flexible>")] DateTime<Utc>,
+ );
+
+ is_equal(StructStringFlexible(zero), expect![[r#""0""#]]);
+ is_equal(StructStringFlexible(one_second), expect![[r#""1""#]]);
+ is_equal(StructStringFlexible(minus_one_second), expect![[r#""-1""#]]);
+ check_serialization(StructStringFlexible(half_second), expect![[r#""1""#]]);
+ check_serialization(
+ StructStringFlexible(minus_half_second),
+ expect![[r#""-1""#]],
+ );
+ check_deserialization(StructStringFlexible(one_second), r#"1"#);
+ check_deserialization(StructStringFlexible(one_second), r#"1.0"#);
+ check_deserialization(StructStringFlexible(minus_half_second), r#""-0.5""#);
+ check_deserialization(StructStringFlexible(half_second), r#"0.5"#);
+ check_error_deserialization::<StructStringFlexible>(
+ r#""a""#,
+ expect![[
+ r#"invalid value: string "a", expected an integer, a float, or a string containing a number at line 1 column 3"#
+ ]],
+ );
+}
+
+#[test]
+fn test_chrono_timestamp_seconds_with_frac() {
+ let zero = DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp_opt(0, 0).unwrap(), Utc);
+ let one_second = zero + Duration::seconds(1);
+ let half_second = zero + Duration::nanoseconds(500_000_000);
+ let minus_one_second = zero - Duration::seconds(1);
+ let minus_half_second = zero - Duration::nanoseconds(500_000_000);
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct Structf64Strict(#[serde_as(as = "TimestampSecondsWithFrac<f64>")] DateTime<Utc>);
+
+ is_equal(Structf64Strict(zero), expect![[r#"0.0"#]]);
+ is_equal(Structf64Strict(one_second), expect![[r#"1.0"#]]);
+ is_equal(Structf64Strict(minus_one_second), expect![[r#"-1.0"#]]);
+ is_equal(Structf64Strict(half_second), expect![[r#"0.5"#]]);
+ is_equal(Structf64Strict(minus_half_second), expect![[r#"-0.5"#]]);
+ check_error_deserialization::<Structf64Strict>(
+ r#""1""#,
+ expect![[r#"invalid type: string "1", expected f64 at line 1 column 3"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct Structf64Flexible(
+ #[serde_as(as = "TimestampSecondsWithFrac<f64, Flexible>")] DateTime<Utc>,
+ );
+
+ is_equal(Structf64Flexible(zero), expect![[r#"0.0"#]]);
+ is_equal(Structf64Flexible(one_second), expect![[r#"1.0"#]]);
+ is_equal(Structf64Flexible(minus_one_second), expect![[r#"-1.0"#]]);
+ is_equal(Structf64Flexible(half_second), expect![[r#"0.5"#]]);
+ is_equal(Structf64Flexible(minus_half_second), expect![[r#"-0.5"#]]);
+ check_deserialization(Structf64Flexible(one_second), r#""1""#);
+ check_deserialization(Structf64Flexible(minus_half_second), r#""-0.5""#);
+ check_error_deserialization::<Structf64Flexible>(
+ r#""a""#,
+ expect![[
+ r#"invalid value: string "a", expected an integer, a float, or a string containing a number at line 1 column 3"#
+ ]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct StructStringStrict(#[serde_as(as = "TimestampSecondsWithFrac<String>")] DateTime<Utc>);
+
+ is_equal(StructStringStrict(zero), expect![[r#""0""#]]);
+ is_equal(StructStringStrict(one_second), expect![[r#""1""#]]);
+ is_equal(StructStringStrict(minus_one_second), expect![[r#""-1""#]]);
+ is_equal(StructStringStrict(half_second), expect![[r#""0.5""#]]);
+ is_equal(
+ StructStringStrict(minus_half_second),
+ expect![[r#""-0.5""#]],
+ );
+ check_error_deserialization::<StructStringStrict>(
+ r#"1"#,
+ expect![[r#"invalid type: integer `1`, expected a string at line 1 column 1"#]],
+ );
+ check_error_deserialization::<StructStringStrict>(
+ r#"0.0"#,
+ expect![[r#"invalid type: floating point `0`, expected a string at line 1 column 3"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct StructStringFlexible(
+ #[serde_as(as = "TimestampSecondsWithFrac<String, Flexible>")] DateTime<Utc>,
+ );
+
+ is_equal(StructStringFlexible(zero), expect![[r#""0""#]]);
+ is_equal(StructStringFlexible(one_second), expect![[r#""1""#]]);
+ is_equal(StructStringFlexible(minus_one_second), expect![[r#""-1""#]]);
+ is_equal(StructStringFlexible(half_second), expect![[r#""0.5""#]]);
+ is_equal(
+ StructStringFlexible(minus_half_second),
+ expect![[r#""-0.5""#]],
+ );
+ check_deserialization(StructStringFlexible(one_second), r#"1"#);
+ check_deserialization(StructStringFlexible(one_second), r#"1.0"#);
+ check_deserialization(StructStringFlexible(half_second), r#"0.5"#);
+ check_error_deserialization::<StructStringFlexible>(
+ r#""a""#,
+ expect![[
+ r#"invalid value: string "a", expected an integer, a float, or a string containing a number at line 1 column 3"#
+ ]],
+ );
+}
+
+macro_rules! smoketest {
+ ($($valuety:ty, $adapter:literal, $value:expr, $expect:tt;)*) => {
+ $({
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S(#[serde_as(as = $adapter)] $valuety);
+ #[allow(unused_braces)]
+ is_equal(S($value), $expect);
+ })*
+ };
+}
+
+#[test]
+fn test_duration_smoketest() {
+ let zero = Duration::seconds(0);
+ let one_second = Duration::seconds(1);
+
+ smoketest! {
+ Duration, "DurationSeconds<i64>", one_second, {expect![[r#"1"#]]};
+ Duration, "DurationSeconds<f64>", one_second, {expect![[r#"1.0"#]]};
+ Duration, "DurationMilliSeconds<i64>", one_second, {expect![[r#"1000"#]]};
+ Duration, "DurationMilliSeconds<f64>", one_second, {expect![[r#"1000.0"#]]};
+ Duration, "DurationMicroSeconds<i64>", one_second, {expect![[r#"1000000"#]]};
+ Duration, "DurationMicroSeconds<f64>", one_second, {expect![[r#"1000000.0"#]]};
+ Duration, "DurationNanoSeconds<i64>", one_second, {expect![[r#"1000000000"#]]};
+ Duration, "DurationNanoSeconds<f64>", one_second, {expect![[r#"1000000000.0"#]]};
+ };
+
+ smoketest! {
+ Duration, "DurationSecondsWithFrac", one_second, {expect![[r#"1.0"#]]};
+ Duration, "DurationSecondsWithFrac<String>", one_second, {expect![[r#""1""#]]};
+ Duration, "DurationMilliSecondsWithFrac", one_second, {expect![[r#"1000.0"#]]};
+ Duration, "DurationMilliSecondsWithFrac<String>", one_second, {expect![[r#""1000""#]]};
+ Duration, "DurationMicroSecondsWithFrac", one_second, {expect![[r#"1000000.0"#]]};
+ Duration, "DurationMicroSecondsWithFrac<String>", one_second, {expect![[r#""1000000""#]]};
+ Duration, "DurationNanoSecondsWithFrac", one_second, {expect![[r#"1000000000.0"#]]};
+ Duration, "DurationNanoSecondsWithFrac<String>", one_second, {expect![[r#""1000000000""#]]};
+ };
+
+ smoketest! {
+ Duration, "DurationSecondsWithFrac", zero, {expect![[r#"0.0"#]]};
+ Duration, "DurationSecondsWithFrac", zero + Duration::nanoseconds(500_000_000), {expect![[r#"0.5"#]]};
+ Duration, "DurationSecondsWithFrac", zero + Duration::seconds(1), {expect![[r#"1.0"#]]};
+ Duration, "DurationSecondsWithFrac", zero - Duration::nanoseconds(500_000_000), {expect![[r#"-0.5"#]]};
+ Duration, "DurationSecondsWithFrac", zero - Duration::seconds(1), {expect![[r#"-1.0"#]]};
+ };
+}
+
+#[test]
+fn test_datetime_utc_smoketest() {
+ let zero = DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp_opt(0, 0).unwrap(), Utc);
+ let one_second = zero + Duration::seconds(1);
+
+ smoketest! {
+ DateTime<Utc>, "TimestampSeconds<i64>", one_second, {expect![[r#"1"#]]};
+ DateTime<Utc>, "TimestampSeconds<f64>", one_second, {expect![[r#"1.0"#]]};
+ DateTime<Utc>, "TimestampMilliSeconds<i64>", one_second, {expect![[r#"1000"#]]};
+ DateTime<Utc>, "TimestampMilliSeconds<f64>", one_second, {expect![[r#"1000.0"#]]};
+ DateTime<Utc>, "TimestampMicroSeconds<i64>", one_second, {expect![[r#"1000000"#]]};
+ DateTime<Utc>, "TimestampMicroSeconds<f64>", one_second, {expect![[r#"1000000.0"#]]};
+ DateTime<Utc>, "TimestampNanoSeconds<i64>", one_second, {expect![[r#"1000000000"#]]};
+ DateTime<Utc>, "TimestampNanoSeconds<f64>", one_second, {expect![[r#"1000000000.0"#]]};
+ };
+
+ smoketest! {
+ DateTime<Utc>, "TimestampSecondsWithFrac", one_second, {expect![[r#"1.0"#]]};
+ DateTime<Utc>, "TimestampSecondsWithFrac<String>", one_second, {expect![[r#""1""#]]};
+ DateTime<Utc>, "TimestampMilliSecondsWithFrac", one_second, {expect![[r#"1000.0"#]]};
+ DateTime<Utc>, "TimestampMilliSecondsWithFrac<String>", one_second, {expect![[r#""1000""#]]};
+ DateTime<Utc>, "TimestampMicroSecondsWithFrac", one_second, {expect![[r#"1000000.0"#]]};
+ DateTime<Utc>, "TimestampMicroSecondsWithFrac<String>", one_second, {expect![[r#""1000000""#]]};
+ DateTime<Utc>, "TimestampNanoSecondsWithFrac", one_second, {expect![[r#"1000000000.0"#]]};
+ DateTime<Utc>, "TimestampNanoSecondsWithFrac<String>", one_second, {expect![[r#""1000000000""#]]};
+ };
+
+ smoketest! {
+ DateTime<Utc>, "TimestampSecondsWithFrac", zero, {expect![[r#"0.0"#]]};
+ DateTime<Utc>, "TimestampSecondsWithFrac", zero + Duration::nanoseconds(500_000_000), {expect![[r#"0.5"#]]};
+ DateTime<Utc>, "TimestampSecondsWithFrac", zero + Duration::seconds(1), {expect![[r#"1.0"#]]};
+ DateTime<Utc>, "TimestampSecondsWithFrac", zero - Duration::nanoseconds(500_000_000), {expect![[r#"-0.5"#]]};
+ DateTime<Utc>, "TimestampSecondsWithFrac", zero - Duration::seconds(1), {expect![[r#"-1.0"#]]};
+ };
+}
+
+#[test]
+fn test_datetime_local_smoketest() {
+ let zero = DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp_opt(0, 0).unwrap(), Utc)
+ .with_timezone(&Local);
+ let one_second = zero + Duration::seconds(1);
+
+ smoketest! {
+ DateTime<Local>, "TimestampSeconds<i64>", one_second, {expect![[r#"1"#]]};
+ DateTime<Local>, "TimestampSeconds<f64>", one_second, {expect![[r#"1.0"#]]};
+ DateTime<Local>, "TimestampMilliSeconds<i64>", one_second, {expect![[r#"1000"#]]};
+ DateTime<Local>, "TimestampMilliSeconds<f64>", one_second, {expect![[r#"1000.0"#]]};
+ DateTime<Local>, "TimestampMicroSeconds<i64>", one_second, {expect![[r#"1000000"#]]};
+ DateTime<Local>, "TimestampMicroSeconds<f64>", one_second, {expect![[r#"1000000.0"#]]};
+ DateTime<Local>, "TimestampNanoSeconds<i64>", one_second, {expect![[r#"1000000000"#]]};
+ DateTime<Local>, "TimestampNanoSeconds<f64>", one_second, {expect![[r#"1000000000.0"#]]};
+ };
+
+ smoketest! {
+ DateTime<Local>, "TimestampSecondsWithFrac", one_second, {expect![[r#"1.0"#]]};
+ DateTime<Local>, "TimestampSecondsWithFrac<String>", one_second, {expect![[r#""1""#]]};
+ DateTime<Local>, "TimestampMilliSecondsWithFrac", one_second, {expect![[r#"1000.0"#]]};
+ DateTime<Local>, "TimestampMilliSecondsWithFrac<String>", one_second, {expect![[r#""1000""#]]};
+ DateTime<Local>, "TimestampMicroSecondsWithFrac", one_second, {expect![[r#"1000000.0"#]]};
+ DateTime<Local>, "TimestampMicroSecondsWithFrac<String>", one_second, {expect![[r#""1000000""#]]};
+ DateTime<Local>, "TimestampNanoSecondsWithFrac", one_second, {expect![[r#"1000000000.0"#]]};
+ DateTime<Local>, "TimestampNanoSecondsWithFrac<String>", one_second, {expect![[r#""1000000000""#]]};
+ };
+
+ smoketest! {
+ DateTime<Local>, "TimestampSecondsWithFrac", zero, {expect![[r#"0.0"#]]};
+ DateTime<Local>, "TimestampSecondsWithFrac", zero + Duration::nanoseconds(500_000_000), {expect![[r#"0.5"#]]};
+ DateTime<Local>, "TimestampSecondsWithFrac", zero + Duration::seconds(1), {expect![[r#"1.0"#]]};
+ DateTime<Local>, "TimestampSecondsWithFrac", zero - Duration::nanoseconds(500_000_000), {expect![[r#"-0.5"#]]};
+ DateTime<Local>, "TimestampSecondsWithFrac", zero - Duration::seconds(1), {expect![[r#"-1.0"#]]};
+ };
+}
+
+#[test]
+fn test_naive_datetime_smoketest() {
+ let zero = NaiveDateTime::from_timestamp_opt(0, 0).unwrap();
+ let one_second = zero + Duration::seconds(1);
+
+ smoketest! {
+ NaiveDateTime, "TimestampSeconds<i64>", one_second, {expect![[r#"1"#]]};
+ NaiveDateTime, "TimestampSeconds<f64>", one_second, {expect![[r#"1.0"#]]};
+ NaiveDateTime, "TimestampMilliSeconds<i64>", one_second, {expect![[r#"1000"#]]};
+ NaiveDateTime, "TimestampMilliSeconds<f64>", one_second, {expect![[r#"1000.0"#]]};
+ NaiveDateTime, "TimestampMicroSeconds<i64>", one_second, {expect![[r#"1000000"#]]};
+ NaiveDateTime, "TimestampMicroSeconds<f64>", one_second, {expect![[r#"1000000.0"#]]};
+ NaiveDateTime, "TimestampNanoSeconds<i64>", one_second, {expect![[r#"1000000000"#]]};
+ NaiveDateTime, "TimestampNanoSeconds<f64>", one_second, {expect![[r#"1000000000.0"#]]};
+ };
+
+ smoketest! {
+ NaiveDateTime, "TimestampSecondsWithFrac", one_second, {expect![[r#"1.0"#]]};
+ NaiveDateTime, "TimestampSecondsWithFrac<String>", one_second, {expect![[r#""1""#]]};
+ NaiveDateTime, "TimestampMilliSecondsWithFrac", one_second, {expect![[r#"1000.0"#]]};
+ NaiveDateTime, "TimestampMilliSecondsWithFrac<String>", one_second, {expect![[r#""1000""#]]};
+ NaiveDateTime, "TimestampMicroSecondsWithFrac", one_second, {expect![[r#"1000000.0"#]]};
+ NaiveDateTime, "TimestampMicroSecondsWithFrac<String>", one_second, {expect![[r#""1000000""#]]};
+ NaiveDateTime, "TimestampNanoSecondsWithFrac", one_second, {expect![[r#"1000000000.0"#]]};
+ NaiveDateTime, "TimestampNanoSecondsWithFrac<String>", one_second, {expect![[r#""1000000000""#]]};
+ };
+
+ smoketest! {
+ NaiveDateTime, "TimestampSecondsWithFrac", zero, {expect![[r#"0.0"#]]};
+ NaiveDateTime, "TimestampSecondsWithFrac", zero + Duration::nanoseconds(500_000_000), {expect![[r#"0.5"#]]};
+ NaiveDateTime, "TimestampSecondsWithFrac", zero + Duration::seconds(1), {expect![[r#"1.0"#]]};
+ NaiveDateTime, "TimestampSecondsWithFrac", zero - Duration::nanoseconds(500_000_000), {expect![[r#"-0.5"#]]};
+ NaiveDateTime, "TimestampSecondsWithFrac", zero - Duration::seconds(1), {expect![[r#"-1.0"#]]};
+ };
+}
diff --git a/third_party/rust/serde_with/tests/derives/deserialize_fromstr.rs b/third_party/rust/serde_with/tests/derives/deserialize_fromstr.rs
new file mode 100644
index 0000000000..26d60bf08f
--- /dev/null
+++ b/third_party/rust/serde_with/tests/derives/deserialize_fromstr.rs
@@ -0,0 +1,96 @@
+use super::*;
+use core::{
+ num::ParseIntError,
+ str::{FromStr, ParseBoolError},
+};
+use pretty_assertions::assert_eq;
+use serde_with::DeserializeFromStr;
+
+#[derive(Debug, PartialEq, DeserializeFromStr)]
+struct A {
+ a: u32,
+ b: bool,
+}
+
+impl FromStr for A {
+ type Err = String;
+
+ /// Parse a value like `123<>true`
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ let mut parts = s.split("<>");
+ let number = parts
+ .next()
+ .ok_or_else(|| "Missing first value".to_string())?
+ .parse()
+ .map_err(|err: ParseIntError| err.to_string())?;
+ let bool = parts
+ .next()
+ .ok_or_else(|| "Missing second value".to_string())?
+ .parse()
+ .map_err(|err: ParseBoolError| err.to_string())?;
+ Ok(Self { a: number, b: bool })
+ }
+}
+
+#[test]
+fn test_deserialize_fromstr() {
+ check_deserialization(A { a: 159, b: true }, "\"159<>true\"");
+ check_deserialization(A { a: 999, b: false }, "\"999<>false\"");
+ check_deserialization(A { a: 0, b: true }, "\"0<>true\"");
+}
+
+#[test]
+fn test_deserialize_from_bytes() {
+ use serde::de::{value::Error, Deserialize, Deserializer, Visitor};
+
+ // Unfortunately serde_json is too clever (i.e. handles bytes gracefully)
+ // so instead create a custom deserializer which can only deserialize bytes.
+ // All other deserialize_* fns are forwarded to deserialize_bytes
+ struct ByteDeserializer(&'static [u8]);
+
+ impl<'de> Deserializer<'de> for ByteDeserializer {
+ type Error = Error;
+
+ fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ self.deserialize_bytes(visitor)
+ }
+
+ fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: Visitor<'de>,
+ {
+ visitor.visit_bytes(self.0)
+ }
+
+ serde::forward_to_deserialize_any! {
+ bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
+ byte_buf option unit unit_struct newtype_struct seq tuple
+ tuple_struct map struct enum identifier ignored_any
+ }
+ }
+
+ // callstack: A::deserialize -> deserialize_str -> deserialize_any ->
+ // deserialize_bytes -> visit_bytes -> visit_str -> success!
+ let a = A::deserialize(ByteDeserializer(b"159<>true")).unwrap();
+
+ assert_eq!(A { a: 159, b: true }, a);
+}
+
+#[test]
+fn test_deserialize_fromstr_in_vec() {
+ check_deserialization(
+ vec![
+ A { a: 123, b: false },
+ A { a: 0, b: true },
+ A { a: 999, b: true },
+ ],
+ r#"[
+ "123<>false",
+ "0<>true",
+ "999<>true"
+ ]"#,
+ );
+}
diff --git a/third_party/rust/serde_with/tests/derives/lib.rs b/third_party/rust/serde_with/tests/derives/lib.rs
new file mode 100644
index 0000000000..a43a3c3535
--- /dev/null
+++ b/third_party/rust/serde_with/tests/derives/lib.rs
@@ -0,0 +1,15 @@
+#![allow(
+ // clippy is broken and shows wrong warnings
+ // clippy on stable does not know yet about the lint name
+ unknown_lints,
+ // https://github.com/rust-lang/rust-clippy/issues/8867
+ clippy::derive_partial_eq_without_eq,
+)]
+
+mod deserialize_fromstr;
+mod serialize_display;
+#[path = "../utils.rs"]
+mod utils;
+
+use expect_test::expect;
+use utils::*;
diff --git a/third_party/rust/serde_with/tests/derives/serialize_display.rs b/third_party/rust/serde_with/tests/derives/serialize_display.rs
new file mode 100644
index 0000000000..e660fa7535
--- /dev/null
+++ b/third_party/rust/serde_with/tests/derives/serialize_display.rs
@@ -0,0 +1,39 @@
+use super::*;
+use core::fmt;
+use serde_with::SerializeDisplay;
+
+#[derive(Debug, SerializeDisplay)]
+struct A {
+ a: u32,
+ b: bool,
+}
+
+impl fmt::Display for A {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "->{} <> {}<-", self.a, self.b)
+ }
+}
+
+#[test]
+fn test_serialize_display() {
+ check_serialization(A { a: 123, b: false }, expect![[r#""->123 <> false<-""#]]);
+ check_serialization(A { a: 0, b: true }, expect![[r#""->0 <> true<-""#]]);
+ check_serialization(A { a: 999, b: true }, expect![[r#""->999 <> true<-""#]]);
+}
+
+#[test]
+fn test_serialize_display_in_vec() {
+ check_serialization(
+ vec![
+ A { a: 123, b: false },
+ A { a: 0, b: true },
+ A { a: 999, b: true },
+ ],
+ expect![[r#"
+ [
+ "->123 <> false<-",
+ "->0 <> true<-",
+ "->999 <> true<-"
+ ]"#]],
+ );
+}
diff --git a/third_party/rust/serde_with/tests/hex.rs b/third_party/rust/serde_with/tests/hex.rs
new file mode 100644
index 0000000000..2994ae475e
--- /dev/null
+++ b/third_party/rust/serde_with/tests/hex.rs
@@ -0,0 +1,93 @@
+#![allow(
+ // clippy is broken and shows wrong warnings
+ // clippy on stable does not know yet about the lint name
+ unknown_lints,
+ // https://github.com/rust-lang/rust-clippy/issues/8867
+ clippy::derive_partial_eq_without_eq,
+)]
+
+mod utils;
+
+use crate::utils::{check_deserialization, check_error_deserialization, is_equal};
+use expect_test::expect;
+use serde::{Deserialize, Serialize};
+use serde_with::{
+ formats::{Lowercase, Uppercase},
+ hex::Hex,
+ serde_as,
+};
+
+#[test]
+fn hex_vec() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ pub struct B(#[serde_as(as = "Vec<Hex>")] Vec<Vec<u8>>);
+
+ is_equal(
+ B(vec![vec![0, 1, 2, 13], vec![14, 5, 6, 7]]),
+ expect![[r#"
+ [
+ "0001020d",
+ "0e050607"
+ ]"#]],
+ );
+
+ // Check mixed case deserialization
+ check_deserialization(
+ B(vec![vec![0xaa, 0xbc, 0xff], vec![0xe0, 0x7d]]),
+ r#"["aaBCff","E07d"]"#,
+ );
+
+ check_error_deserialization::<B>(
+ r#"["0"]"#,
+ expect![[r#"Odd number of digits at line 1 column 5"#]],
+ );
+ check_error_deserialization::<B>(
+ r#"["zz"]"#,
+ expect![[r#"Invalid character 'z' at position 0 at line 1 column 6"#]],
+ );
+}
+
+#[test]
+fn hex_vec_lowercase() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ pub struct B(#[serde_as(as = "Vec<Hex<Lowercase>>")] Vec<Vec<u8>>);
+
+ is_equal(
+ B(vec![vec![0, 1, 2, 13], vec![14, 5, 6, 7]]),
+ expect![[r#"
+ [
+ "0001020d",
+ "0e050607"
+ ]"#]],
+ );
+
+ // Check mixed case deserialization
+ check_deserialization(
+ B(vec![vec![0xaa, 0xbc, 0xff], vec![0xe0, 0x7d]]),
+ r#"["aaBCff","E07d"]"#,
+ );
+}
+
+#[test]
+fn hex_vec_uppercase() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ pub struct B(#[serde_as(as = "Vec<Hex<Uppercase>>")] Vec<Vec<u8>>);
+
+ is_equal(
+ B(vec![vec![0, 1, 2, 13], vec![14, 5, 6, 7]]),
+ expect![[r#"
+ [
+ "0001020D",
+ "0E050607"
+ ]"#]],
+ );
+
+ // Check mixed case deserialization
+ check_deserialization(
+ B(vec![vec![0xaa, 0xbc, 0xff], vec![0xe0, 0x7d]]),
+ r#"["aaBCff","E07d"]"#,
+ );
+}
diff --git a/third_party/rust/serde_with/tests/indexmap_1.rs b/third_party/rust/serde_with/tests/indexmap_1.rs
new file mode 100644
index 0000000000..0f53bb3b66
--- /dev/null
+++ b/third_party/rust/serde_with/tests/indexmap_1.rs
@@ -0,0 +1,262 @@
+#![allow(
+ // clippy is broken and shows wrong warnings
+ // clippy on stable does not know yet about the lint name
+ unknown_lints,
+ // https://github.com/rust-lang/rust-clippy/issues/8867
+ clippy::derive_partial_eq_without_eq,
+)]
+
+mod utils;
+
+use crate::utils::{check_deserialization, check_error_deserialization, is_equal};
+use core::iter::FromIterator;
+use expect_test::expect;
+use indexmap_1::{IndexMap, IndexSet};
+use serde::{Deserialize, Serialize};
+use serde_with::{serde_as, DisplayFromStr, Same};
+use std::net::IpAddr;
+
+#[test]
+fn test_indexmap() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S(#[serde_as(as = "IndexMap<DisplayFromStr, DisplayFromStr>")] IndexMap<u8, u32>);
+
+ // Normal
+ is_equal(
+ S([(1, 1), (3, 3), (111, 111)].iter().cloned().collect()),
+ expect![[r#"
+ {
+ "1": "1",
+ "3": "3",
+ "111": "111"
+ }"#]],
+ );
+ is_equal(S(IndexMap::default()), expect![[r#"{}"#]]);
+}
+
+#[test]
+fn test_indexset() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S(#[serde_as(as = "IndexSet<DisplayFromStr>")] IndexSet<u32>);
+
+ // Normal
+ is_equal(
+ S([1, 2, 3, 4, 5].iter().cloned().collect()),
+ expect![[r#"
+ [
+ "1",
+ "2",
+ "3",
+ "4",
+ "5"
+ ]"#]],
+ );
+ is_equal(S(IndexSet::default()), expect![[r#"[]"#]]);
+}
+
+#[test]
+fn test_map_as_tuple_list() {
+ let ip = "1.2.3.4".parse().unwrap();
+ let ip2 = "255.255.255.255".parse().unwrap();
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct SI(#[serde_as(as = "Vec<(DisplayFromStr, DisplayFromStr)>")] IndexMap<u32, IpAddr>);
+
+ let map: IndexMap<_, _> = vec![(1, ip), (10, ip), (200, ip2)].into_iter().collect();
+ is_equal(
+ SI(map.clone()),
+ expect![[r#"
+ [
+ [
+ "1",
+ "1.2.3.4"
+ ],
+ [
+ "10",
+ "1.2.3.4"
+ ],
+ [
+ "200",
+ "255.255.255.255"
+ ]
+ ]"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct SI2(#[serde_as(as = "Vec<(Same, DisplayFromStr)>")] IndexMap<u32, IpAddr>);
+
+ is_equal(
+ SI2(map),
+ expect![[r#"
+ [
+ [
+ 1,
+ "1.2.3.4"
+ ],
+ [
+ 10,
+ "1.2.3.4"
+ ],
+ [
+ 200,
+ "255.255.255.255"
+ ]
+ ]"#]],
+ );
+}
+
+#[test]
+fn duplicate_key_first_wins_indexmap() {
+ #[derive(Debug, PartialEq, Deserialize, Serialize)]
+ struct S(#[serde(with = "::serde_with::rust::maps_first_key_wins")] IndexMap<usize, usize>);
+
+ // Different value and key always works
+ is_equal(
+ S(IndexMap::from_iter(vec![(1, 1), (2, 2), (3, 3)])),
+ expect![[r#"
+ {
+ "1": 1,
+ "2": 2,
+ "3": 3
+ }"#]],
+ );
+
+ // Same value for different keys is ok
+ is_equal(
+ S(IndexMap::from_iter(vec![(1, 1), (2, 1), (3, 1)])),
+ expect![[r#"
+ {
+ "1": 1,
+ "2": 1,
+ "3": 1
+ }"#]],
+ );
+
+ // Duplicate keys, the first one is used
+ check_deserialization(
+ S(IndexMap::from_iter(vec![(1, 1), (2, 2)])),
+ r#"{"1": 1, "2": 2, "1": 3}"#,
+ );
+}
+
+#[test]
+fn prohibit_duplicate_key_indexmap() {
+ #[derive(Debug, Eq, PartialEq, Deserialize, Serialize)]
+ struct S(
+ #[serde(with = "::serde_with::rust::maps_duplicate_key_is_error")] IndexMap<usize, usize>,
+ );
+
+ // Different value and key always works
+ is_equal(
+ S(IndexMap::from_iter(vec![(1, 1), (2, 2), (3, 3)])),
+ expect![[r#"
+ {
+ "1": 1,
+ "2": 2,
+ "3": 3
+ }"#]],
+ );
+
+ // Same value for different keys is ok
+ is_equal(
+ S(IndexMap::from_iter(vec![(1, 1), (2, 1), (3, 1)])),
+ expect![[r#"
+ {
+ "1": 1,
+ "2": 1,
+ "3": 1
+ }"#]],
+ );
+
+ // Duplicate keys are an error
+ check_error_deserialization::<S>(
+ r#"{"1": 1, "2": 2, "1": 3}"#,
+ expect![[r#"invalid entry: found duplicate key at line 1 column 24"#]],
+ );
+}
+
+#[test]
+fn duplicate_value_last_wins_indexset() {
+ #[derive(Debug, PartialEq, Deserialize, Serialize)]
+ struct S(#[serde(with = "::serde_with::rust::sets_last_value_wins")] IndexSet<W>);
+
+ #[derive(Debug, Eq, Deserialize, Serialize)]
+ struct W(i32, bool);
+ impl PartialEq for W {
+ fn eq(&self, other: &Self) -> bool {
+ self.0 == other.0
+ }
+ }
+ impl std::hash::Hash for W {
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: std::hash::Hasher,
+ {
+ self.0.hash(state)
+ }
+ }
+
+ // Different values always work
+ is_equal(
+ S(IndexSet::from_iter(vec![
+ W(1, true),
+ W(2, false),
+ W(3, true),
+ ])),
+ expect![[r#"
+ [
+ [
+ 1,
+ true
+ ],
+ [
+ 2,
+ false
+ ],
+ [
+ 3,
+ true
+ ]
+ ]"#]],
+ );
+
+ let value: S = serde_json::from_str(
+ r#"[
+ [1, false],
+ [1, true],
+ [2, true],
+ [2, false]
+ ]"#,
+ )
+ .unwrap();
+ let entries: Vec<_> = value.0.into_iter().collect();
+ assert_eq!(1, entries[0].0);
+ assert!(entries[0].1);
+ assert_eq!(2, entries[1].0);
+ assert!(!entries[1].1);
+}
+
+#[test]
+fn prohibit_duplicate_value_indexset() {
+ #[derive(Debug, PartialEq, Deserialize, Serialize)]
+ struct S(#[serde(with = "::serde_with::rust::sets_duplicate_value_is_error")] IndexSet<usize>);
+
+ is_equal(
+ S(IndexSet::from_iter(vec![1, 2, 3, 4])),
+ expect![[r#"
+ [
+ 1,
+ 2,
+ 3,
+ 4
+ ]"#]],
+ );
+ check_error_deserialization::<S>(
+ r#"[1, 2, 3, 4, 1]"#,
+ expect![[r#"invalid entry: found duplicate value at line 1 column 15"#]],
+ );
+}
diff --git a/third_party/rust/serde_with/tests/json.rs b/third_party/rust/serde_with/tests/json.rs
new file mode 100644
index 0000000000..1babc44fee
--- /dev/null
+++ b/third_party/rust/serde_with/tests/json.rs
@@ -0,0 +1,62 @@
+#![allow(
+ // clippy is broken and shows wrong warnings
+ // clippy on stable does not know yet about the lint name
+ unknown_lints,
+ // https://github.com/rust-lang/rust-clippy/issues/8867
+ clippy::derive_partial_eq_without_eq,
+)]
+
+mod utils;
+
+use crate::utils::is_equal;
+use expect_test::expect;
+use serde::{Deserialize, Serialize};
+use serde_with::{json::JsonString, serde_as, DisplayFromStr};
+use std::collections::BTreeMap;
+
+#[test]
+fn test_jsonstring() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct Struct {
+ #[serde_as(as = "JsonString")]
+ value: Nested,
+ }
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct Nested {
+ #[serde_as(as = "DisplayFromStr")]
+ value: u32,
+ }
+
+ is_equal(
+ Struct {
+ value: Nested { value: 444 },
+ },
+ expect![[r#"
+ {
+ "value": "{\"value\":\"444\"}"
+ }"#]],
+ );
+}
+
+#[test]
+fn test_jsonstring_nested() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct Struct {
+ #[serde_as(as = "JsonString<Vec<(JsonString, _)>>")]
+ value: BTreeMap<[u8; 2], u32>,
+ }
+
+ is_equal(
+ Struct {
+ value: BTreeMap::from([([1, 2], 3), ([4, 5], 6)]),
+ },
+ expect![[r#"
+ {
+ "value": "[[\"[1,2]\",3],[\"[4,5]\",6]]"
+ }"#]],
+ );
+}
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..9b3efefff2
--- /dev/null
+++ b/third_party/rust/serde_with/tests/rust.rs
@@ -0,0 +1,386 @@
+#![allow(
+ // clippy is broken and shows wrong warnings
+ // clippy on stable does not know yet about the lint name
+ unknown_lints,
+ // https://github.com/rust-lang/rust-clippy/issues/8867
+ clippy::derive_partial_eq_without_eq,
+)]
+
+extern crate alloc;
+
+mod utils;
+
+use crate::utils::{check_deserialization, check_error_deserialization, is_equal};
+use alloc::collections::{BTreeMap, BTreeSet};
+use core::{cmp, iter::FromIterator as _};
+use expect_test::expect;
+use fnv::{FnvHashMap as HashMap, FnvHashSet as HashSet};
+use pretty_assertions::assert_eq;
+use serde::{Deserialize, Serialize};
+
+#[test]
+fn prohibit_duplicate_value_hashset() {
+ #[derive(Debug, PartialEq, Deserialize, Serialize)]
+ struct S(#[serde(with = "::serde_with::rust::sets_duplicate_value_is_error")] HashSet<usize>);
+
+ is_equal(
+ S(HashSet::from_iter(vec![1, 2, 3, 4])),
+ expect![[r#"
+ [
+ 4,
+ 1,
+ 3,
+ 2
+ ]"#]],
+ );
+ check_error_deserialization::<S>(
+ r#"[1, 2, 3, 4, 1]"#,
+ expect![[r#"invalid entry: found duplicate value at line 1 column 15"#]],
+ );
+}
+
+#[test]
+fn prohibit_duplicate_value_btreeset() {
+ #[derive(Debug, PartialEq, Deserialize, Serialize)]
+ struct S(#[serde(with = "::serde_with::rust::sets_duplicate_value_is_error")] BTreeSet<usize>);
+
+ is_equal(
+ S(BTreeSet::from_iter(vec![1, 2, 3, 4])),
+ expect![[r#"
+ [
+ 1,
+ 2,
+ 3,
+ 4
+ ]"#]],
+ );
+ check_error_deserialization::<S>(
+ r#"[1, 2, 3, 4, 1]"#,
+ expect![[r#"invalid entry: found duplicate value at line 1 column 15"#]],
+ );
+}
+
+#[test]
+fn prohibit_duplicate_key_hashmap() {
+ #[derive(Debug, Eq, PartialEq, Deserialize, Serialize)]
+ struct S(
+ #[serde(with = "::serde_with::rust::maps_duplicate_key_is_error")] HashMap<usize, usize>,
+ );
+
+ // Different value and key always works
+ is_equal(
+ S(HashMap::from_iter(vec![(1, 1), (2, 2), (3, 3)])),
+ expect![[r#"
+ {
+ "1": 1,
+ "3": 3,
+ "2": 2
+ }"#]],
+ );
+
+ // Same value for different keys is ok
+ is_equal(
+ S(HashMap::from_iter(vec![(1, 1), (2, 1), (3, 1)])),
+ expect![[r#"
+ {
+ "1": 1,
+ "3": 1,
+ "2": 1
+ }"#]],
+ );
+
+ // Duplicate keys are an error
+ check_error_deserialization::<S>(
+ r#"{"1": 1, "2": 2, "1": 3}"#,
+ expect![[r#"invalid entry: found duplicate key at line 1 column 24"#]],
+ );
+}
+
+#[test]
+fn prohibit_duplicate_key_btreemap() {
+ #[derive(Debug, Eq, PartialEq, Deserialize, Serialize)]
+ struct S(
+ #[serde(with = "::serde_with::rust::maps_duplicate_key_is_error")] BTreeMap<usize, usize>,
+ );
+
+ // Different value and key always works
+ is_equal(
+ S(BTreeMap::from_iter(vec![(1, 1), (2, 2), (3, 3)])),
+ expect![[r#"
+ {
+ "1": 1,
+ "2": 2,
+ "3": 3
+ }"#]],
+ );
+
+ // Same value for different keys is ok
+ is_equal(
+ S(BTreeMap::from_iter(vec![(1, 1), (2, 1), (3, 1)])),
+ expect![[r#"
+ {
+ "1": 1,
+ "2": 1,
+ "3": 1
+ }"#]],
+ );
+
+ // Duplicate keys are an error
+ check_error_deserialization::<S>(
+ r#"{"1": 1, "2": 2, "1": 3}"#,
+ expect![[r#"invalid entry: found duplicate key at line 1 column 24"#]],
+ );
+}
+
+#[test]
+fn duplicate_key_first_wins_hashmap() {
+ #[derive(Debug, PartialEq, Deserialize, Serialize)]
+ struct S(#[serde(with = "::serde_with::rust::maps_first_key_wins")] HashMap<usize, usize>);
+
+ // Different value and key always works
+ is_equal(
+ S(HashMap::from_iter(vec![(1, 1), (2, 2), (3, 3)])),
+ expect![[r#"
+ {
+ "1": 1,
+ "3": 3,
+ "2": 2
+ }"#]],
+ );
+
+ // Same value for different keys is ok
+ is_equal(
+ S(HashMap::from_iter(vec![(1, 1), (2, 1), (3, 1)])),
+ expect![[r#"
+ {
+ "1": 1,
+ "3": 1,
+ "2": 1
+ }"#]],
+ );
+
+ // Duplicate keys, the first one is used
+ check_deserialization(
+ S(HashMap::from_iter(vec![(1, 1), (2, 2)])),
+ r#"{"1": 1, "2": 2, "1": 3}"#,
+ );
+}
+
+#[test]
+fn duplicate_key_first_wins_btreemap() {
+ #[derive(Debug, PartialEq, Deserialize, Serialize)]
+ struct S(#[serde(with = "::serde_with::rust::maps_first_key_wins")] BTreeMap<usize, usize>);
+
+ // Different value and key always works
+ is_equal(
+ S(BTreeMap::from_iter(vec![(1, 1), (2, 2), (3, 3)])),
+ expect![[r#"
+ {
+ "1": 1,
+ "2": 2,
+ "3": 3
+ }"#]],
+ );
+
+ // Same value for different keys is ok
+ is_equal(
+ S(BTreeMap::from_iter(vec![(1, 1), (2, 1), (3, 1)])),
+ expect![[r#"
+ {
+ "1": 1,
+ "2": 1,
+ "3": 1
+ }"#]],
+ );
+
+ // Duplicate keys, the first one is used
+ check_deserialization(
+ S(BTreeMap::from_iter(vec![(1, 1), (2, 2)])),
+ r#"{"1": 1, "2": 2, "1": 3}"#,
+ );
+}
+
+#[test]
+fn duplicate_value_first_wins_hashset() {
+ #[derive(Debug, PartialEq, Deserialize, Serialize)]
+ struct S(HashSet<W>);
+ // struct S(#[serde(with = "::serde_with::rust::sets_first_value_wins")] HashSet<W>);
+
+ #[derive(Debug, Eq, Deserialize, Serialize)]
+ struct W(i32, bool);
+ impl PartialEq for W {
+ fn eq(&self, other: &Self) -> bool {
+ self.0 == other.0
+ }
+ }
+ impl std::hash::Hash for W {
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: std::hash::Hasher,
+ {
+ self.0.hash(state)
+ }
+ }
+
+ // Different values always work
+ is_equal(
+ S(HashSet::from_iter(vec![
+ W(1, true),
+ W(2, false),
+ W(3, true),
+ ])),
+ expect![[r#"
+ [
+ [
+ 1,
+ true
+ ],
+ [
+ 3,
+ true
+ ],
+ [
+ 2,
+ false
+ ]
+ ]"#]],
+ );
+
+ let value: S = serde_json::from_str(
+ r#"[
+ [1, false],
+ [1, true],
+ [2, true],
+ [2, false]
+ ]"#,
+ )
+ .unwrap();
+ let entries: Vec<_> = value.0.into_iter().collect();
+ assert_eq!(1, entries[0].0);
+ assert!(!entries[0].1);
+ assert_eq!(2, entries[1].0);
+ assert!(entries[1].1);
+}
+
+#[test]
+fn duplicate_value_last_wins_hashset() {
+ #[derive(Debug, PartialEq, Deserialize, Serialize)]
+ struct S(#[serde(with = "::serde_with::rust::sets_last_value_wins")] HashSet<W>);
+
+ #[derive(Debug, Eq, Deserialize, Serialize)]
+ struct W(i32, bool);
+ impl PartialEq for W {
+ fn eq(&self, other: &Self) -> bool {
+ self.0 == other.0
+ }
+ }
+ impl std::hash::Hash for W {
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: std::hash::Hasher,
+ {
+ self.0.hash(state)
+ }
+ }
+
+ // Different values always work
+ is_equal(
+ S(HashSet::from_iter(vec![
+ W(1, true),
+ W(2, false),
+ W(3, true),
+ ])),
+ expect![[r#"
+ [
+ [
+ 1,
+ true
+ ],
+ [
+ 3,
+ true
+ ],
+ [
+ 2,
+ false
+ ]
+ ]"#]],
+ );
+
+ let value: S = serde_json::from_str(
+ r#"[
+ [1, false],
+ [1, true],
+ [2, true],
+ [2, false]
+ ]"#,
+ )
+ .unwrap();
+ let entries: Vec<_> = value.0.into_iter().collect();
+ assert_eq!(1, entries[0].0);
+ assert!(entries[0].1);
+ assert_eq!(2, entries[1].0);
+ assert!(!entries[1].1);
+}
+
+#[test]
+fn duplicate_value_last_wins_btreeset() {
+ #[derive(Debug, PartialEq, Deserialize, Serialize)]
+ struct S(#[serde(with = "::serde_with::rust::sets_last_value_wins")] BTreeSet<W>);
+ #[derive(Debug, Eq, Deserialize, Serialize)]
+ struct W(i32, bool);
+ impl PartialEq for W {
+ fn eq(&self, other: &Self) -> bool {
+ self.0 == other.0
+ }
+ }
+ impl Ord for W {
+ fn cmp(&self, other: &Self) -> cmp::Ordering {
+ self.0.cmp(&other.0)
+ }
+ }
+ impl PartialOrd for W {
+ fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
+ Some(self.cmp(other))
+ }
+ }
+
+ // Different values always work
+ is_equal(
+ S(BTreeSet::from_iter(vec![
+ W(1, true),
+ W(2, false),
+ W(3, true),
+ ])),
+ expect![[r#"
+ [
+ [
+ 1,
+ true
+ ],
+ [
+ 2,
+ false
+ ],
+ [
+ 3,
+ true
+ ]
+ ]"#]],
+ );
+
+ let value: S = serde_json::from_str(
+ r#"[
+ [1, false],
+ [1, true],
+ [2, true],
+ [2, false]
+ ]"#,
+ )
+ .unwrap();
+ let entries: Vec<_> = value.0.into_iter().collect();
+ assert_eq!(1, entries[0].0);
+ assert!(entries[0].1);
+ assert_eq!(2, entries[1].0);
+ assert!(!entries[1].1);
+}
diff --git a/third_party/rust/serde_with/tests/serde_as/collections.rs b/third_party/rust/serde_with/tests/serde_as/collections.rs
new file mode 100644
index 0000000000..dad84c4978
--- /dev/null
+++ b/third_party/rust/serde_with/tests/serde_as/collections.rs
@@ -0,0 +1,44 @@
+use super::*;
+use fnv::{FnvHashMap, FnvHashSet};
+
+/// Test that HashSets are also supported with non-default hashers.
+#[test]
+fn test_fnv_hashset() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S(#[serde_as(as = "FnvHashSet<DisplayFromStr>")] FnvHashSet<u32>);
+
+ // Normal
+ is_equal(
+ S([1, 2, 3, 4, 5].iter().cloned().collect()),
+ expect![[r#"
+ [
+ "5",
+ "4",
+ "1",
+ "3",
+ "2"
+ ]"#]],
+ );
+ is_equal(S(FnvHashSet::default()), expect![[r#"[]"#]]);
+}
+
+/// Test that HashSets are also supported with non-default hashers.
+#[test]
+fn test_fnv_hashmap() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S(#[serde_as(as = "FnvHashMap<DisplayFromStr, DisplayFromStr>")] FnvHashMap<u8, u32>);
+
+ // Normal
+ is_equal(
+ S([(1, 1), (3, 3), (111, 111)].iter().cloned().collect()),
+ expect![[r#"
+ {
+ "1": "1",
+ "3": "3",
+ "111": "111"
+ }"#]],
+ );
+ is_equal(S(FnvHashMap::default()), expect![[r#"{}"#]]);
+}
diff --git a/third_party/rust/serde_with/tests/serde_as/default_on.rs b/third_party/rust/serde_with/tests/serde_as/default_on.rs
new file mode 100644
index 0000000000..ea3678b166
--- /dev/null
+++ b/third_party/rust/serde_with/tests/serde_as/default_on.rs
@@ -0,0 +1,130 @@
+use super::*;
+use serde_with::{DefaultOnError, DefaultOnNull};
+
+#[test]
+fn test_default_on_error() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S(#[serde_as(as = "DefaultOnError<DisplayFromStr>")] u32);
+
+ // Normal
+ is_equal(S(123), expect![[r#""123""#]]);
+ is_equal(S(0), expect![[r#""0""#]]);
+ // Error cases
+ check_deserialization(S(0), r#""""#);
+ check_deserialization(S(0), r#""12+3""#);
+ check_deserialization(S(0), r#""abc""#);
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S2(#[serde_as(as = "DefaultOnError<Vec<DisplayFromStr>>")] Vec<u32>);
+
+ // Normal
+ is_equal(
+ S2(vec![1, 2, 3]),
+ expect![[r#"
+ [
+ "1",
+ "2",
+ "3"
+ ]"#]],
+ );
+ is_equal(S2(vec![]), expect![[r#"[]"#]]);
+ // Error cases
+ check_deserialization(S2(vec![]), r#"2"#);
+ check_deserialization(S2(vec![]), r#""not_a_list""#);
+ check_deserialization(S2(vec![]), r#"{}"#);
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct Struct2 {
+ #[serde_as(as = "DefaultOnError<Vec<DisplayFromStr>>")]
+ value: Vec<u32>,
+ }
+ check_deserialization(Struct2 { value: vec![] }, r#"{"value":}"#);
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S3(#[serde_as(as = "Vec<DefaultOnError<DisplayFromStr>>")] Vec<u32>);
+
+ // Normal
+ is_equal(
+ S3(vec![1, 2, 3]),
+ expect![[r#"
+ [
+ "1",
+ "2",
+ "3"
+ ]"#]],
+ );
+ is_equal(S3(vec![]), expect![[r#"[]"#]]);
+ // Error cases
+ check_deserialization(S3(vec![0, 3, 0]), r#"[2,"3",4]"#);
+ check_deserialization(S3(vec![0, 0]), r#"["AA",5]"#);
+}
+
+#[test]
+fn test_default_on_null() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S(#[serde_as(as = "DefaultOnNull<DisplayFromStr>")] u32);
+
+ // Normal
+ is_equal(S(123), expect![[r#""123""#]]);
+ is_equal(S(0), expect![[r#""0""#]]);
+ // Null case
+ check_deserialization(S(0), r#"null"#);
+ // Error cases
+ check_error_deserialization::<S>(
+ r#""12+3""#,
+ expect![[r#"invalid digit found in string at line 1 column 6"#]],
+ );
+ check_error_deserialization::<S>(
+ r#""abc""#,
+ expect![[r#"invalid digit found in string at line 1 column 5"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S2(#[serde_as(as = "Vec<DefaultOnNull>")] Vec<u32>);
+
+ // Normal
+ is_equal(
+ S2(vec![1, 2, 0, 3]),
+ expect![[r#"
+ [
+ 1,
+ 2,
+ 0,
+ 3
+ ]"#]],
+ );
+ is_equal(S2(vec![]), expect![[r#"[]"#]]);
+ // Null cases
+ check_deserialization(S2(vec![1, 0, 2]), r#"[1, null, 2]"#);
+ check_error_deserialization::<S2>(
+ r#"["not_a_number"]"#,
+ expect![[r#"invalid type: string "not_a_number", expected u32 at line 1 column 15"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S3(#[serde_as(as = "Vec<DefaultOnNull<DisplayFromStr>>")] Vec<u32>);
+
+ // Normal
+ is_equal(
+ S3(vec![1, 2, 3]),
+ expect![[r#"
+ [
+ "1",
+ "2",
+ "3"
+ ]"#]],
+ );
+ // Null case
+ check_deserialization(S3(vec![0, 3, 0]), r#"[null,"3",null]"#);
+ check_error_deserialization::<S3>(
+ r#"[null,3,null]"#,
+ expect![[r#"invalid type: integer `3`, expected a string at line 1 column 7"#]],
+ );
+}
diff --git a/third_party/rust/serde_with/tests/serde_as/enum_map.rs b/third_party/rust/serde_with/tests/serde_as/enum_map.rs
new file mode 100644
index 0000000000..4d620c9d27
--- /dev/null
+++ b/third_party/rust/serde_with/tests/serde_as/enum_map.rs
@@ -0,0 +1,458 @@
+use super::*;
+use core::{fmt::Write as _, str::FromStr};
+use serde_test::Configure;
+use serde_with::EnumMap;
+use std::net::IpAddr;
+
+fn bytes_debug_readable(bytes: &[u8]) -> String {
+ let mut result = String::with_capacity(bytes.len() * 2);
+ for &byte in bytes {
+ match byte {
+ non_printable if !(0x20..0x7f).contains(&non_printable) => {
+ write!(result, "\\x{byte:02x}").unwrap();
+ }
+ b'\\' => result.push_str("\\\\"),
+ _ => {
+ result.push(byte as char);
+ }
+ }
+ }
+ result
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+enum EnumValue {
+ Int(i32),
+ String(String),
+ Unit,
+ Tuple(i32, String, bool),
+ Struct {
+ a: i32,
+ b: String,
+ c: bool,
+ },
+ Ip(IpAddr, IpAddr),
+ #[serde(rename = "$value")]
+ Extra(serde_json::Value),
+}
+
+#[serde_as]
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+struct VecEnumValues {
+ #[serde_as(as = "EnumMap")]
+ vec: Vec<EnumValue>,
+}
+
+#[test]
+fn json_round_trip() {
+ let values = VecEnumValues {
+ vec: vec![
+ EnumValue::Int(123),
+ EnumValue::String("FooBar".to_string()),
+ EnumValue::Int(456),
+ EnumValue::String("XXX".to_string()),
+ EnumValue::Unit,
+ EnumValue::Tuple(1, "Middle".to_string(), false),
+ EnumValue::Struct {
+ a: 666,
+ b: "BBB".to_string(),
+ c: true,
+ },
+ ],
+ };
+
+ let json = serde_json::to_string_pretty(&values).unwrap();
+ expect_test::expect![[r#"
+ {
+ "vec": {
+ "Int": 123,
+ "String": "FooBar",
+ "Int": 456,
+ "String": "XXX",
+ "Unit": null,
+ "Tuple": [
+ 1,
+ "Middle",
+ false
+ ],
+ "Struct": {
+ "a": 666,
+ "b": "BBB",
+ "c": true
+ }
+ }
+ }"#]]
+ .assert_eq(&json);
+ let deser_values: VecEnumValues = serde_json::from_str(&json).unwrap();
+ assert_eq!(values, deser_values);
+}
+
+#[test]
+fn ron_serialize() {
+ let values = VecEnumValues {
+ vec: vec![
+ EnumValue::Int(123),
+ EnumValue::String("FooBar".to_string()),
+ EnumValue::Int(456),
+ EnumValue::String("XXX".to_string()),
+ EnumValue::Unit,
+ EnumValue::Tuple(1, "Middle".to_string(), false),
+ EnumValue::Struct {
+ a: 666,
+ b: "BBB".to_string(),
+ c: true,
+ },
+ ],
+ };
+
+ let pretty_config = ron::ser::PrettyConfig::new().new_line("\n".into());
+ let ron = ron::ser::to_string_pretty(&values, pretty_config).unwrap();
+ expect_test::expect![[r#"
+ (
+ vec: {
+ "Int": 123,
+ "String": "FooBar",
+ "Int": 456,
+ "String": "XXX",
+ "Unit": (),
+ "Tuple": (1, "Middle", false),
+ "Struct": (
+ a: 666,
+ b: "BBB",
+ c: true,
+ ),
+ },
+ )"#]]
+ .assert_eq(&ron);
+ // TODO deserializing a Strings as an Identifier seems unsupported
+ let deser_values: ron::Value = ron::de::from_str(&ron).unwrap();
+ expect_test::expect![[r#"
+ Map(
+ Map(
+ {
+ String(
+ "vec",
+ ): Map(
+ Map(
+ {
+ String(
+ "Int",
+ ): Number(
+ Integer(
+ 456,
+ ),
+ ),
+ String(
+ "String",
+ ): String(
+ "XXX",
+ ),
+ String(
+ "Struct",
+ ): Map(
+ Map(
+ {
+ String(
+ "a",
+ ): Number(
+ Integer(
+ 666,
+ ),
+ ),
+ String(
+ "b",
+ ): String(
+ "BBB",
+ ),
+ String(
+ "c",
+ ): Bool(
+ true,
+ ),
+ },
+ ),
+ ),
+ String(
+ "Tuple",
+ ): Seq(
+ [
+ Number(
+ Integer(
+ 1,
+ ),
+ ),
+ String(
+ "Middle",
+ ),
+ Bool(
+ false,
+ ),
+ ],
+ ),
+ String(
+ "Unit",
+ ): Unit,
+ },
+ ),
+ ),
+ },
+ ),
+ )
+ "#]]
+ .assert_debug_eq(&deser_values);
+}
+
+#[test]
+fn xml_round_trip() {
+ let values = VecEnumValues {
+ vec: vec![
+ EnumValue::Int(123),
+ EnumValue::String("FooBar".to_string()),
+ EnumValue::Int(456),
+ EnumValue::String("XXX".to_string()),
+ EnumValue::Unit,
+ // serialize_tuple and variants are not supported by XML
+ // EnumValue::Tuple(1, "Middle".to_string(), false),
+ // Cannot be deserialized. It serializes to:
+ // <Struct><EnumValue><a>666</a><b>BBB</b><c>true</c></EnumValue></Struct>
+ // EnumValue::Struct {
+ // a: 666,
+ // b: "BBB".to_string(),
+ // c: true,
+ // },
+ ],
+ };
+
+ let xml = serde_xml_rs::to_string(&values).unwrap();
+ expect_test::expect![[r#"<?xml version="1.0" encoding="UTF-8"?><VecEnumValues><vec><Int>123</Int><String>FooBar</String><Int>456</Int><String>XXX</String><Unit /></vec></VecEnumValues>"#]]
+ .assert_eq(&xml);
+ let deser_values: VecEnumValues = serde_xml_rs::from_str(&xml).unwrap();
+ assert_eq!(values, deser_values);
+}
+
+#[test]
+fn serde_test_round_trip() {
+ let values = VecEnumValues {
+ vec: vec![
+ EnumValue::Int(123),
+ EnumValue::String("FooBar".to_string()),
+ EnumValue::Int(456),
+ EnumValue::String("XXX".to_string()),
+ EnumValue::Unit,
+ EnumValue::Tuple(1, "Middle".to_string(), false),
+ EnumValue::Struct {
+ a: 666,
+ b: "BBB".to_string(),
+ c: true,
+ },
+ ],
+ };
+
+ use serde_test::Token::*;
+ serde_test::assert_tokens(
+ &values.readable(),
+ &[
+ Struct {
+ name: "VecEnumValues",
+ len: 1,
+ },
+ Str("vec"),
+ Map {
+ len: Option::Some(7),
+ },
+ Str("Int"),
+ I32(123),
+ Str("String"),
+ Str("FooBar"),
+ Str("Int"),
+ I32(456),
+ Str("String"),
+ Str("XXX"),
+ Str("Unit"),
+ Unit,
+ Str("Tuple"),
+ TupleStruct {
+ name: "EnumValue",
+ len: 3,
+ },
+ I32(1),
+ Str("Middle"),
+ Bool(false),
+ TupleStructEnd,
+ Str("Struct"),
+ Struct {
+ name: "EnumValue",
+ len: 3,
+ },
+ Str("a"),
+ I32(666),
+ Str("b"),
+ Str("BBB"),
+ Str("c"),
+ Bool(true),
+ StructEnd,
+ MapEnd,
+ StructEnd,
+ ],
+ );
+}
+
+#[test]
+fn serde_test_round_trip_human_readable() {
+ let values = VecEnumValues {
+ vec: vec![EnumValue::Ip(
+ IpAddr::from_str("127.0.0.1").unwrap(),
+ IpAddr::from_str("::7777:dead:beef").unwrap(),
+ )],
+ };
+
+ use serde_test::Token::*;
+ serde_test::assert_tokens(
+ &values.clone().readable(),
+ &[
+ Struct {
+ name: "VecEnumValues",
+ len: 1,
+ },
+ Str("vec"),
+ Map {
+ len: Option::Some(1),
+ },
+ Str("Ip"),
+ TupleStruct {
+ name: "EnumValue",
+ len: 2,
+ },
+ Str("127.0.0.1"),
+ Str("::7777:dead:beef"),
+ TupleStructEnd,
+ MapEnd,
+ StructEnd,
+ ],
+ );
+
+ serde_test::assert_tokens(
+ &values.compact(),
+ &[
+ Struct {
+ name: "VecEnumValues",
+ len: 1,
+ },
+ Str("vec"),
+ Map {
+ len: Option::Some(1),
+ },
+ Str("Ip"),
+ TupleStruct {
+ name: "EnumValue",
+ len: 2,
+ },
+ NewtypeVariant {
+ name: "IpAddr",
+ variant: "V4",
+ },
+ Tuple { len: 4 },
+ U8(127),
+ U8(0),
+ U8(0),
+ U8(1),
+ TupleEnd,
+ NewtypeVariant {
+ name: "IpAddr",
+ variant: "V6",
+ },
+ Tuple { len: 16 },
+ U8(0),
+ U8(0),
+ U8(0),
+ U8(0),
+ U8(0),
+ U8(0),
+ U8(0),
+ U8(0),
+ U8(0),
+ U8(0),
+ U8(0x77),
+ U8(0x77),
+ U8(0xde),
+ U8(0xad),
+ U8(0xbe),
+ U8(0xef),
+ TupleEnd,
+ TupleStructEnd,
+ MapEnd,
+ StructEnd,
+ ],
+ );
+}
+
+// Bincode does not support Deserializer::deserialize_identifier
+// https://github.com/bincode-org/bincode/blob/e0ac3245162ba668ba04591897dd88ff5b3096b8/src/de/mod.rs#L442
+
+#[test]
+fn rmp_round_trip() {
+ let values = VecEnumValues {
+ vec: vec![
+ EnumValue::Int(123),
+ EnumValue::String("FooBar".to_string()),
+ EnumValue::Int(456),
+ EnumValue::String("XXX".to_string()),
+ EnumValue::Unit,
+ EnumValue::Tuple(1, "Middle".to_string(), false),
+ EnumValue::Struct {
+ a: 666,
+ b: "BBB".to_string(),
+ c: true,
+ },
+ EnumValue::Ip(
+ IpAddr::from_str("127.0.0.1").unwrap(),
+ IpAddr::from_str("::7777:dead:beef").unwrap(),
+ ),
+ ],
+ };
+
+ let rmp = rmp_serde::to_vec(&values).unwrap();
+ expect_test::expect![[r#"\x91\x88\xa3Int{\xa6String\xa6FooBar\xa3Int\xcd\x01\xc8\xa6String\xa3XXX\xa4Unit\xc0\xa5Tuple\x93\x01\xa6Middle\xc2\xa6Struct\x93\xcd\x02\x9a\xa3BBB\xc3\xa2Ip\x92\x81\xa2V4\x94\x7f\x00\x00\x01\x81\xa2V6\xdc\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00ww\xcc\xde\xcc\xad\xcc\xbe\xcc\xef"#]]
+ .assert_eq(&bytes_debug_readable(&rmp));
+ let deser_values: VecEnumValues = rmp_serde::from_read(&*rmp).unwrap();
+ assert_eq!(values, deser_values);
+}
+
+#[test]
+fn yaml_round_trip() {
+ // Duplicate enum variants do not work with YAML
+ let values = VecEnumValues {
+ vec: vec![
+ EnumValue::Int(123),
+ EnumValue::String("FooBar".to_string()),
+ // EnumValue::Int(456),
+ // EnumValue::String("XXX".to_string()),
+ EnumValue::Unit,
+ EnumValue::Tuple(1, "Middle".to_string(), false),
+ EnumValue::Struct {
+ a: 666,
+ b: "BBB".to_string(),
+ c: true,
+ },
+ ],
+ };
+
+ let yaml = serde_yaml::to_string(&values).unwrap();
+ expect_test::expect![[r#"
+ vec:
+ Int: 123
+ String: FooBar
+ Unit: null
+ Tuple:
+ - 1
+ - Middle
+ - false
+ Struct:
+ a: 666
+ b: BBB
+ c: true
+ "#]]
+ .assert_eq(&yaml);
+ let deser_values: VecEnumValues = serde_yaml::from_str(&yaml).unwrap();
+ assert_eq!(values, deser_values);
+}
diff --git a/third_party/rust/serde_with/tests/serde_as/frominto.rs b/third_party/rust/serde_with/tests/serde_as/frominto.rs
new file mode 100644
index 0000000000..f7f3cac213
--- /dev/null
+++ b/third_party/rust/serde_with/tests/serde_as/frominto.rs
@@ -0,0 +1,187 @@
+use super::*;
+use core::convert::TryFrom;
+use serde_with::{FromInto, TryFromInto};
+
+#[derive(Clone, Debug, PartialEq)]
+enum IntoSerializable {
+ A,
+ B,
+ C,
+}
+
+impl From<IntoSerializable> for String {
+ fn from(value: IntoSerializable) -> Self {
+ match value {
+ IntoSerializable::A => "String A",
+ IntoSerializable::B => "Some other value",
+ IntoSerializable::C => "Looks like 123",
+ }
+ .to_string()
+ }
+}
+
+#[derive(Debug, PartialEq)]
+enum FromDeserializable {
+ Zero,
+ Odd(u32),
+ Even(u32),
+}
+
+impl From<u32> for FromDeserializable {
+ fn from(value: u32) -> Self {
+ match value {
+ 0 => FromDeserializable::Zero,
+ e if e % 2 == 0 => FromDeserializable::Even(e),
+ o => FromDeserializable::Odd(o),
+ }
+ }
+}
+
+#[derive(Clone, Debug, PartialEq)]
+enum LikeBool {
+ Trueish,
+ Falseisch,
+}
+
+impl From<bool> for LikeBool {
+ fn from(b: bool) -> Self {
+ if b {
+ LikeBool::Trueish
+ } else {
+ LikeBool::Falseisch
+ }
+ }
+}
+
+impl From<LikeBool> for bool {
+ fn from(lb: LikeBool) -> Self {
+ match lb {
+ LikeBool::Trueish => true,
+ LikeBool::Falseisch => false,
+ }
+ }
+}
+
+#[test]
+fn test_frominto_ser() {
+ #[serde_as]
+ #[derive(Debug, PartialEq, Serialize)]
+ struct S(#[serde_as(serialize_as = "FromInto<String>")] IntoSerializable);
+
+ check_serialization(S(IntoSerializable::A), expect![[r#""String A""#]]);
+ check_serialization(S(IntoSerializable::B), expect![[r#""Some other value""#]]);
+ check_serialization(S(IntoSerializable::C), expect![[r#""Looks like 123""#]]);
+}
+
+#[test]
+fn test_tryfrominto_ser() {
+ #[serde_as]
+ #[derive(Debug, PartialEq, Serialize)]
+ struct S(#[serde_as(serialize_as = "TryFromInto<String>")] IntoSerializable);
+
+ check_serialization(S(IntoSerializable::A), expect![[r#""String A""#]]);
+ check_serialization(S(IntoSerializable::B), expect![[r#""Some other value""#]]);
+ check_serialization(S(IntoSerializable::C), expect![[r#""Looks like 123""#]]);
+}
+
+#[test]
+fn test_frominto_de() {
+ #[serde_as]
+ #[derive(Debug, PartialEq, Deserialize)]
+ struct S(#[serde_as(deserialize_as = "FromInto<u32>")] FromDeserializable);
+
+ check_deserialization(S(FromDeserializable::Zero), "0");
+ check_deserialization(S(FromDeserializable::Odd(1)), "1");
+ check_deserialization(S(FromDeserializable::Odd(101)), "101");
+ check_deserialization(S(FromDeserializable::Even(2)), "2");
+ check_deserialization(S(FromDeserializable::Even(202)), "202");
+}
+
+#[test]
+fn test_tryfrominto_de() {
+ #[serde_as]
+ #[derive(Debug, PartialEq, Deserialize)]
+ struct S(#[serde_as(deserialize_as = "TryFromInto<u32>")] FromDeserializable);
+
+ check_deserialization(S(FromDeserializable::Zero), "0");
+ check_deserialization(S(FromDeserializable::Odd(1)), "1");
+ check_deserialization(S(FromDeserializable::Odd(101)), "101");
+ check_deserialization(S(FromDeserializable::Even(2)), "2");
+ check_deserialization(S(FromDeserializable::Even(202)), "202");
+}
+
+#[test]
+fn test_frominto_de_and_ser() {
+ #[serde_as]
+ #[derive(Debug, PartialEq, Deserialize, Serialize)]
+ struct S(#[serde_as(as = "FromInto<bool>")] LikeBool);
+
+ is_equal(S(LikeBool::Trueish), expect![[r#"true"#]]);
+ is_equal(S(LikeBool::Falseisch), expect![[r#"false"#]]);
+}
+
+#[test]
+fn test_tryfrominto_de_and_ser() {
+ #[serde_as]
+ #[derive(Debug, PartialEq, Deserialize, Serialize)]
+ struct S(#[serde_as(as = "TryFromInto<bool>")] LikeBool);
+
+ is_equal(S(LikeBool::Trueish), expect![[r#"true"#]]);
+ is_equal(S(LikeBool::Falseisch), expect![[r#"false"#]]);
+}
+
+#[derive(Clone, Debug, PartialEq)]
+enum TryIntoSerializable {
+ Works,
+ Fails,
+}
+
+impl TryFrom<TryIntoSerializable> for String {
+ type Error = &'static str;
+
+ fn try_from(value: TryIntoSerializable) -> Result<Self, Self::Error> {
+ match value {
+ TryIntoSerializable::Works => Ok("Works".to_string()),
+ TryIntoSerializable::Fails => Err("Fails cannot be turned into String"),
+ }
+ }
+}
+
+#[derive(Debug, PartialEq)]
+enum TryFromDeserializable {
+ Zero,
+}
+
+impl TryFrom<u32> for TryFromDeserializable {
+ type Error = &'static str;
+
+ fn try_from(value: u32) -> Result<Self, Self::Error> {
+ match value {
+ 0 => Ok(TryFromDeserializable::Zero),
+ _ => Err("Number is not zero"),
+ }
+ }
+}
+
+#[test]
+fn test_tryfrominto_ser_with_error() {
+ #[serde_as]
+ #[derive(Debug, PartialEq, Serialize)]
+ struct S(#[serde_as(serialize_as = "TryFromInto<String>")] TryIntoSerializable);
+
+ check_serialization(S(TryIntoSerializable::Works), expect![[r#""Works""#]]);
+ check_error_serialization(
+ S(TryIntoSerializable::Fails),
+ expect![[r#"Fails cannot be turned into String"#]],
+ );
+}
+
+#[test]
+fn test_tryfrominto_de_with_error() {
+ #[serde_as]
+ #[derive(Debug, PartialEq, Deserialize)]
+ struct S(#[serde_as(deserialize_as = "TryFromInto<u32>")] TryFromDeserializable);
+
+ check_deserialization(S(TryFromDeserializable::Zero), "0");
+ check_error_deserialization::<S>("1", expect![[r#"Number is not zero"#]]);
+}
diff --git a/third_party/rust/serde_with/tests/serde_as/key_value_map.rs b/third_party/rust/serde_with/tests/serde_as/key_value_map.rs
new file mode 100644
index 0000000000..8975af4421
--- /dev/null
+++ b/third_party/rust/serde_with/tests/serde_as/key_value_map.rs
@@ -0,0 +1,350 @@
+use super::*;
+use core::str::FromStr;
+use serde_test::Configure;
+use serde_with::{serde_as, KeyValueMap};
+use std::net::IpAddr;
+
+#[serde_as]
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+#[serde(transparent)]
+struct KVMap<E> {
+ #[serde_as(as = "KeyValueMap<_>")]
+ #[serde(bound(serialize = "E: Serialize", deserialize = "E: Deserialize<'de>"))]
+ foo: Vec<E>,
+}
+
+#[test]
+fn test_kvmap_struct_json() {
+ #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+ struct Struct {
+ #[serde(rename = "$key$")]
+ key: String,
+ bar: String,
+ baz: i32,
+ }
+
+ let kvmap = KVMap {
+ foo: vec![
+ Struct {
+ key: "a".to_string(),
+ bar: "b".to_string(),
+ baz: 1,
+ },
+ Struct {
+ key: "c".to_string(),
+ bar: "d".to_string(),
+ baz: 2,
+ },
+ ],
+ };
+
+ is_equal(
+ kvmap,
+ expect![[r#"
+ {
+ "a": {
+ "bar": "b",
+ "baz": 1
+ },
+ "c": {
+ "bar": "d",
+ "baz": 2
+ }
+ }"#]],
+ );
+}
+
+#[test]
+fn test_kvmap_tuple_struct_json() {
+ #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+ struct TupleStruct(String, String, i32);
+
+ let kvmap = KVMap {
+ foo: vec![
+ TupleStruct("a".to_string(), "b".to_string(), 1),
+ TupleStruct("c".to_string(), "d".to_string(), 2),
+ ],
+ };
+
+ is_equal(
+ kvmap,
+ expect![[r#"
+ {
+ "a": [
+ "b",
+ 1
+ ],
+ "c": [
+ "d",
+ 2
+ ]
+ }"#]],
+ );
+}
+
+#[test]
+fn test_kvmap_tuple_json() {
+ #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+ #[serde(transparent)]
+ struct Tuple((String, String, i32));
+
+ let kvmap = KVMap {
+ foo: vec![
+ Tuple(("a".to_string(), "b".to_string(), 1)),
+ Tuple(("c".to_string(), "d".to_string(), 2)),
+ ],
+ };
+
+ is_equal(
+ kvmap,
+ expect![[r#"
+ {
+ "a": [
+ "b",
+ 1
+ ],
+ "c": [
+ "d",
+ 2
+ ]
+ }"#]],
+ );
+}
+
+#[test]
+fn test_kvmap_map_json() {
+ #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+ #[serde(transparent)]
+ struct Map(BTreeMap<String, String>);
+
+ let kvmap = KVMap {
+ foo: vec![
+ Map(BTreeMap::from([
+ ("$key$".to_string(), "a".to_string()),
+ ("bar".to_string(), "b".to_string()),
+ ("baz".to_string(), "1".to_string()),
+ ])),
+ Map(BTreeMap::from([
+ ("$key$".to_string(), "c".to_string()),
+ ("bar".to_string(), "d".to_string()),
+ ("baz".to_string(), "2".to_string()),
+ ])),
+ ],
+ };
+
+ is_equal(
+ kvmap,
+ expect![[r#"
+ {
+ "a": {
+ "bar": "b",
+ "baz": "1"
+ },
+ "c": {
+ "bar": "d",
+ "baz": "2"
+ }
+ }"#]],
+ );
+}
+
+#[test]
+fn test_kvmap_seq_json() {
+ #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+ #[serde(transparent)]
+ struct Seq(Vec<String>);
+
+ let kvmap = KVMap {
+ foo: vec![
+ Seq(vec!["a".to_string(), "b".to_string(), "1".to_string()]),
+ Seq(vec!["c".to_string(), "d".to_string(), "2".to_string()]),
+ ],
+ };
+
+ is_equal(
+ kvmap,
+ expect![[r#"
+ {
+ "a": [
+ "b",
+ "1"
+ ],
+ "c": [
+ "d",
+ "2"
+ ]
+ }"#]],
+ );
+}
+
+#[test]
+fn test_kvmap_complex_key_serde_test() {
+ #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+ struct ComplexKey {
+ #[serde(rename = "$key$")]
+ net: (IpAddr, u8),
+ bar: String,
+ baz: i32,
+ }
+
+ let kvmap = KVMap {
+ foo: vec![
+ ComplexKey {
+ net: (IpAddr::from_str("127.0.0.0").unwrap(), 24),
+ bar: "b".to_string(),
+ baz: 1,
+ },
+ ComplexKey {
+ net: (IpAddr::from_str("::7777:dead:beef").unwrap(), 48),
+ bar: "d".to_string(),
+ baz: 2,
+ },
+ ],
+ };
+
+ {
+ use serde_test::Token::*;
+ serde_test::assert_tokens(
+ &kvmap.clone().readable(),
+ &[
+ Map {
+ len: Option::Some(2),
+ },
+ Tuple { len: 2 },
+ Str("127.0.0.0"),
+ U8(24),
+ TupleEnd,
+ Struct {
+ name: "ComplexKey",
+ len: 2,
+ },
+ Str("bar"),
+ Str("b"),
+ Str("baz"),
+ I32(1),
+ StructEnd,
+ Tuple { len: 2 },
+ Str("::7777:dead:beef"),
+ U8(48),
+ TupleEnd,
+ Struct {
+ name: "ComplexKey",
+ len: 2,
+ },
+ Str("bar"),
+ Str("d"),
+ Str("baz"),
+ I32(2),
+ StructEnd,
+ MapEnd,
+ ],
+ );
+
+ serde_test::assert_tokens(
+ &kvmap.compact(),
+ &[
+ Map {
+ len: Option::Some(2),
+ },
+ Tuple { len: 2 },
+ NewtypeVariant {
+ name: "IpAddr",
+ variant: "V4",
+ },
+ Tuple { len: 4 },
+ U8(127),
+ U8(0),
+ U8(0),
+ U8(0),
+ TupleEnd,
+ U8(24),
+ TupleEnd,
+ Struct {
+ name: "ComplexKey",
+ len: 2,
+ },
+ Str("bar"),
+ Str("b"),
+ Str("baz"),
+ I32(1),
+ StructEnd,
+ Tuple { len: 2 },
+ NewtypeVariant {
+ name: "IpAddr",
+ variant: "V6",
+ },
+ Tuple { len: 16 },
+ U8(0),
+ U8(0),
+ U8(0),
+ U8(0),
+ U8(0),
+ U8(0),
+ U8(0),
+ U8(0),
+ U8(0),
+ U8(0),
+ U8(0x77),
+ U8(0x77),
+ U8(0xde),
+ U8(0xad),
+ U8(0xbe),
+ U8(0xef),
+ TupleEnd,
+ U8(48),
+ TupleEnd,
+ Struct {
+ name: "ComplexKey",
+ len: 2,
+ },
+ Str("bar"),
+ Str("d"),
+ Str("baz"),
+ I32(2),
+ StructEnd,
+ MapEnd,
+ ],
+ );
+ }
+}
+
+#[test]
+fn test_kvmap_complex_key_yaml() {
+ #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+ struct ComplexKey {
+ #[serde(rename = "$key$")]
+ net: (IpAddr, u8),
+ bar: String,
+ baz: i32,
+ }
+
+ let kvmap = KVMap {
+ foo: vec![
+ ComplexKey {
+ net: (IpAddr::from_str("127.0.0.0").unwrap(), 24),
+ bar: "b".to_string(),
+ baz: 1,
+ },
+ ComplexKey {
+ net: (IpAddr::from_str("::7777:dead:beef").unwrap(), 48),
+ bar: "d".to_string(),
+ baz: 2,
+ },
+ ],
+ };
+
+ let yaml = serde_yaml::to_string(&kvmap).unwrap();
+ expect_test::expect![[r#"
+ ? - 127.0.0.0
+ - 24
+ : bar: b
+ baz: 1
+ ? - ::7777:dead:beef
+ - 48
+ : bar: d
+ baz: 2
+ "#]]
+ .assert_eq(&yaml);
+ let deser_values = serde_yaml::from_str(&yaml).unwrap();
+ assert_eq!(kvmap, deser_values);
+}
diff --git a/third_party/rust/serde_with/tests/serde_as/lib.rs b/third_party/rust/serde_with/tests/serde_as/lib.rs
new file mode 100644
index 0000000000..122c02fdb8
--- /dev/null
+++ b/third_party/rust/serde_with/tests/serde_as/lib.rs
@@ -0,0 +1,1181 @@
+#![allow(
+ // clippy is broken and shows wrong warnings
+ // clippy on stable does not know yet about the lint name
+ unknown_lints,
+ // https://github.com/rust-lang/rust-clippy/issues/8867
+ clippy::derive_partial_eq_without_eq,
+)]
+
+extern crate alloc;
+
+mod collections;
+mod default_on;
+mod enum_map;
+mod frominto;
+mod key_value_map;
+mod map_tuple_list;
+mod pickfirst;
+mod serde_as_macro;
+mod serde_conv;
+mod time;
+#[path = "../utils.rs"]
+mod utils;
+
+use crate::utils::*;
+use alloc::{
+ collections::{BTreeMap, BTreeSet, LinkedList, VecDeque},
+ rc::{Rc, Weak as RcWeak},
+ sync::{Arc, Weak as ArcWeak},
+};
+use core::cell::{Cell, RefCell};
+use expect_test::expect;
+use serde::{Deserialize, Serialize};
+use serde_with::{
+ formats::{CommaSeparator, Flexible, Strict},
+ serde_as, BoolFromInt, BytesOrString, DisplayFromStr, Map, NoneAsEmptyString, OneOrMany, Same,
+ Seq, StringWithSeparator,
+};
+use std::{
+ collections::HashMap,
+ sync::{Mutex, RwLock},
+};
+
+#[test]
+fn test_basic_wrappers() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct SBox(#[serde_as(as = "Box<DisplayFromStr>")] Box<u32>);
+
+ is_equal(SBox(Box::new(123)), expect![[r#""123""#]]);
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct SRc(#[serde_as(as = "Rc<DisplayFromStr>")] Rc<u32>);
+
+ is_equal(SRc(Rc::new(123)), expect![[r#""123""#]]);
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize)]
+ struct SRcWeak(#[serde_as(as = "RcWeak<DisplayFromStr>")] RcWeak<u32>);
+
+ check_serialization(SRcWeak(RcWeak::new()), expect![[r#"null"#]]);
+ let s: SRcWeak = serde_json::from_str("null").unwrap();
+ assert!(s.0.upgrade().is_none());
+ let s: SRcWeak = serde_json::from_str("\"123\"").unwrap();
+ assert!(s.0.upgrade().is_none());
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct SArc(#[serde_as(as = "Arc<DisplayFromStr>")] Arc<u32>);
+
+ is_equal(SArc(Arc::new(123)), expect![[r#""123""#]]);
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize)]
+ struct SArcWeak(#[serde_as(as = "ArcWeak<DisplayFromStr>")] ArcWeak<u32>);
+
+ check_serialization(SArcWeak(ArcWeak::new()), expect![[r#"null"#]]);
+ let s: SArcWeak = serde_json::from_str("null").unwrap();
+ assert!(s.0.upgrade().is_none());
+ let s: SArcWeak = serde_json::from_str("\"123\"").unwrap();
+ assert!(s.0.upgrade().is_none());
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct SCell(#[serde_as(as = "Cell<DisplayFromStr>")] Cell<u32>);
+
+ is_equal(SCell(Cell::new(123)), expect![[r#""123""#]]);
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct SRefCell(#[serde_as(as = "RefCell<DisplayFromStr>")] RefCell<u32>);
+
+ is_equal(SRefCell(RefCell::new(123)), expect![[r#""123""#]]);
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize)]
+ struct SMutex(#[serde_as(as = "Mutex<DisplayFromStr>")] Mutex<u32>);
+
+ check_serialization(SMutex(Mutex::new(123)), expect![[r#""123""#]]);
+ let s: SMutex = serde_json::from_str("\"123\"").unwrap();
+ assert_eq!(*s.0.lock().unwrap(), 123);
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize)]
+ struct SRwLock(#[serde_as(as = "RwLock<DisplayFromStr>")] RwLock<u32>);
+
+ let expected = expect![[r#""123""#]];
+ check_serialization(SRwLock(RwLock::new(123)), expected);
+ let s: SRwLock = serde_json::from_str("\"123\"").unwrap();
+ assert_eq!(*s.0.read().unwrap(), 123);
+}
+
+#[test]
+fn test_option() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S(#[serde_as(as = "_")] Option<u32>);
+
+ is_equal(S(None), expect![[r#"null"#]]);
+ is_equal(S(Some(9)), expect![[r#"9"#]]);
+ check_error_deserialization::<S>(
+ r#"{}"#,
+ expect![[r#"invalid type: map, expected u32 at line 1 column 0"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct Struct {
+ #[serde_as(as = "_")]
+ value: Option<u32>,
+ }
+ check_error_deserialization::<Struct>(
+ r#"{}"#,
+ expect![[r#"missing field `value` at line 1 column 2"#]],
+ );
+}
+
+#[test]
+fn test_result() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S(
+ #[serde_as(as = "Result<StringWithSeparator<CommaSeparator, u32>, DisplayFromStr>")]
+ Result<Vec<u32>, u32>,
+ );
+
+ is_equal(
+ S(Ok(vec![1, 2, 3])),
+ expect![[r#"
+ {
+ "Ok": "1,2,3"
+ }"#]],
+ );
+ is_equal(
+ S(Err(9)),
+ expect![[r#"
+ {
+ "Err": "9"
+ }"#]],
+ );
+ check_error_deserialization::<S>(r#"{}"#, expect![[r#"expected value at line 1 column 2"#]]);
+}
+
+#[test]
+fn test_display_fromstr() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S(#[serde_as(as = "DisplayFromStr")] u32);
+
+ is_equal(S(123), expect![[r#""123""#]]);
+}
+
+#[test]
+fn test_tuples() {
+ use std::net::IpAddr;
+ let ip = "1.2.3.4".parse().unwrap();
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S1(#[serde_as(as = "(DisplayFromStr,)")] (u32,));
+ is_equal(
+ S1((1,)),
+ expect![[r#"
+ [
+ "1"
+ ]"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S2a(#[serde_as(as = "(DisplayFromStr, DisplayFromStr)")] (u32, IpAddr));
+ is_equal(
+ S2a((555_888, ip)),
+ expect![[r#"
+ [
+ "555888",
+ "1.2.3.4"
+ ]"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S2b(#[serde_as(as = "(_, DisplayFromStr)")] (u32, IpAddr));
+ is_equal(
+ S2b((987, ip)),
+ expect![[r#"
+ [
+ 987,
+ "1.2.3.4"
+ ]"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S2c(#[serde_as(as = "(Same, DisplayFromStr)")] (u32, IpAddr));
+ is_equal(
+ S2c((987, ip)),
+ expect![[r#"
+ [
+ 987,
+ "1.2.3.4"
+ ]"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S6(
+ #[serde_as(as = "(Same, Same, Same, Same, Same, Same)")] (u8, u16, u32, i8, i16, i32),
+ );
+ is_equal(
+ S6((8, 16, 32, -8, 16, -32)),
+ expect![[r#"
+ [
+ 8,
+ 16,
+ 32,
+ -8,
+ 16,
+ -32
+ ]"#]],
+ );
+}
+
+#[test]
+fn test_arrays() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S0(#[serde_as(as = "[DisplayFromStr; 0]")] [u32; 0]);
+ is_equal(S0([]), expect![[r#"[]"#]]);
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S1(#[serde_as(as = "[DisplayFromStr; 1]")] [u32; 1]);
+ is_equal(
+ S1([1]),
+ expect![[r#"
+ [
+ "1"
+ ]"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S2(#[serde_as(as = "[Same; 2]")] [u32; 2]);
+ is_equal(
+ S2([11, 22]),
+ expect![[r#"
+ [
+ 11,
+ 22
+ ]"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S32(#[serde_as(as = "[Same; 32]")] [u32; 32]);
+ is_equal(
+ S32([
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ ]),
+ expect![[r#"
+ [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31
+ ]"#]],
+ );
+}
+
+#[test]
+fn test_sequence_like_types() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S1(#[serde_as(as = "Box<[Same]>")] Box<[u32]>);
+ is_equal(
+ S1(vec![1, 2, 3, 99].into()),
+ expect![[r#"
+ [
+ 1,
+ 2,
+ 3,
+ 99
+ ]"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S2(#[serde_as(as = "BTreeSet<Same>")] BTreeSet<u32>);
+ is_equal(
+ S2(vec![1, 2, 3, 99].into_iter().collect()),
+ expect![[r#"
+ [
+ 1,
+ 2,
+ 3,
+ 99
+ ]"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S3(#[serde_as(as = "LinkedList<Same>")] LinkedList<u32>);
+ is_equal(
+ S3(vec![1, 2, 3, 99].into_iter().collect()),
+ expect![[r#"
+ [
+ 1,
+ 2,
+ 3,
+ 99
+ ]"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S4(#[serde_as(as = "Vec<Same>")] Vec<u32>);
+ is_equal(
+ S4(vec![1, 2, 3, 99]),
+ expect![[r#"
+ [
+ 1,
+ 2,
+ 3,
+ 99
+ ]"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S5(#[serde_as(as = "VecDeque<Same>")] VecDeque<u32>);
+ is_equal(
+ S5(vec![1, 2, 3, 99].into()),
+ expect![[r#"
+ [
+ 1,
+ 2,
+ 3,
+ 99
+ ]"#]],
+ );
+}
+
+#[test]
+fn test_none_as_empty_string() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S(#[serde_as(as = "NoneAsEmptyString")] Option<String>);
+
+ is_equal(S(None), expect![[r#""""#]]);
+ is_equal(S(Some("Hello".to_string())), expect![[r#""Hello""#]]);
+}
+
+#[test]
+fn test_bytes_or_string() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S(#[serde_as(as = "BytesOrString")] Vec<u8>);
+
+ is_equal(
+ S(vec![1, 2, 3]),
+ expect![[r#"
+ [
+ 1,
+ 2,
+ 3
+ ]"#]],
+ );
+ check_deserialization(S(vec![72, 101, 108, 108, 111]), r#""Hello""#);
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct SVec(#[serde_as(as = "Vec<BytesOrString>")] Vec<Vec<u8>>);
+
+ is_equal(
+ SVec(vec![vec![1, 2, 3]]),
+ expect![[r#"
+ [
+ [
+ 1,
+ 2,
+ 3
+ ]
+ ]"#]],
+ );
+ check_deserialization(
+ SVec(vec![
+ vec![72, 101, 108, 108, 111],
+ vec![87, 111, 114, 108, 100],
+ vec![1, 2, 3],
+ ]),
+ r#"["Hello","World",[1,2,3]]"#,
+ );
+}
+
+#[test]
+fn string_with_separator() {
+ use serde_with::{
+ formats::{CommaSeparator, SpaceSeparator},
+ StringWithSeparator,
+ };
+
+ #[serde_as]
+ #[derive(Deserialize, Serialize)]
+ struct A {
+ #[serde_as(as = "StringWithSeparator::<SpaceSeparator, String>")]
+ tags: Vec<String>,
+ #[serde_as(as = "StringWithSeparator::<CommaSeparator, String>")]
+ // more_tags: Vec<String>,
+ 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: Default::default(),
+ };
+ assert_eq!(
+ r#"{"tags":"1 2 3","more_tags":""}"#,
+ serde_json::to_string(&x).unwrap()
+ );
+}
+
+#[test]
+fn test_vec_skip_error() {
+ use serde_with::VecSkipError;
+
+ #[serde_as]
+ #[derive(Debug, PartialEq, Deserialize, Serialize)]
+ struct S {
+ tag: String,
+ #[serde_as(as = "VecSkipError<_>")]
+ values: Vec<u8>,
+ }
+
+ check_deserialization(
+ S {
+ tag: "type".into(),
+ values: vec![0, 1],
+ },
+ r#"{"tag":"type","values":[0, "str", 1, [10, 11], -2, {}, 300]}"#,
+ );
+ is_equal(
+ S {
+ tag: "round-trip".into(),
+ values: vec![0, 255],
+ },
+ expect![[r#"
+ {
+ "tag": "round-trip",
+ "values": [
+ 0,
+ 255
+ ]
+ }"#]],
+ );
+}
+
+#[test]
+fn test_serialize_reference() {
+ #[serde_as]
+ #[derive(Debug, Serialize)]
+ struct S1<'a>(#[serde_as(as = "Vec<DisplayFromStr>")] &'a Vec<u32>);
+ check_serialization(
+ S1(&vec![1, 2]),
+ expect![[r#"
+ [
+ "1",
+ "2"
+ ]"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize)]
+ struct S1a<'a>(#[serde_as(as = "&Vec<DisplayFromStr>")] &'a Vec<u32>);
+ check_serialization(
+ S1(&vec![1, 2]),
+ expect![[r#"
+ [
+ "1",
+ "2"
+ ]"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize)]
+ struct S1Mut<'a>(#[serde_as(as = "Vec<DisplayFromStr>")] &'a mut Vec<u32>);
+ check_serialization(
+ S1(&vec![1, 2]),
+ expect![[r#"
+ [
+ "1",
+ "2"
+ ]"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize)]
+ struct S1aMut<'a>(#[serde_as(as = "&mut Vec<DisplayFromStr>")] &'a mut Vec<u32>);
+ check_serialization(
+ S1(&vec![1, 2]),
+ expect![[r#"
+ [
+ "1",
+ "2"
+ ]"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize)]
+ struct S2<'a>(#[serde_as(as = "&[DisplayFromStr]")] &'a [u32]);
+ check_serialization(
+ S2(&[1, 2]),
+ expect![[r#"
+ [
+ "1",
+ "2"
+ ]"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize)]
+ struct S3<'a>(
+ #[serde_as(as = "&BTreeMap<DisplayFromStr, DisplayFromStr>")] &'a BTreeMap<bool, u32>,
+ );
+ let bmap = vec![(false, 123), (true, 456)].into_iter().collect();
+ check_serialization(
+ S3(&bmap),
+ expect![[r#"
+ {
+ "false": "123",
+ "true": "456"
+ }"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize)]
+ struct S4<'a>(#[serde_as(as = "&Vec<(_, DisplayFromStr)>")] &'a BTreeMap<bool, u32>);
+ let bmap = vec![(false, 123), (true, 456)].into_iter().collect();
+ check_serialization(
+ S4(&bmap),
+ expect![[r#"
+ [
+ [
+ false,
+ "123"
+ ],
+ [
+ true,
+ "456"
+ ]
+ ]"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize)]
+ struct S5<'a>(
+ #[serde_as(as = "&BTreeMap<DisplayFromStr, &Vec<(_, _)>>")]
+ &'a Vec<(u32, &'a BTreeMap<bool, String>)>,
+ );
+ let bmap0 = vec![(false, "123".to_string()), (true, "456".to_string())]
+ .into_iter()
+ .collect();
+ let bmap1 = vec![(true, "Hello".to_string()), (false, "World".to_string())]
+ .into_iter()
+ .collect();
+ let vec = vec![(111, &bmap0), (999, &bmap1)];
+ check_serialization(
+ S5(&vec),
+ expect![[r#"
+ {
+ "111": [
+ [
+ false,
+ "123"
+ ],
+ [
+ true,
+ "456"
+ ]
+ ],
+ "999": [
+ [
+ false,
+ "World"
+ ],
+ [
+ true,
+ "Hello"
+ ]
+ ]
+ }"#]],
+ );
+}
+
+#[test]
+fn test_big_arrays() {
+ // Single Big Array
+ #[serde_as]
+ #[derive(Debug, PartialEq, Serialize, Deserialize)]
+ struct S1(#[serde_as(as = "[_; 64]")] [u8; 64]);
+ is_equal_compact(
+ S1([0; 64]),
+ expect![[
+ r#"[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]"#
+ ]],
+ );
+ // Too few entries
+ check_error_deserialization::<S1>(
+ r#"[0,0,0,0,0,0,0,0,0,0,0,0,0,0]"#,
+ expect![[r#"invalid length 14, expected an array of size 64 at line 1 column 29"#]],
+ );
+ // Too many entries
+ check_error_deserialization::<S1>(
+ r#"[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]"#,
+ expect![[r#"trailing characters at line 1 column 130"#]],
+ );
+
+ // Single Big Array
+ #[serde_as]
+ #[derive(Debug, PartialEq, Serialize, Deserialize)]
+ struct S2(#[serde_as(as = "[DisplayFromStr; 40]")] [u8; 40]);
+ is_equal_compact(
+ S2([0; 40]),
+ expect![[
+ r#"["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"]"#
+ ]],
+ );
+
+ // Nested Big Arrays
+ #[serde_as]
+ #[derive(Debug, PartialEq, Serialize, Deserialize)]
+ struct S3(#[serde_as(as = "[[_; 34]; 33]")] [[u8; 34]; 33]);
+ is_equal_compact(
+ S3([[0; 34]; 33]),
+ expect![[
+ r#"[[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]]"#
+ ]],
+ );
+}
+
+#[test]
+fn test_bytes() {
+ // The test case is copied from
+ // https://github.com/serde-rs/bytes/blob/cbae606b9dc225fc094b031cc84eac9493da2058/tests/test_derive.rs
+ // Original code by @dtolnay
+
+ use alloc::borrow::Cow;
+ use serde_test::{assert_de_tokens, assert_tokens, Token};
+ use serde_with::Bytes;
+
+ #[serde_as]
+ #[derive(Serialize, Deserialize, PartialEq, Debug)]
+ struct Test<'a> {
+ #[serde_as(as = "Bytes")]
+ array: [u8; 52],
+
+ #[serde_as(as = "Bytes")]
+ slice: &'a [u8],
+
+ #[serde_as(as = "Bytes")]
+ vec: Vec<u8>,
+
+ #[serde_as(as = "Bytes")]
+ cow_slice: Cow<'a, [u8]>,
+
+ #[serde_as(as = "Box<Bytes>")]
+ boxed_array: Box<[u8; 52]>,
+
+ #[serde_as(as = "Bytes")]
+ boxed_array2: Box<[u8; 52]>,
+
+ #[serde_as(as = "Bytes")]
+ boxed_slice: Box<[u8]>,
+
+ #[serde_as(as = "Option<Bytes>")]
+ opt_slice: Option<&'a [u8]>,
+
+ #[serde_as(as = "Option<Bytes>")]
+ opt_vec: Option<Vec<u8>>,
+
+ #[serde_as(as = "Option<Bytes>")]
+ opt_cow_slice: Option<Cow<'a, [u8]>>,
+ }
+
+ let test = Test {
+ array: *b"ABCDEFGHIJKLMNOPQRSTUVWXZYabcdefghijklmnopqrstuvwxyz",
+ slice: b"...",
+ vec: b"...".to_vec(),
+ cow_slice: Cow::Borrowed(b"..."),
+ boxed_array: Box::new(*b"ABCDEFGHIJKLMNOPQRSTUVWXZYabcdefghijklmnopqrstuvwxyz"),
+ boxed_array2: Box::new(*b"ABCDEFGHIJKLMNOPQRSTUVWXZYabcdefghijklmnopqrstuvwxyz"),
+ boxed_slice: b"...".to_vec().into_boxed_slice(),
+ opt_slice: Some(b"..."),
+ opt_vec: Some(b"...".to_vec()),
+ opt_cow_slice: Some(Cow::Borrowed(b"...")),
+ };
+
+ assert_tokens(
+ &test,
+ &[
+ Token::Struct {
+ name: "Test",
+ len: 10,
+ },
+ Token::Str("array"),
+ Token::BorrowedBytes(b"ABCDEFGHIJKLMNOPQRSTUVWXZYabcdefghijklmnopqrstuvwxyz"),
+ Token::Str("slice"),
+ Token::BorrowedBytes(b"..."),
+ Token::Str("vec"),
+ Token::Bytes(b"..."),
+ Token::Str("cow_slice"),
+ Token::BorrowedBytes(b"..."),
+ Token::Str("boxed_array"),
+ Token::BorrowedBytes(b"ABCDEFGHIJKLMNOPQRSTUVWXZYabcdefghijklmnopqrstuvwxyz"),
+ Token::Str("boxed_array2"),
+ Token::BorrowedBytes(b"ABCDEFGHIJKLMNOPQRSTUVWXZYabcdefghijklmnopqrstuvwxyz"),
+ Token::Str("boxed_slice"),
+ Token::Bytes(b"..."),
+ Token::Str("opt_slice"),
+ Token::Some,
+ Token::BorrowedBytes(b"..."),
+ Token::Str("opt_vec"),
+ Token::Some,
+ Token::Bytes(b"..."),
+ Token::Str("opt_cow_slice"),
+ Token::Some,
+ Token::BorrowedBytes(b"..."),
+ Token::StructEnd,
+ ],
+ );
+
+ // Test string deserialization
+ assert_de_tokens(
+ &test,
+ &[
+ Token::Struct {
+ name: "Test",
+ len: 10,
+ },
+ Token::Str("array"),
+ Token::BorrowedStr("ABCDEFGHIJKLMNOPQRSTUVWXZYabcdefghijklmnopqrstuvwxyz"),
+ Token::Str("slice"),
+ Token::BorrowedStr("..."),
+ Token::Str("vec"),
+ Token::Bytes(b"..."),
+ Token::Str("cow_slice"),
+ Token::BorrowedStr("..."),
+ Token::Str("boxed_array"),
+ Token::BorrowedStr("ABCDEFGHIJKLMNOPQRSTUVWXZYabcdefghijklmnopqrstuvwxyz"),
+ Token::Str("boxed_array2"),
+ Token::BorrowedStr("ABCDEFGHIJKLMNOPQRSTUVWXZYabcdefghijklmnopqrstuvwxyz"),
+ Token::Str("boxed_slice"),
+ Token::Bytes(b"..."),
+ Token::Str("opt_slice"),
+ Token::Some,
+ Token::BorrowedStr("..."),
+ Token::Str("opt_vec"),
+ Token::Some,
+ Token::Bytes(b"..."),
+ Token::Str("opt_cow_slice"),
+ Token::Some,
+ Token::BorrowedStr("..."),
+ Token::StructEnd,
+ ],
+ );
+}
+
+#[test]
+fn test_one_or_many_prefer_one() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S1Vec(#[serde_as(as = "OneOrMany<_>")] Vec<u32>);
+
+ // Normal
+ is_equal(S1Vec(vec![]), expect![[r#"[]"#]]);
+ is_equal(S1Vec(vec![1]), expect![[r#"1"#]]);
+ is_equal(
+ S1Vec(vec![1, 2, 3]),
+ expect![[r#"
+ [
+ 1,
+ 2,
+ 3
+ ]"#]],
+ );
+ check_deserialization(S1Vec(vec![1]), r#"1"#);
+ check_deserialization(S1Vec(vec![1]), r#"[1]"#);
+ check_error_deserialization::<S1Vec>(
+ r#"{}"#,
+ expect![[r#"
+ OneOrMany could not deserialize any variant:
+ One: invalid type: map, expected u32
+ Many: invalid type: map, expected a sequence"#]],
+ );
+ check_error_deserialization::<S1Vec>(
+ r#""xx""#,
+ expect![[r#"
+ OneOrMany could not deserialize any variant:
+ One: invalid type: string "xx", expected u32
+ Many: invalid type: string "xx", expected a sequence"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S2Vec(#[serde_as(as = "OneOrMany<DisplayFromStr>")] Vec<u32>);
+
+ // Normal
+ is_equal(S2Vec(vec![]), expect![[r#"[]"#]]);
+ is_equal(S2Vec(vec![1]), expect![[r#""1""#]]);
+ is_equal(
+ S2Vec(vec![1, 2, 3]),
+ expect![[r#"
+ [
+ "1",
+ "2",
+ "3"
+ ]"#]],
+ );
+ check_deserialization(S2Vec(vec![1]), r#""1""#);
+ check_deserialization(S2Vec(vec![1]), r#"["1"]"#);
+ check_error_deserialization::<S2Vec>(
+ r#"{}"#,
+ expect![[r#"
+ OneOrMany could not deserialize any variant:
+ One: invalid type: map, expected a string
+ Many: invalid type: map, expected a sequence"#]],
+ );
+ check_error_deserialization::<S2Vec>(
+ r#""xx""#,
+ expect![[r#"
+ OneOrMany could not deserialize any variant:
+ One: invalid digit found in string
+ Many: invalid type: string "xx", expected a sequence"#]],
+ );
+}
+
+#[test]
+fn test_one_or_many_prefer_many() {
+ use serde_with::formats::PreferMany;
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S1Vec(#[serde_as(as = "OneOrMany<_, PreferMany>")] Vec<u32>);
+
+ // Normal
+ is_equal(S1Vec(vec![]), expect![[r#"[]"#]]);
+ is_equal(
+ S1Vec(vec![1]),
+ expect![[r#"
+ [
+ 1
+ ]"#]],
+ );
+ is_equal(
+ S1Vec(vec![1, 2, 3]),
+ expect![[r#"
+ [
+ 1,
+ 2,
+ 3
+ ]"#]],
+ );
+ check_deserialization(S1Vec(vec![1]), r#"1"#);
+ check_deserialization(S1Vec(vec![1]), r#"[1]"#);
+ check_error_deserialization::<S1Vec>(
+ r#"{}"#,
+ expect![[r#"
+ OneOrMany could not deserialize any variant:
+ One: invalid type: map, expected u32
+ Many: invalid type: map, expected a sequence"#]],
+ );
+ check_error_deserialization::<S1Vec>(
+ r#""xx""#,
+ expect![[r#"
+ OneOrMany could not deserialize any variant:
+ One: invalid type: string "xx", expected u32
+ Many: invalid type: string "xx", expected a sequence"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S2Vec(#[serde_as(as = "OneOrMany<DisplayFromStr, PreferMany>")] Vec<u32>);
+
+ // Normal
+ is_equal(S2Vec(vec![]), expect![[r#"[]"#]]);
+ is_equal(
+ S2Vec(vec![1]),
+ expect![[r#"
+ [
+ "1"
+ ]"#]],
+ );
+ is_equal(
+ S2Vec(vec![1, 2, 3]),
+ expect![[r#"
+ [
+ "1",
+ "2",
+ "3"
+ ]"#]],
+ );
+ check_deserialization(S2Vec(vec![1]), r#""1""#);
+ check_deserialization(S2Vec(vec![1]), r#"["1"]"#);
+ check_error_deserialization::<S2Vec>(
+ r#"{}"#,
+ expect![[r#"
+ OneOrMany could not deserialize any variant:
+ One: invalid type: map, expected a string
+ Many: invalid type: map, expected a sequence"#]],
+ );
+ check_error_deserialization::<S2Vec>(
+ r#""xx""#,
+ expect![[r#"
+ OneOrMany could not deserialize any variant:
+ One: invalid digit found in string
+ Many: invalid type: string "xx", expected a sequence"#]],
+ );
+}
+
+/// Test that Cow borrows from the input
+#[test]
+fn test_borrow_cow_str() {
+ use alloc::borrow::Cow;
+ use serde_test::{assert_ser_tokens, Token};
+ use serde_with::BorrowCow;
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S1<'a> {
+ #[serde_as(as = "BorrowCow")]
+ cow: Cow<'a, str>,
+ #[serde_as(as = "Option<BorrowCow>")]
+ opt: Option<Cow<'a, str>>,
+ #[serde_as(as = "Box<BorrowCow>")]
+ b: Box<Cow<'a, str>>,
+ #[serde_as(as = "[BorrowCow; 1]")]
+ arr: [Cow<'a, str>; 1],
+ }
+
+ assert_ser_tokens(
+ &S1 {
+ cow: "abc".into(),
+ opt: Some("foo".into()),
+ b: Box::new("bar".into()),
+ arr: ["def".into()],
+ },
+ &[
+ Token::Struct { name: "S1", len: 4 },
+ Token::Str("cow"),
+ Token::BorrowedStr("abc"),
+ Token::Str("opt"),
+ Token::Some,
+ Token::BorrowedStr("foo"),
+ Token::Str("b"),
+ Token::BorrowedStr("bar"),
+ Token::Str("arr"),
+ Token::Tuple { len: 1 },
+ Token::BorrowedStr("def"),
+ Token::TupleEnd,
+ Token::StructEnd,
+ ],
+ );
+ let s1: S1<'_> = serde_json::from_str(
+ r#"{
+ "cow": "abc",
+ "opt": "foo",
+ "b": "bar",
+ "arr": ["def"]
+ }"#,
+ )
+ .unwrap();
+ assert!(matches!(s1.cow, Cow::Borrowed(_)));
+ assert!(matches!(s1.opt, Some(Cow::Borrowed(_))));
+ assert!(matches!(*s1.b, Cow::Borrowed(_)));
+ assert!(matches!(s1.arr, [Cow::Borrowed(_)]));
+ let s1: S1<'_> = serde_json::from_str(
+ r#"{
+ "cow": "a\"c",
+ "opt": "f\"o",
+ "b": "b\"r",
+ "arr": ["d\"f"]
+ }"#,
+ )
+ .unwrap();
+ assert!(matches!(s1.cow, Cow::Owned(_)));
+ assert!(matches!(s1.opt, Some(Cow::Owned(_))));
+ assert!(matches!(*s1.b, Cow::Owned(_)));
+ assert!(matches!(s1.arr, [Cow::Owned(_)]));
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S2<'a> {
+ #[serde_as(as = "BorrowCow")]
+ cow: Cow<'a, [u8]>,
+ #[serde_as(as = "Option<BorrowCow>")]
+ opt: Option<Cow<'a, [u8]>>,
+ }
+
+ assert_ser_tokens(
+ &S2 {
+ cow: b"abc"[..].into(),
+ opt: Some(b"foo"[..].into()),
+ },
+ &[
+ Token::Struct { name: "S2", len: 2 },
+ Token::Str("cow"),
+ Token::Seq { len: Some(3) },
+ Token::U8(b'a'),
+ Token::U8(b'b'),
+ Token::U8(b'c'),
+ Token::SeqEnd,
+ Token::Str("opt"),
+ Token::Some,
+ Token::Seq { len: Some(3) },
+ Token::U8(b'f'),
+ Token::U8(b'o'),
+ Token::U8(b'o'),
+ Token::SeqEnd,
+ Token::StructEnd,
+ ],
+ );
+ let tokens = &[
+ Token::Struct { name: "S2", len: 2 },
+ Token::Str("cow"),
+ Token::BorrowedBytes(b"abc"),
+ Token::Str("opt"),
+ Token::Some,
+ Token::BorrowedBytes(b"foo"),
+ Token::StructEnd,
+ ];
+ let mut deser = serde_test::Deserializer::new(tokens);
+ let s2 = S2::deserialize(&mut deser).unwrap();
+ assert!(matches!(s2.cow, Cow::Borrowed(_)));
+ assert!(matches!(s2.opt, Some(Cow::Borrowed(_))));
+
+ // Check that a manual borrow works too
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S3<'a>(
+ #[serde(borrow = "'a")]
+ #[serde_as(as = "BorrowCow")]
+ Cow<'a, [u8]>,
+ // TODO add a test for Cow<'b, [u8; N]>
+ // #[serde_as(as = "BorrowCow")]
+ // Cow<'b, [u8; N]>,
+ );
+ let tokens = &[
+ Token::NewtypeStruct { name: "S3" },
+ Token::BorrowedBytes(b"abc"),
+ ];
+
+ let mut deser = serde_test::Deserializer::new(tokens);
+ let s3 = S3::deserialize(&mut deser).unwrap();
+ assert!(matches!(s3.0, Cow::Borrowed(_)));
+}
+
+#[test]
+fn test_boolfromint() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S(#[serde_as(as = "BoolFromInt")] bool);
+
+ is_equal(S(false), expect![[r#"0"#]]);
+ is_equal(S(true), expect![[r#"1"#]]);
+ check_error_deserialization::<S>(
+ "2",
+ expect![[r#"invalid value: integer `2`, expected 0 or 1 at line 1 column 1"#]],
+ );
+ check_error_deserialization::<S>(
+ "-100",
+ expect![[r#"invalid value: integer `-100`, expected 0 or 1 at line 1 column 4"#]],
+ );
+ check_error_deserialization::<S>(
+ "18446744073709551615",
+ expect![[
+ r#"invalid value: integer `18446744073709551615`, expected 0 or 1 at line 1 column 20"#
+ ]],
+ );
+ check_error_deserialization::<S>(
+ r#""""#,
+ expect![[r#"invalid type: string "", expected an integer 0 or 1 at line 1 column 2"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct SStrict(#[serde_as(as = "BoolFromInt<Strict>")] bool);
+
+ is_equal(SStrict(false), expect![[r#"0"#]]);
+ is_equal(SStrict(true), expect![[r#"1"#]]);
+ check_error_deserialization::<SStrict>(
+ "2",
+ expect![[r#"invalid value: integer `2`, expected 0 or 1 at line 1 column 1"#]],
+ );
+ check_error_deserialization::<SStrict>(
+ "-100",
+ expect![[r#"invalid value: integer `-100`, expected 0 or 1 at line 1 column 4"#]],
+ );
+ check_error_deserialization::<SStrict>(
+ "18446744073709551615",
+ expect![[
+ r#"invalid value: integer `18446744073709551615`, expected 0 or 1 at line 1 column 20"#
+ ]],
+ );
+ check_error_deserialization::<SStrict>(
+ r#""""#,
+ expect![[r#"invalid type: string "", expected an integer 0 or 1 at line 1 column 2"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct SFlexible(#[serde_as(as = "BoolFromInt<Flexible>")] bool);
+
+ is_equal(SFlexible(false), expect![[r#"0"#]]);
+ is_equal(SFlexible(true), expect![[r#"1"#]]);
+ check_deserialization::<SFlexible>(SFlexible(true), "2");
+ check_deserialization::<SFlexible>(SFlexible(true), "-100");
+ check_deserialization::<SFlexible>(SFlexible(true), "18446744073709551615");
+ check_error_deserialization::<SFlexible>(
+ r#""""#,
+ expect![[r#"invalid type: string "", expected an integer at line 1 column 2"#]],
+ );
+}
diff --git a/third_party/rust/serde_with/tests/serde_as/map_tuple_list.rs b/third_party/rust/serde_with/tests/serde_as/map_tuple_list.rs
new file mode 100644
index 0000000000..59b00d614e
--- /dev/null
+++ b/third_party/rust/serde_with/tests/serde_as/map_tuple_list.rs
@@ -0,0 +1,687 @@
+use super::*;
+use std::net::IpAddr;
+
+#[test]
+fn test_map_as_tuple_list() {
+ let ip = "1.2.3.4".parse().unwrap();
+ let ip2 = "255.255.255.255".parse().unwrap();
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct SM(#[serde_as(as = "Seq<(DisplayFromStr, DisplayFromStr)>")] BTreeMap<u32, IpAddr>);
+
+ let map: BTreeMap<_, _> = vec![(1, ip), (10, ip), (200, ip2)].into_iter().collect();
+ is_equal(
+ SM(map),
+ expect![[r#"
+ [
+ [
+ "1",
+ "1.2.3.4"
+ ],
+ [
+ "10",
+ "1.2.3.4"
+ ],
+ [
+ "200",
+ "255.255.255.255"
+ ]
+ ]"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct SB(#[serde_as(as = "Vec<(DisplayFromStr, DisplayFromStr)>")] BTreeMap<u32, IpAddr>);
+
+ let map: BTreeMap<_, _> = vec![(1, ip), (10, ip), (200, ip2)].into_iter().collect();
+ is_equal(
+ SB(map.clone()),
+ expect![[r#"
+ [
+ [
+ "1",
+ "1.2.3.4"
+ ],
+ [
+ "10",
+ "1.2.3.4"
+ ],
+ [
+ "200",
+ "255.255.255.255"
+ ]
+ ]"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct SB2(#[serde_as(as = "Vec<(Same, DisplayFromStr)>")] BTreeMap<u32, IpAddr>);
+
+ is_equal(
+ SB2(map),
+ expect![[r#"
+ [
+ [
+ 1,
+ "1.2.3.4"
+ ],
+ [
+ 10,
+ "1.2.3.4"
+ ],
+ [
+ 200,
+ "255.255.255.255"
+ ]
+ ]"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct SH(#[serde_as(as = "Vec<(DisplayFromStr, DisplayFromStr)>")] HashMap<u32, IpAddr>);
+
+ // HashMap serialization tests with more than 1 entry are unreliable
+ let map1: HashMap<_, _> = vec![(200, ip2)].into_iter().collect();
+ let map: HashMap<_, _> = vec![(1, ip), (10, ip), (200, ip2)].into_iter().collect();
+ is_equal(
+ SH(map1.clone()),
+ expect![[r#"
+ [
+ [
+ "200",
+ "255.255.255.255"
+ ]
+ ]"#]],
+ );
+ check_deserialization(
+ SH(map.clone()),
+ r#"[["1","1.2.3.4"],["10","1.2.3.4"],["200","255.255.255.255"]]"#,
+ );
+ check_error_deserialization::<SH>(
+ r#"{"200":"255.255.255.255"}"#,
+ expect![[r#"invalid type: map, expected a sequence at line 1 column 0"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct SH2(#[serde_as(as = "Vec<(Same, DisplayFromStr)>")] HashMap<u32, IpAddr>);
+
+ is_equal(
+ SH2(map1),
+ expect![[r#"
+ [
+ [
+ 200,
+ "255.255.255.255"
+ ]
+ ]"#]],
+ );
+ check_deserialization(
+ SH2(map),
+ r#"[[1,"1.2.3.4"],[10,"1.2.3.4"],[200,"255.255.255.255"]]"#,
+ );
+ check_error_deserialization::<SH2>(
+ r#"1"#,
+ expect![[r#"invalid type: integer `1`, expected a sequence at line 1 column 1"#]],
+ );
+}
+
+#[test]
+fn test_tuple_list_as_map() {
+ let ip = "1.2.3.4".parse().unwrap();
+ let ip2 = "255.255.255.255".parse().unwrap();
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct SM(#[serde_as(as = "Map<DisplayFromStr, DisplayFromStr>")] Vec<(u32, IpAddr)>);
+
+ is_equal(
+ SM(vec![(1, ip), (10, ip), (200, ip2)]),
+ expect![[r#"
+ {
+ "1": "1.2.3.4",
+ "10": "1.2.3.4",
+ "200": "255.255.255.255"
+ }"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct SH(#[serde_as(as = "HashMap<DisplayFromStr, DisplayFromStr>")] Vec<(u32, IpAddr)>);
+
+ is_equal(
+ SH(vec![(1, ip), (10, ip), (200, ip2)]),
+ expect![[r#"
+ {
+ "1": "1.2.3.4",
+ "10": "1.2.3.4",
+ "200": "255.255.255.255"
+ }"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct SB(#[serde_as(as = "BTreeMap<DisplayFromStr, DisplayFromStr>")] Vec<(u32, IpAddr)>);
+
+ is_equal(
+ SB(vec![(1, ip), (10, ip), (200, ip2)]),
+ expect![[r#"
+ {
+ "1": "1.2.3.4",
+ "10": "1.2.3.4",
+ "200": "255.255.255.255"
+ }"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct SD(#[serde_as(as = "BTreeMap<DisplayFromStr, DisplayFromStr>")] VecDeque<(u32, IpAddr)>);
+
+ is_equal(
+ SD(vec![(1, ip), (10, ip), (200, ip2)].into()),
+ expect![[r#"
+ {
+ "1": "1.2.3.4",
+ "10": "1.2.3.4",
+ "200": "255.255.255.255"
+ }"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct Sll(
+ #[serde_as(as = "HashMap<DisplayFromStr, DisplayFromStr>")] LinkedList<(u32, IpAddr)>,
+ );
+
+ is_equal(
+ Sll(vec![(1, ip), (10, ip), (200, ip2)].into_iter().collect()),
+ expect![[r#"
+ {
+ "1": "1.2.3.4",
+ "10": "1.2.3.4",
+ "200": "255.255.255.255"
+ }"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct SO(#[serde_as(as = "HashMap<DisplayFromStr, DisplayFromStr>")] Option<(u32, IpAddr)>);
+
+ is_equal(
+ SO(Some((1, ip))),
+ expect![[r#"
+ {
+ "1": "1.2.3.4"
+ }"#]],
+ );
+ is_equal(SO(None), expect![[r#"{}"#]]);
+}
+
+#[test]
+fn test_tuple_array_as_map() {
+ #[serde_as]
+ #[derive(Debug, PartialEq, Serialize, Deserialize)]
+ struct S0(#[serde_as(as = "Map<_, _>")] [(u8, u8); 1]);
+ is_equal(
+ S1([(1, 2)]),
+ expect![[r#"
+ {
+ "1": 2
+ }"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, PartialEq, Serialize, Deserialize)]
+ struct S1(#[serde_as(as = "BTreeMap<_, _>")] [(u8, u8); 1]);
+ is_equal(
+ S1([(1, 2)]),
+ expect![[r#"
+ {
+ "1": 2
+ }"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, PartialEq, Serialize, Deserialize)]
+ struct S2(#[serde_as(as = "HashMap<_, _>")] [(u8, u8); 33]);
+ is_equal(
+ S2([
+ (0, 0),
+ (1, 1),
+ (2, 2),
+ (3, 3),
+ (4, 4),
+ (5, 5),
+ (6, 6),
+ (7, 7),
+ (8, 8),
+ (9, 9),
+ (10, 10),
+ (11, 11),
+ (12, 12),
+ (13, 13),
+ (14, 14),
+ (15, 15),
+ (16, 16),
+ (17, 17),
+ (18, 18),
+ (19, 19),
+ (20, 20),
+ (21, 21),
+ (22, 22),
+ (23, 23),
+ (24, 24),
+ (25, 25),
+ (26, 26),
+ (27, 27),
+ (28, 28),
+ (29, 29),
+ (30, 30),
+ (31, 31),
+ (32, 32),
+ ]),
+ expect![[r#"
+ {
+ "0": 0,
+ "1": 1,
+ "2": 2,
+ "3": 3,
+ "4": 4,
+ "5": 5,
+ "6": 6,
+ "7": 7,
+ "8": 8,
+ "9": 9,
+ "10": 10,
+ "11": 11,
+ "12": 12,
+ "13": 13,
+ "14": 14,
+ "15": 15,
+ "16": 16,
+ "17": 17,
+ "18": 18,
+ "19": 19,
+ "20": 20,
+ "21": 21,
+ "22": 22,
+ "23": 23,
+ "24": 24,
+ "25": 25,
+ "26": 26,
+ "27": 27,
+ "28": 28,
+ "29": 29,
+ "30": 30,
+ "31": 31,
+ "32": 32
+ }"#]],
+ );
+}
+
+// Test that the `Seq` conversion works when the inner type is explicity specified.
+#[test]
+fn test_map_as_tuple_with_nested_complex_type() {
+ #[serde_as]
+ #[derive(Debug, PartialEq, Serialize, Deserialize)]
+ struct S0(#[serde_as(as = "Seq<(_, Vec<_>)>")] BTreeMap<usize, Vec<usize>>);
+
+ let value = S0(BTreeMap::from([
+ (1, Vec::from([1, 2])),
+ (2, Vec::from([3, 4])),
+ ]));
+ is_equal(
+ value,
+ expect![[r#"
+ [
+ [
+ 1,
+ [
+ 1,
+ 2
+ ]
+ ],
+ [
+ 2,
+ [
+ 3,
+ 4
+ ]
+ ]
+ ]"#]],
+ );
+}
+
+#[test]
+fn test_map_as_tuple_list_works_with_serializer_that_needs_length_to_serialize_sequence() {
+ use serde::{
+ ser::{
+ SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple,
+ SerializeTupleStruct, SerializeTupleVariant,
+ },
+ Serializer,
+ };
+ use std::fmt::{self, Debug, Display};
+
+ #[derive(Debug)]
+ enum TestError {
+ LengthRequired,
+ Other,
+ }
+
+ impl Display for TestError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ Debug::fmt(self, f)
+ }
+ }
+
+ impl std::error::Error for TestError {}
+
+ impl serde::ser::Error for TestError {
+ fn custom<T>(_: T) -> Self
+ where
+ T: Display,
+ {
+ TestError::Other
+ }
+ }
+
+ struct TestSerializer;
+
+ impl<'a> Serializer for &'a mut TestSerializer {
+ type Ok = ();
+ type Error = TestError;
+ type SerializeSeq = Self;
+ type SerializeTuple = Self;
+ type SerializeTupleStruct = Self;
+ type SerializeTupleVariant = Self;
+ type SerializeMap = Self;
+ type SerializeStruct = Self;
+ type SerializeStructVariant = Self;
+
+ fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> {
+ Ok(())
+ }
+
+ fn serialize_i8(self, _: i8) -> Result<Self::Ok, Self::Error> {
+ Ok(())
+ }
+
+ fn serialize_i16(self, _: i16) -> Result<Self::Ok, Self::Error> {
+ Ok(())
+ }
+
+ fn serialize_i32(self, _: i32) -> Result<Self::Ok, Self::Error> {
+ Ok(())
+ }
+
+ fn serialize_i64(self, _: i64) -> Result<Self::Ok, Self::Error> {
+ Ok(())
+ }
+
+ fn serialize_u8(self, _: u8) -> Result<Self::Ok, Self::Error> {
+ Ok(())
+ }
+
+ fn serialize_u16(self, _: u16) -> Result<Self::Ok, Self::Error> {
+ Ok(())
+ }
+
+ fn serialize_u32(self, _: u32) -> Result<Self::Ok, Self::Error> {
+ Ok(())
+ }
+
+ fn serialize_u64(self, _: u64) -> Result<Self::Ok, Self::Error> {
+ Ok(())
+ }
+
+ fn serialize_f32(self, _: f32) -> Result<Self::Ok, Self::Error> {
+ Ok(())
+ }
+
+ fn serialize_f64(self, _: f64) -> Result<Self::Ok, Self::Error> {
+ Ok(())
+ }
+
+ fn serialize_char(self, _: char) -> Result<Self::Ok, Self::Error> {
+ Ok(())
+ }
+
+ fn serialize_str(self, _: &str) -> Result<Self::Ok, Self::Error> {
+ Ok(())
+ }
+
+ fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, Self::Error> {
+ Ok(())
+ }
+
+ fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
+ Ok(())
+ }
+
+ fn serialize_some<T>(self, v: &T) -> Result<Self::Ok, Self::Error>
+ where
+ T: Serialize + ?Sized,
+ {
+ v.serialize(self)
+ }
+
+ fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
+ Ok(())
+ }
+
+ fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
+ Ok(())
+ }
+
+ fn serialize_unit_variant(
+ self,
+ _: &'static str,
+ _: u32,
+ _: &'static str,
+ ) -> Result<Self::Ok, Self::Error> {
+ Ok(())
+ }
+
+ fn serialize_newtype_struct<T>(
+ self,
+ _: &'static str,
+ value: &T,
+ ) -> Result<Self::Ok, Self::Error>
+ where
+ T: Serialize + ?Sized,
+ {
+ value.serialize(self)
+ }
+
+ fn serialize_newtype_variant<T>(
+ self,
+ _: &'static str,
+ _: u32,
+ _: &'static str,
+ value: &T,
+ ) -> Result<Self::Ok, Self::Error>
+ where
+ T: Serialize + ?Sized,
+ {
+ value.serialize(self)
+ }
+
+ fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
+ len.map(|_| self).ok_or(TestError::LengthRequired)
+ }
+
+ fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, Self::Error> {
+ Ok(self)
+ }
+
+ fn serialize_tuple_struct(
+ self,
+ _: &'static str,
+ _: usize,
+ ) -> Result<Self::SerializeTupleStruct, Self::Error> {
+ Ok(self)
+ }
+
+ fn serialize_tuple_variant(
+ self,
+ _: &'static str,
+ _: u32,
+ _: &'static str,
+ _: usize,
+ ) -> Result<Self::SerializeTupleVariant, Self::Error> {
+ Ok(self)
+ }
+
+ fn serialize_map(self, _: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
+ Ok(self)
+ }
+
+ fn serialize_struct(
+ self,
+ _: &'static str,
+ _: usize,
+ ) -> Result<Self::SerializeStruct, Self::Error> {
+ Ok(self)
+ }
+
+ fn serialize_struct_variant(
+ self,
+ _: &'static str,
+ _: u32,
+ _: &'static str,
+ _: usize,
+ ) -> Result<Self::SerializeStructVariant, Self::Error> {
+ Ok(self)
+ }
+ }
+
+ impl<'a> SerializeMap for &'a mut TestSerializer {
+ type Ok = ();
+ type Error = TestError;
+
+ fn serialize_key<T>(&mut self, key: &T) -> Result<(), Self::Error>
+ where
+ T: Serialize + ?Sized,
+ {
+ key.serialize(&mut **self)
+ }
+
+ fn serialize_value<T>(&mut self, value: &T) -> Result<(), Self::Error>
+ where
+ T: Serialize + ?Sized,
+ {
+ value.serialize(&mut **self)
+ }
+
+ fn end(self) -> Result<Self::Ok, Self::Error> {
+ Ok(())
+ }
+ }
+
+ impl<'a> SerializeSeq for &'a mut TestSerializer {
+ type Ok = ();
+ type Error = TestError;
+
+ fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
+ where
+ T: Serialize + ?Sized,
+ {
+ value.serialize(&mut **self)
+ }
+
+ fn end(self) -> Result<Self::Ok, Self::Error> {
+ Ok(())
+ }
+ }
+
+ impl<'a> SerializeStruct for &'a mut TestSerializer {
+ type Ok = ();
+ type Error = TestError;
+
+ fn serialize_field<T>(&mut self, _: &'static str, value: &T) -> Result<(), Self::Error>
+ where
+ T: Serialize + ?Sized,
+ {
+ value.serialize(&mut **self)
+ }
+
+ fn end(self) -> Result<Self::Ok, Self::Error> {
+ Ok(())
+ }
+ }
+
+ impl<'a> SerializeStructVariant for &'a mut TestSerializer {
+ type Ok = ();
+ type Error = TestError;
+
+ fn serialize_field<T>(&mut self, _: &'static str, value: &T) -> Result<(), Self::Error>
+ where
+ T: Serialize + ?Sized,
+ {
+ value.serialize(&mut **self)
+ }
+
+ fn end(self) -> Result<Self::Ok, Self::Error> {
+ Ok(())
+ }
+ }
+
+ impl<'a> SerializeTuple for &'a mut TestSerializer {
+ type Ok = ();
+ type Error = TestError;
+
+ fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
+ where
+ T: Serialize + ?Sized,
+ {
+ value.serialize(&mut **self)
+ }
+
+ fn end(self) -> Result<Self::Ok, Self::Error> {
+ Ok(())
+ }
+ }
+
+ impl<'a> SerializeTupleStruct for &'a mut TestSerializer {
+ type Ok = ();
+ type Error = TestError;
+
+ fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
+ where
+ T: Serialize + ?Sized,
+ {
+ value.serialize(&mut **self)
+ }
+
+ fn end(self) -> Result<Self::Ok, Self::Error> {
+ Ok(())
+ }
+ }
+
+ impl<'a> SerializeTupleVariant for &'a mut TestSerializer {
+ type Ok = ();
+ type Error = TestError;
+
+ fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
+ where
+ T: Serialize + ?Sized,
+ {
+ value.serialize(&mut **self)
+ }
+
+ fn end(self) -> Result<Self::Ok, Self::Error> {
+ Ok(())
+ }
+ }
+
+ #[serde_as]
+ #[derive(Debug, Default, Serialize)]
+ struct Data {
+ #[serde_as(as = "Seq<(_, _)>")]
+ xs: HashMap<i32, i32>,
+ }
+
+ Data::default().serialize(&mut TestSerializer).unwrap();
+}
diff --git a/third_party/rust/serde_with/tests/serde_as/pickfirst.rs b/third_party/rust/serde_with/tests/serde_as/pickfirst.rs
new file mode 100644
index 0000000000..8c221df86b
--- /dev/null
+++ b/third_party/rust/serde_with/tests/serde_as/pickfirst.rs
@@ -0,0 +1,149 @@
+use super::*;
+use serde_with::{
+ formats::{CommaSeparator, SpaceSeparator},
+ PickFirst, StringWithSeparator,
+};
+
+#[test]
+fn test_pick_first_two() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S(#[serde_as(as = "PickFirst<(_, DisplayFromStr)>")] u32);
+
+ is_equal(S(123), expect![[r#"123"#]]);
+ check_deserialization(S(123), r#""123""#);
+ check_error_deserialization::<S>(
+ r#""Abc""#,
+ expect![[r#"
+ PickFirst could not deserialize any variant:
+ First: invalid type: string "Abc", expected u32
+ Second: invalid digit found in string"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S2(#[serde_as(as = "PickFirst<(DisplayFromStr, _)>")] u32);
+
+ is_equal(S2(123), expect![[r#""123""#]]);
+ check_deserialization(S2(123), r#"123"#);
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S3(
+ #[serde_as(as = "PickFirst<(_, StringWithSeparator::<SpaceSeparator, String>,)>")]
+ Vec<String>,
+ );
+ is_equal(
+ S3(vec!["A".to_string(), "B".to_string(), "C".to_string()]),
+ expect![[r#"
+ [
+ "A",
+ "B",
+ "C"
+ ]"#]],
+ );
+ check_deserialization(
+ S3(vec!["A".to_string(), "B".to_string(), "C".to_string()]),
+ r#""A B C""#,
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S4(
+ #[serde_as(as = "PickFirst<(StringWithSeparator::<CommaSeparator, String>, _,)>")]
+ Vec<String>,
+ );
+ is_equal(
+ S4(vec!["A".to_string(), "B".to_string(), "C".to_string()]),
+ expect![[r#""A,B,C""#]],
+ );
+ check_deserialization(
+ S4(vec!["A".to_string(), "B".to_string(), "C".to_string()]),
+ r#"["A", "B", "C"]"#,
+ );
+}
+
+#[test]
+fn test_pick_first_three() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S(
+ #[serde_as(
+ as = "PickFirst<(_, Vec<DisplayFromStr>, StringWithSeparator::<CommaSeparator, u32>)>"
+ )]
+ Vec<u32>,
+ );
+ is_equal(
+ S(vec![1, 2, 3]),
+ expect![[r#"
+ [
+ 1,
+ 2,
+ 3
+ ]"#]],
+ );
+ check_deserialization(
+ S(vec![1, 2, 3]),
+ r#"
+ [
+ "1",
+ "2",
+ "3"
+ ]"#,
+ );
+ check_deserialization(S(vec![1, 2, 3]), r#""1,2,3""#);
+ check_error_deserialization::<S>(
+ r#""Abc""#,
+ expect![[r#"
+ PickFirst could not deserialize any variant:
+ First: invalid type: string "Abc", expected a sequence
+ Second: invalid type: string "Abc", expected a sequence
+ Third: invalid digit found in string"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S2(
+ #[serde_as(
+ as = "PickFirst<(StringWithSeparator::<CommaSeparator, u32>, _, Vec<DisplayFromStr>)>"
+ )]
+ Vec<u32>,
+ );
+ is_equal(S2(vec![1, 2, 3]), expect![[r#""1,2,3""#]]);
+ check_deserialization(
+ S2(vec![1, 2, 3]),
+ r#"
+ [
+ "1",
+ "2",
+ "3"
+ ]"#,
+ );
+ check_deserialization(
+ S2(vec![1, 2, 3]),
+ r#"
+ [
+ 1,
+ 2,
+ 3
+ ]"#,
+ );
+}
+
+#[test]
+fn test_pick_first_four() {
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S(#[serde_as(as = "PickFirst<(_, _, _, _)>")] u32);
+
+ is_equal(S(123), expect![[r#"123"#]]);
+ check_error_deserialization::<S>(
+ r#""Abc""#,
+ expect![[r#"
+ PickFirst could not deserialize any variant:
+ First: invalid type: string "Abc", expected u32
+ Second: invalid type: string "Abc", expected u32
+ Third: invalid type: string "Abc", expected u32
+ Fourth: invalid type: string "Abc", expected u32"#]],
+ );
+}
diff --git a/third_party/rust/serde_with/tests/serde_as/serde_as_macro.rs b/third_party/rust/serde_with/tests/serde_as/serde_as_macro.rs
new file mode 100644
index 0000000000..8ef8fcb6c5
--- /dev/null
+++ b/third_party/rust/serde_with/tests/serde_as/serde_as_macro.rs
@@ -0,0 +1,307 @@
+use super::*;
+
+/// Test that the [`serde_as`] macro can replace the `_` type and the resulting code compiles.
+#[test]
+fn test_serde_as_macro_replace_infer_type() {
+ #[serde_as]
+ #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
+ struct Data {
+ #[serde_as(as = "_")]
+ a: u32,
+ #[serde_as(as = "std::vec::Vec<_>")]
+ b: Vec<u32>,
+ #[serde_as(as = "Vec<(_, _)>")]
+ c: Vec<(u32, String)>,
+ #[serde_as(as = "[_; 2]")]
+ d: [u32; 2],
+ #[serde_as(as = "Box<[_]>")]
+ e: Box<[u32]>,
+ }
+
+ is_equal(
+ Data {
+ a: 10,
+ b: vec![20, 33],
+ c: vec![(40, "Hello".into()), (55, "World".into()), (60, "!".into())],
+ d: [70, 88],
+ e: vec![99, 100, 110].into_boxed_slice(),
+ },
+ expect![[r#"
+ {
+ "a": 10,
+ "b": [
+ 20,
+ 33
+ ],
+ "c": [
+ [
+ 40,
+ "Hello"
+ ],
+ [
+ 55,
+ "World"
+ ],
+ [
+ 60,
+ "!"
+ ]
+ ],
+ "d": [
+ 70,
+ 88
+ ],
+ "e": [
+ 99,
+ 100,
+ 110
+ ]
+ }"#]],
+ );
+}
+
+/// Test that the [`serde_as`] macro supports `deserialize_as`
+#[test]
+fn test_serde_as_macro_deserialize() {
+ #[serde_as]
+ #[derive(Debug, Eq, PartialEq, Deserialize)]
+ struct Data {
+ #[serde_as(deserialize_as = "DisplayFromStr")]
+ a: u32,
+ #[serde_as(deserialize_as = "Vec<DisplayFromStr>")]
+ b: Vec<u32>,
+ #[serde_as(deserialize_as = "(DisplayFromStr, _)")]
+ c: (u32, u32),
+ }
+
+ check_deserialization(
+ Data {
+ a: 10,
+ b: vec![20, 33],
+ c: (40, 55),
+ },
+ r##"{
+ "a": "10",
+ "b": [
+ "20",
+ "33"
+ ],
+ "c": [
+ "40",
+ 55
+ ]
+}"##,
+ );
+}
+
+/// Test that the [`serde_as`] macro supports `serialize_as`
+#[test]
+fn test_serde_as_macro_serialize() {
+ #[serde_as]
+ #[derive(Debug, Eq, PartialEq, Serialize)]
+ struct Data {
+ #[serde_as(serialize_as = "DisplayFromStr")]
+ a: u32,
+ #[serde_as(serialize_as = "Vec<DisplayFromStr>")]
+ b: Vec<u32>,
+ #[serde_as(serialize_as = "(DisplayFromStr, _)")]
+ c: (u32, u32),
+ }
+
+ check_serialization(
+ Data {
+ a: 10,
+ b: vec![20, 33],
+ c: (40, 55),
+ },
+ expect![[r#"
+ {
+ "a": "10",
+ "b": [
+ "20",
+ "33"
+ ],
+ "c": [
+ "40",
+ 55
+ ]
+ }"#]],
+ );
+}
+
+/// Test that the [`serde_as`] macro supports `serialize_as` and `deserialize_as`
+#[test]
+fn test_serde_as_macro_serialize_deserialize() {
+ #[serde_as]
+ #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
+ struct Data {
+ #[serde_as(serialize_as = "DisplayFromStr", deserialize_as = "DisplayFromStr")]
+ a: u32,
+ #[serde_as(
+ serialize_as = "Vec<DisplayFromStr>",
+ deserialize_as = "Vec<DisplayFromStr>"
+ )]
+ b: Vec<u32>,
+ #[serde_as(
+ serialize_as = "(DisplayFromStr, _)",
+ deserialize_as = "(DisplayFromStr, _)"
+ )]
+ c: (u32, u32),
+ }
+
+ is_equal(
+ Data {
+ a: 10,
+ b: vec![20, 33],
+ c: (40, 55),
+ },
+ expect![[r#"
+ {
+ "a": "10",
+ "b": [
+ "20",
+ "33"
+ ],
+ "c": [
+ "40",
+ 55
+ ]
+ }"#]],
+ );
+}
+
+/// Test that the [`serde_as`] macro works correctly if applied multiple times to a field
+#[test]
+fn test_serde_as_macro_multiple_field_attributes() {
+ #[serde_as]
+ #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
+ struct Data {
+ #[serde_as(serialize_as = "DisplayFromStr")]
+ #[serde_as(deserialize_as = "DisplayFromStr")]
+ a: u32,
+ }
+
+ is_equal(
+ Data { a: 10 },
+ expect![[r#"
+ {
+ "a": "10"
+ }"#]],
+ );
+}
+
+/// Ensure that `serde_as` applies `default` if both the field and the conversion are option.
+#[test]
+fn test_default_on_option() {
+ #[serde_as]
+ #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
+ struct Data {
+ #[serde_as(as = "Option<DisplayFromStr>")]
+ a: Option<u32>,
+ }
+
+ is_equal(
+ Data { a: None },
+ expect![[r#"
+ {
+ "a": null
+ }"#]],
+ );
+ is_equal(
+ Data { a: Some(123) },
+ expect![[r#"
+ {
+ "a": "123"
+ }"#]],
+ );
+ check_deserialization(Data { a: None }, "{}");
+
+ #[serde_as]
+ #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
+ struct DataNoDefault {
+ #[serde_as(as = "Option<DisplayFromStr>", no_default)]
+ a: Option<u32>,
+ }
+
+ is_equal(
+ DataNoDefault { a: None },
+ expect![[r#"
+ {
+ "a": null
+ }"#]],
+ );
+ is_equal(
+ DataNoDefault { a: Some(123) },
+ expect![[r#"
+ {
+ "a": "123"
+ }"#]],
+ );
+ check_error_deserialization::<DataNoDefault>(
+ "{}",
+ expect!["missing field `a` at line 1 column 2"],
+ );
+
+ fn default_555() -> Option<u32> {
+ Some(555)
+ }
+
+ #[serde_as]
+ #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
+ struct DataExplicitDefault {
+ #[serde_as(as = "Option<DisplayFromStr>")]
+ #[serde(default = "default_555")]
+ a: Option<u32>,
+ }
+
+ is_equal(
+ DataExplicitDefault { a: None },
+ expect![[r#"
+ {
+ "a": null
+ }"#]],
+ );
+ is_equal(
+ DataExplicitDefault { a: Some(123) },
+ expect![[r#"
+ {
+ "a": "123"
+ }"#]],
+ );
+ check_deserialization(DataExplicitDefault { a: Some(555) }, "{}");
+
+ #[serde_as]
+ #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
+ struct DataString {
+ #[serde_as(as = "NoneAsEmptyString")]
+ a: Option<String>,
+ }
+
+ is_equal(
+ DataString { a: None },
+ expect![[r#"
+ {
+ "a": ""
+ }"#]],
+ );
+ is_equal(
+ DataString {
+ a: Some("123".to_string()),
+ },
+ expect![[r#"
+ {
+ "a": "123"
+ }"#]],
+ );
+ check_deserialization(DataString { a: None }, r#"{"a": ""}"#);
+ check_deserialization(
+ DataString {
+ a: Some("555".to_string()),
+ },
+ r#"{"a": "555"}"#,
+ );
+ check_error_deserialization::<DataString>(
+ "{}",
+ expect!["missing field `a` at line 1 column 2"],
+ );
+}
diff --git a/third_party/rust/serde_with/tests/serde_as/serde_conv.rs b/third_party/rust/serde_with/tests/serde_as/serde_conv.rs
new file mode 100644
index 0000000000..1e510f72a3
--- /dev/null
+++ b/third_party/rust/serde_with/tests/serde_as/serde_conv.rs
@@ -0,0 +1,52 @@
+use super::*;
+use serde_with::serde_conv;
+
+#[test]
+fn test_bool_as_string() {
+ serde_conv!(BoolAsString, bool, |x: &bool| x.to_string(), |x: String| x
+ .parse());
+
+ #[derive(Debug, PartialEq, Serialize, Deserialize)]
+ struct SWith(#[serde(with = "BoolAsString")] bool);
+
+ is_equal(SWith(false), expect![[r#""false""#]]);
+ is_equal(SWith(true), expect![[r#""true""#]]);
+ check_error_deserialization::<SWith>(
+ "123",
+ expect![[r#"invalid type: integer `123`, expected a string at line 1 column 3"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, PartialEq, Serialize, Deserialize)]
+ struct SAs(#[serde_as(as = "BoolAsString")] bool);
+
+ is_equal(SAs(false), expect![[r#""false""#]]);
+ is_equal(SAs(true), expect![[r#""true""#]]);
+ check_error_deserialization::<SAs>(
+ "123",
+ expect![[r#"invalid type: integer `123`, expected a string at line 1 column 3"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, PartialEq, Serialize, Deserialize)]
+ struct SAsVec(#[serde_as(as = "Vec<BoolAsString>")] Vec<bool>);
+
+ is_equal(
+ SAsVec(vec![false]),
+ expect![[r#"
+ [
+ "false"
+ ]"#]],
+ );
+ is_equal(
+ SAsVec(vec![true]),
+ expect![[r#"
+ [
+ "true"
+ ]"#]],
+ );
+ check_error_deserialization::<SAsVec>(
+ "123",
+ expect![[r#"invalid type: integer `123`, expected a sequence at line 1 column 3"#]],
+ );
+}
diff --git a/third_party/rust/serde_with/tests/serde_as/time.rs b/third_party/rust/serde_with/tests/serde_as/time.rs
new file mode 100644
index 0000000000..91808b4d8c
--- /dev/null
+++ b/third_party/rust/serde_with/tests/serde_as/time.rs
@@ -0,0 +1,521 @@
+use super::*;
+use core::time::Duration;
+use serde_with::{
+ DurationMicroSeconds, DurationMicroSecondsWithFrac, DurationMilliSeconds,
+ DurationMilliSecondsWithFrac, DurationNanoSeconds, DurationNanoSecondsWithFrac,
+ DurationSeconds, DurationSecondsWithFrac, TimestampMicroSeconds, TimestampMicroSecondsWithFrac,
+ TimestampMilliSeconds, TimestampMilliSecondsWithFrac, TimestampNanoSeconds,
+ TimestampNanoSecondsWithFrac, TimestampSeconds, TimestampSecondsWithFrac,
+};
+use std::time::SystemTime;
+
+#[test]
+fn test_duration_seconds() {
+ let zero = Duration::new(0, 0);
+ let one_second = Duration::new(1, 0);
+ let half_second = Duration::new(0, 500_000_000);
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct IntStrict(#[serde_as(as = "DurationSeconds")] Duration);
+
+ is_equal(IntStrict(zero), expect![[r#"0"#]]);
+ is_equal(IntStrict(one_second), expect![[r#"1"#]]);
+ check_serialization(IntStrict(half_second), expect![[r#"1"#]]);
+ check_error_deserialization::<IntStrict>(
+ r#""1""#,
+ expect![[r#"invalid type: string "1", expected u64 at line 1 column 3"#]],
+ );
+ check_error_deserialization::<IntStrict>(
+ r#"-1"#,
+ expect![[r#"invalid value: integer `-1`, expected u64 at line 1 column 2"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct IntFlexible(#[serde_as(as = "DurationSeconds<u64, Flexible>")] Duration);
+
+ is_equal(IntFlexible(zero), expect![[r#"0"#]]);
+ is_equal(IntFlexible(one_second), expect![[r#"1"#]]);
+ check_serialization(IntFlexible(half_second), expect![[r#"1"#]]);
+ check_deserialization(IntFlexible(half_second), r#""0.5""#);
+ check_deserialization(IntFlexible(one_second), r#""1""#);
+ check_deserialization(IntFlexible(zero), r#""0""#);
+ check_error_deserialization::<IntFlexible>(
+ r#""a""#,
+ expect![[
+ r#"invalid value: string "a", expected an integer, a float, or a string containing a number at line 1 column 3"#
+ ]],
+ );
+ check_error_deserialization::<IntFlexible>(
+ r#"-1"#,
+ expect![[r#"std::time::Duration cannot be negative"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct F64Strict(#[serde_as(as = "DurationSeconds<f64>")] Duration);
+
+ is_equal(F64Strict(zero), expect![[r#"0.0"#]]);
+ is_equal(F64Strict(one_second), expect![[r#"1.0"#]]);
+ check_serialization(F64Strict(half_second), expect![[r#"1.0"#]]);
+ check_deserialization(F64Strict(one_second), r#"0.5"#);
+ check_error_deserialization::<F64Strict>(
+ r#""1""#,
+ expect![[r#"invalid type: string "1", expected f64 at line 1 column 3"#]],
+ );
+ check_error_deserialization::<F64Strict>(
+ r#"-1.0"#,
+ expect![[r#"std::time::Duration cannot be negative"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct F64Flexible(#[serde_as(as = "DurationSeconds<f64, Flexible>")] Duration);
+
+ is_equal(F64Flexible(zero), expect![[r#"0.0"#]]);
+ is_equal(F64Flexible(one_second), expect![[r#"1.0"#]]);
+ check_serialization(F64Flexible(half_second), expect![[r#"1.0"#]]);
+ check_deserialization(F64Flexible(half_second), r#""0.5""#);
+ check_deserialization(F64Flexible(one_second), r#""1""#);
+ check_deserialization(F64Flexible(zero), r#""0""#);
+ check_error_deserialization::<F64Flexible>(
+ r#""a""#,
+ expect![[
+ r#"invalid value: string "a", expected an integer, a float, or a string containing a number at line 1 column 3"#
+ ]],
+ );
+ check_error_deserialization::<F64Flexible>(
+ r#"-1"#,
+ expect![[r#"std::time::Duration cannot be negative"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct StringStrict(#[serde_as(as = "DurationSeconds<String>")] Duration);
+
+ is_equal(StringStrict(zero), expect![[r#""0""#]]);
+ is_equal(StringStrict(one_second), expect![[r#""1""#]]);
+ check_serialization(StringStrict(half_second), expect![[r#""1""#]]);
+ check_error_deserialization::<StringStrict>(
+ r#"1"#,
+ expect![[
+ r#"invalid type: integer `1`, expected a string containing a number at line 1 column 1"#
+ ]],
+ );
+ check_error_deserialization::<StringStrict>(
+ r#"-1"#,
+ expect![[
+ r#"invalid type: integer `-1`, expected a string containing a number at line 1 column 2"#
+ ]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct StringFlexible(#[serde_as(as = "DurationSeconds<String, Flexible>")] Duration);
+
+ is_equal(StringFlexible(zero), expect![[r#""0""#]]);
+ is_equal(StringFlexible(one_second), expect![[r#""1""#]]);
+ check_serialization(StringFlexible(half_second), expect![[r#""1""#]]);
+ check_deserialization(StringFlexible(half_second), r#""0.5""#);
+ check_deserialization(StringFlexible(one_second), r#""1""#);
+ check_deserialization(StringFlexible(zero), r#""0""#);
+ check_error_deserialization::<StringFlexible>(
+ r#""a""#,
+ expect![[
+ r#"invalid value: string "a", expected an integer, a float, or a string containing a number at line 1 column 3"#
+ ]],
+ );
+ check_error_deserialization::<StringFlexible>(
+ r#"-1"#,
+ expect![[r#"std::time::Duration cannot be negative"#]],
+ );
+}
+
+#[test]
+fn test_duration_seconds_with_frac() {
+ let zero = Duration::new(0, 0);
+ let one_second = Duration::new(1, 0);
+ let half_second = Duration::new(0, 500_000_000);
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct F64Strict(#[serde_as(as = "DurationSecondsWithFrac<f64>")] Duration);
+
+ is_equal(F64Strict(zero), expect![[r#"0.0"#]]);
+ is_equal(F64Strict(one_second), expect![[r#"1.0"#]]);
+ is_equal(F64Strict(half_second), expect![[r#"0.5"#]]);
+ check_error_deserialization::<F64Strict>(
+ r#""1""#,
+ expect![[r#"invalid type: string "1", expected f64 at line 1 column 3"#]],
+ );
+ check_error_deserialization::<F64Strict>(
+ r#"-1.0"#,
+ expect![[r#"std::time::Duration cannot be negative"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct F64Flexible(#[serde_as(as = "DurationSecondsWithFrac<f64, Flexible>")] Duration);
+
+ is_equal(F64Flexible(zero), expect![[r#"0.0"#]]);
+ is_equal(F64Flexible(one_second), expect![[r#"1.0"#]]);
+ is_equal(F64Flexible(half_second), expect![[r#"0.5"#]]);
+ check_deserialization(F64Flexible(one_second), r#""1""#);
+ check_deserialization(F64Flexible(zero), r#""0""#);
+ check_error_deserialization::<F64Flexible>(
+ r#""a""#,
+ expect![[
+ r#"invalid value: string "a", expected an integer, a float, or a string containing a number at line 1 column 3"#
+ ]],
+ );
+ check_error_deserialization::<F64Flexible>(
+ r#"-1"#,
+ expect![[r#"std::time::Duration cannot be negative"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct StringStrict(#[serde_as(as = "DurationSecondsWithFrac<String>")] Duration);
+
+ is_equal(StringStrict(zero), expect![[r#""0""#]]);
+ is_equal(StringStrict(one_second), expect![[r#""1""#]]);
+ is_equal(StringStrict(half_second), expect![[r#""0.5""#]]);
+ check_error_deserialization::<StringStrict>(
+ r#"1"#,
+ expect![[r#"invalid type: integer `1`, expected a string at line 1 column 1"#]],
+ );
+ check_error_deserialization::<StringStrict>(
+ r#"-1"#,
+ expect![[r#"invalid type: integer `-1`, expected a string at line 1 column 2"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct StringFlexible(#[serde_as(as = "DurationSecondsWithFrac<String, Flexible>")] Duration);
+
+ is_equal(StringFlexible(zero), expect![[r#""0""#]]);
+ is_equal(StringFlexible(one_second), expect![[r#""1""#]]);
+ is_equal(StringFlexible(half_second), expect![[r#""0.5""#]]);
+ check_deserialization(StringFlexible(zero), r#""0""#);
+ check_error_deserialization::<StringFlexible>(
+ r#""a""#,
+ expect![[
+ r#"invalid value: string "a", expected an integer, a float, or a string containing a number at line 1 column 3"#
+ ]],
+ );
+ check_error_deserialization::<StringFlexible>(
+ r#"-1"#,
+ expect![[r#"std::time::Duration cannot be negative"#]],
+ );
+}
+
+#[test]
+fn test_timestamp_seconds_systemtime() {
+ let zero = SystemTime::UNIX_EPOCH;
+ let one_second = SystemTime::UNIX_EPOCH
+ .checked_add(Duration::new(1, 0))
+ .unwrap();
+ let half_second = SystemTime::UNIX_EPOCH
+ .checked_add(Duration::new(0, 500_000_000))
+ .unwrap();
+ let minus_one_second = SystemTime::UNIX_EPOCH
+ .checked_sub(Duration::new(1, 0))
+ .unwrap();
+ let minus_half_second = SystemTime::UNIX_EPOCH
+ .checked_sub(Duration::new(0, 500_000_000))
+ .unwrap();
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct StructIntStrict(#[serde_as(as = "TimestampSeconds")] SystemTime);
+
+ is_equal(StructIntStrict(zero), expect![[r#"0"#]]);
+ is_equal(StructIntStrict(one_second), expect![[r#"1"#]]);
+ is_equal(StructIntStrict(minus_one_second), expect![[r#"-1"#]]);
+ check_serialization(StructIntStrict(half_second), expect![[r#"1"#]]);
+ check_serialization(StructIntStrict(minus_half_second), expect![[r#"-1"#]]);
+ check_error_deserialization::<StructIntStrict>(
+ r#""1""#,
+ expect![[r#"invalid type: string "1", expected i64 at line 1 column 3"#]],
+ );
+ check_error_deserialization::<StructIntStrict>(
+ r#"0.123"#,
+ expect![[r#"invalid type: floating point `0.123`, expected i64 at line 1 column 5"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct StructIntFlexible(#[serde_as(as = "TimestampSeconds<i64, Flexible>")] SystemTime);
+
+ is_equal(StructIntFlexible(zero), expect![[r#"0"#]]);
+ is_equal(StructIntFlexible(one_second), expect![[r#"1"#]]);
+ is_equal(StructIntFlexible(minus_one_second), expect![[r#"-1"#]]);
+ check_serialization(StructIntFlexible(half_second), expect![[r#"1"#]]);
+ check_serialization(StructIntFlexible(minus_half_second), expect![[r#"-1"#]]);
+ check_deserialization(StructIntFlexible(one_second), r#""1""#);
+ check_deserialization(StructIntFlexible(one_second), r#"1.0"#);
+ check_deserialization(StructIntFlexible(minus_half_second), r#""-0.5""#);
+ check_deserialization(StructIntFlexible(half_second), r#"0.5"#);
+ check_error_deserialization::<StructIntFlexible>(
+ r#""a""#,
+ expect![[
+ r#"invalid value: string "a", expected an integer, a float, or a string containing a number at line 1 column 3"#
+ ]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct Structf64Strict(#[serde_as(as = "TimestampSeconds<f64>")] SystemTime);
+
+ is_equal(Structf64Strict(zero), expect![[r#"0.0"#]]);
+ is_equal(Structf64Strict(one_second), expect![[r#"1.0"#]]);
+ is_equal(Structf64Strict(minus_one_second), expect![[r#"-1.0"#]]);
+ check_serialization(Structf64Strict(half_second), expect![[r#"1.0"#]]);
+ check_serialization(Structf64Strict(minus_half_second), expect![[r#"-1.0"#]]);
+ check_deserialization(Structf64Strict(one_second), r#"0.5"#);
+ check_error_deserialization::<Structf64Strict>(
+ r#""1""#,
+ expect![[r#"invalid type: string "1", expected f64 at line 1 column 3"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct Structf64Flexible(#[serde_as(as = "TimestampSeconds<f64, Flexible>")] SystemTime);
+
+ is_equal(Structf64Flexible(zero), expect![[r#"0.0"#]]);
+ is_equal(Structf64Flexible(one_second), expect![[r#"1.0"#]]);
+ is_equal(Structf64Flexible(minus_one_second), expect![[r#"-1.0"#]]);
+ check_serialization(Structf64Flexible(half_second), expect![[r#"1.0"#]]);
+ check_serialization(Structf64Flexible(minus_half_second), expect![[r#"-1.0"#]]);
+ check_deserialization(Structf64Flexible(one_second), r#""1""#);
+ check_deserialization(Structf64Flexible(one_second), r#"1.0"#);
+ check_deserialization(Structf64Flexible(minus_half_second), r#""-0.5""#);
+ check_deserialization(Structf64Flexible(half_second), r#"0.5"#);
+ check_error_deserialization::<Structf64Flexible>(
+ r#""a""#,
+ expect![[
+ r#"invalid value: string "a", expected an integer, a float, or a string containing a number at line 1 column 3"#
+ ]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct StructStringStrict(#[serde_as(as = "TimestampSeconds<String>")] SystemTime);
+
+ is_equal(StructStringStrict(zero), expect![[r#""0""#]]);
+ is_equal(StructStringStrict(one_second), expect![[r#""1""#]]);
+ is_equal(StructStringStrict(minus_one_second), expect![[r#""-1""#]]);
+ check_serialization(StructStringStrict(half_second), expect![[r#""1""#]]);
+ check_serialization(StructStringStrict(minus_half_second), expect![[r#""-1""#]]);
+ check_deserialization(StructStringStrict(one_second), r#""1""#);
+ check_error_deserialization::<StructStringStrict>(
+ r#""0.5""#,
+ expect![[r#"invalid digit found in string at line 1 column 5"#]],
+ );
+ check_error_deserialization::<StructStringStrict>(
+ r#""-0.5""#,
+ expect![[r#"invalid digit found in string at line 1 column 6"#]],
+ );
+ check_error_deserialization::<StructStringStrict>(
+ r#"1"#,
+ expect![[
+ r#"invalid type: integer `1`, expected a string containing a number at line 1 column 1"#
+ ]],
+ );
+ check_error_deserialization::<StructStringStrict>(
+ r#"0.0"#,
+ expect![[
+ r#"invalid type: floating point `0`, expected a string containing a number at line 1 column 3"#
+ ]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct StructStringFlexible(#[serde_as(as = "TimestampSeconds<String, Flexible>")] SystemTime);
+
+ is_equal(StructStringFlexible(zero), expect![[r#""0""#]]);
+ is_equal(StructStringFlexible(one_second), expect![[r#""1""#]]);
+ is_equal(StructStringFlexible(minus_one_second), expect![[r#""-1""#]]);
+ check_serialization(StructStringFlexible(half_second), expect![[r#""1""#]]);
+ check_serialization(
+ StructStringFlexible(minus_half_second),
+ expect![[r#""-1""#]],
+ );
+ check_deserialization(StructStringFlexible(one_second), r#"1"#);
+ check_deserialization(StructStringFlexible(one_second), r#"1.0"#);
+ check_deserialization(StructStringFlexible(minus_half_second), r#""-0.5""#);
+ check_deserialization(StructStringFlexible(half_second), r#"0.5"#);
+ check_error_deserialization::<StructStringFlexible>(
+ r#""a""#,
+ expect![[
+ r#"invalid value: string "a", expected an integer, a float, or a string containing a number at line 1 column 3"#
+ ]],
+ );
+}
+
+#[test]
+fn test_timestamp_seconds_with_frac_systemtime() {
+ let zero = SystemTime::UNIX_EPOCH;
+ let one_second = SystemTime::UNIX_EPOCH
+ .checked_add(Duration::new(1, 0))
+ .unwrap();
+ let half_second = SystemTime::UNIX_EPOCH
+ .checked_add(Duration::new(0, 500_000_000))
+ .unwrap();
+ let minus_one_second = SystemTime::UNIX_EPOCH
+ .checked_sub(Duration::new(1, 0))
+ .unwrap();
+ let minus_half_second = SystemTime::UNIX_EPOCH
+ .checked_sub(Duration::new(0, 500_000_000))
+ .unwrap();
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct Structf64Strict(#[serde_as(as = "TimestampSecondsWithFrac<f64>")] SystemTime);
+
+ is_equal(Structf64Strict(zero), expect![[r#"0.0"#]]);
+ is_equal(Structf64Strict(one_second), expect![[r#"1.0"#]]);
+ is_equal(Structf64Strict(minus_one_second), expect![[r#"-1.0"#]]);
+ is_equal(Structf64Strict(half_second), expect![[r#"0.5"#]]);
+ is_equal(Structf64Strict(minus_half_second), expect![[r#"-0.5"#]]);
+ check_error_deserialization::<Structf64Strict>(
+ r#""1""#,
+ expect![[r#"invalid type: string "1", expected f64 at line 1 column 3"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct Structf64Flexible(
+ #[serde_as(as = "TimestampSecondsWithFrac<f64, Flexible>")] SystemTime,
+ );
+
+ is_equal(Structf64Flexible(zero), expect![[r#"0.0"#]]);
+ is_equal(Structf64Flexible(one_second), expect![[r#"1.0"#]]);
+ is_equal(Structf64Flexible(minus_one_second), expect![[r#"-1.0"#]]);
+ is_equal(Structf64Flexible(half_second), expect![[r#"0.5"#]]);
+ is_equal(Structf64Flexible(minus_half_second), expect![[r#"-0.5"#]]);
+ check_deserialization(Structf64Flexible(one_second), r#""1""#);
+ check_deserialization(Structf64Flexible(one_second), r#"1.0"#);
+ check_deserialization(Structf64Flexible(minus_half_second), r#""-0.5""#);
+ check_deserialization(Structf64Flexible(half_second), r#"0.5"#);
+ check_error_deserialization::<Structf64Flexible>(
+ r#""a""#,
+ expect![[
+ r#"invalid value: string "a", expected an integer, a float, or a string containing a number at line 1 column 3"#
+ ]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct StructStringStrict(#[serde_as(as = "TimestampSecondsWithFrac<String>")] SystemTime);
+
+ is_equal(StructStringStrict(zero), expect![[r#""0""#]]);
+ is_equal(StructStringStrict(one_second), expect![[r#""1""#]]);
+ is_equal(StructStringStrict(minus_one_second), expect![[r#""-1""#]]);
+ is_equal(StructStringStrict(half_second), expect![[r#""0.5""#]]);
+ is_equal(
+ StructStringStrict(minus_half_second),
+ expect![[r#""-0.5""#]],
+ );
+ check_error_deserialization::<StructStringStrict>(
+ r#"1"#,
+ expect![[r#"invalid type: integer `1`, expected a string at line 1 column 1"#]],
+ );
+ check_error_deserialization::<StructStringStrict>(
+ r#"0.0"#,
+ expect![[r#"invalid type: floating point `0`, expected a string at line 1 column 3"#]],
+ );
+
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct StructStringFlexible(
+ #[serde_as(as = "TimestampSecondsWithFrac<String, Flexible>")] SystemTime,
+ );
+
+ is_equal(StructStringFlexible(zero), expect![[r#""0""#]]);
+ is_equal(StructStringFlexible(one_second), expect![[r#""1""#]]);
+ is_equal(StructStringFlexible(minus_one_second), expect![[r#""-1""#]]);
+ is_equal(StructStringFlexible(half_second), expect![[r#""0.5""#]]);
+ is_equal(
+ StructStringFlexible(minus_half_second),
+ expect![[r#""-0.5""#]],
+ );
+ check_deserialization(StructStringFlexible(one_second), r#"1"#);
+ check_deserialization(StructStringFlexible(one_second), r#"1.0"#);
+ check_deserialization(StructStringFlexible(half_second), r#"0.5"#);
+ check_error_deserialization::<StructStringFlexible>(
+ r#""a""#,
+ expect![[
+ r#"invalid value: string "a", expected an integer, a float, or a string containing a number at line 1 column 3"#
+ ]],
+ );
+}
+
+macro_rules! smoketest {
+ ($($valuety:ty, $adapter:literal, $value:ident, $expect:tt;)*) => {
+ $({
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S(#[serde_as(as = $adapter)] $valuety);
+ #[allow(unused_braces)]
+ is_equal(S($value), $expect);
+ })*
+ };
+}
+
+#[test]
+fn test_duration_smoketest() {
+ let one_second = Duration::new(1, 0);
+
+ smoketest! {
+ Duration, "DurationSeconds<u64>", one_second, {expect![[r#"1"#]]};
+ Duration, "DurationSeconds<f64>", one_second, {expect![[r#"1.0"#]]};
+ Duration, "DurationMilliSeconds<u64>", one_second, {expect![[r#"1000"#]]};
+ Duration, "DurationMilliSeconds<f64>", one_second, {expect![[r#"1000.0"#]]};
+ Duration, "DurationMicroSeconds<u64>", one_second, {expect![[r#"1000000"#]]};
+ Duration, "DurationMicroSeconds<f64>", one_second, {expect![[r#"1000000.0"#]]};
+ Duration, "DurationNanoSeconds<u64>", one_second, {expect![[r#"1000000000"#]]};
+ Duration, "DurationNanoSeconds<f64>", one_second, {expect![[r#"1000000000.0"#]]};
+ };
+
+ smoketest! {
+ Duration, "DurationSecondsWithFrac", one_second, {expect![[r#"1.0"#]]};
+ Duration, "DurationSecondsWithFrac<String>", one_second, {expect![[r#""1""#]]};
+ Duration, "DurationMilliSecondsWithFrac", one_second, {expect![[r#"1000.0"#]]};
+ Duration, "DurationMilliSecondsWithFrac<String>", one_second, {expect![[r#""1000""#]]};
+ Duration, "DurationMicroSecondsWithFrac", one_second, {expect![[r#"1000000.0"#]]};
+ Duration, "DurationMicroSecondsWithFrac<String>", one_second, {expect![[r#""1000000""#]]};
+ Duration, "DurationNanoSecondsWithFrac", one_second, {expect![[r#"1000000000.0"#]]};
+ Duration, "DurationNanoSecondsWithFrac<String>", one_second, {expect![[r#""1000000000""#]]};
+ };
+}
+
+#[test]
+fn test_timestamp_systemtime_smoketest() {
+ let one_second = SystemTime::UNIX_EPOCH
+ .checked_add(Duration::new(1, 0))
+ .unwrap();
+
+ smoketest! {
+ SystemTime, "TimestampSeconds<i64>", one_second, {expect![[r#"1"#]]};
+ SystemTime, "TimestampSeconds<f64>", one_second, {expect![[r#"1.0"#]]};
+ SystemTime, "TimestampMilliSeconds<i64>", one_second, {expect![[r#"1000"#]]};
+ SystemTime, "TimestampMilliSeconds<f64>", one_second, {expect![[r#"1000.0"#]]};
+ SystemTime, "TimestampMicroSeconds<i64>", one_second, {expect![[r#"1000000"#]]};
+ SystemTime, "TimestampMicroSeconds<f64>", one_second, {expect![[r#"1000000.0"#]]};
+ SystemTime, "TimestampNanoSeconds<i64>", one_second, {expect![[r#"1000000000"#]]};
+ SystemTime, "TimestampNanoSeconds<f64>", one_second, {expect![[r#"1000000000.0"#]]};
+ };
+
+ smoketest! {
+ SystemTime, "TimestampSecondsWithFrac", one_second, {expect![[r#"1.0"#]]};
+ SystemTime, "TimestampSecondsWithFrac<String>", one_second, {expect![[r#""1""#]]};
+ SystemTime, "TimestampMilliSecondsWithFrac", one_second, {expect![[r#"1000.0"#]]};
+ SystemTime, "TimestampMilliSecondsWithFrac<String>", one_second, {expect![[r#""1000""#]]};
+ SystemTime, "TimestampMicroSecondsWithFrac", one_second, {expect![[r#"1000000.0"#]]};
+ SystemTime, "TimestampMicroSecondsWithFrac<String>", one_second, {expect![[r#""1000000""#]]};
+ SystemTime, "TimestampNanoSecondsWithFrac", one_second, {expect![[r#"1000000000.0"#]]};
+ SystemTime, "TimestampNanoSecondsWithFrac<String>", one_second, {expect![[r#""1000000000""#]]};
+ };
+}
diff --git a/third_party/rust/serde_with/tests/time_0_3.rs b/third_party/rust/serde_with/tests/time_0_3.rs
new file mode 100644
index 0000000000..214ec39f8f
--- /dev/null
+++ b/third_party/rust/serde_with/tests/time_0_3.rs
@@ -0,0 +1,279 @@
+#![allow(
+ // clippy is broken and shows wrong warnings
+ // clippy on stable does not know yet about the lint name
+ unknown_lints,
+ // https://github.com/rust-lang/rust-clippy/issues/8867
+ clippy::derive_partial_eq_without_eq,
+)]
+
+mod utils;
+
+use crate::utils::{check_deserialization, check_error_deserialization, is_equal};
+use expect_test::expect;
+use serde::{Deserialize, Serialize};
+use serde_with::{
+ serde_as, DurationMicroSeconds, DurationMicroSecondsWithFrac, DurationMilliSeconds,
+ DurationMilliSecondsWithFrac, DurationNanoSeconds, DurationNanoSecondsWithFrac,
+ DurationSeconds, DurationSecondsWithFrac, TimestampMicroSeconds, TimestampMicroSecondsWithFrac,
+ TimestampMilliSeconds, TimestampMilliSecondsWithFrac, TimestampNanoSeconds,
+ TimestampNanoSecondsWithFrac, TimestampSeconds, TimestampSecondsWithFrac,
+};
+use time_0_3::{Duration, OffsetDateTime, PrimitiveDateTime, UtcOffset};
+
+/// Create a [`PrimitiveDateTime`] for the Unix Epoch
+fn unix_epoch_primitive() -> PrimitiveDateTime {
+ PrimitiveDateTime::new(
+ time_0_3::Date::from_ordinal_date(1970, 1).unwrap(),
+ time_0_3::Time::from_hms_nano(0, 0, 0, 0).unwrap(),
+ )
+}
+
+macro_rules! smoketest {
+ ($($valuety:ty, $adapter:literal, $value:expr, $expect:tt;)*) => {
+ $({
+ #[serde_as]
+ #[derive(Debug, Serialize, Deserialize, PartialEq)]
+ struct S(#[serde_as(as = $adapter)] $valuety);
+ #[allow(unused_braces)]
+ is_equal(S($value), $expect);
+ })*
+ };
+}
+
+#[test]
+fn test_duration_smoketest() {
+ let zero = Duration::seconds(0);
+ let one_second = Duration::seconds(1);
+
+ smoketest! {
+ Duration, "DurationSeconds<i64>", one_second, {expect![[r#"1"#]]};
+ Duration, "DurationSeconds<f64>", one_second, {expect![[r#"1.0"#]]};
+ Duration, "DurationMilliSeconds<i64>", one_second, {expect![[r#"1000"#]]};
+ Duration, "DurationMilliSeconds<f64>", one_second, {expect![[r#"1000.0"#]]};
+ Duration, "DurationMicroSeconds<i64>", one_second, {expect![[r#"1000000"#]]};
+ Duration, "DurationMicroSeconds<f64>", one_second, {expect![[r#"1000000.0"#]]};
+ Duration, "DurationNanoSeconds<i64>", one_second, {expect![[r#"1000000000"#]]};
+ Duration, "DurationNanoSeconds<f64>", one_second, {expect![[r#"1000000000.0"#]]};
+ };
+
+ smoketest! {
+ Duration, "DurationSecondsWithFrac", one_second, {expect![[r#"1.0"#]]};
+ Duration, "DurationSecondsWithFrac<String>", one_second, {expect![[r#""1""#]]};
+ Duration, "DurationMilliSecondsWithFrac", one_second, {expect![[r#"1000.0"#]]};
+ Duration, "DurationMilliSecondsWithFrac<String>", one_second, {expect![[r#""1000""#]]};
+ Duration, "DurationMicroSecondsWithFrac", one_second, {expect![[r#"1000000.0"#]]};
+ Duration, "DurationMicroSecondsWithFrac<String>", one_second, {expect![[r#""1000000""#]]};
+ Duration, "DurationNanoSecondsWithFrac", one_second, {expect![[r#"1000000000.0"#]]};
+ Duration, "DurationNanoSecondsWithFrac<String>", one_second, {expect![[r#""1000000000""#]]};
+ };
+
+ smoketest! {
+ Duration, "DurationSecondsWithFrac", zero, {expect![[r#"0.0"#]]};
+ Duration, "DurationSecondsWithFrac", zero + Duration::nanoseconds(500_000_000), {expect![[r#"0.5"#]]};
+ Duration, "DurationSecondsWithFrac", zero + Duration::seconds(1), {expect![[r#"1.0"#]]};
+ Duration, "DurationSecondsWithFrac", zero - Duration::nanoseconds(500_000_000), {expect![[r#"-0.5"#]]};
+ Duration, "DurationSecondsWithFrac", zero - Duration::seconds(1), {expect![[r#"-1.0"#]]};
+ };
+}
+
+#[test]
+fn test_datetime_utc_smoketest() {
+ let zero = OffsetDateTime::UNIX_EPOCH;
+ let one_second = zero + Duration::seconds(1);
+
+ smoketest! {
+ OffsetDateTime, "TimestampSeconds<i64>", one_second, {expect![[r#"1"#]]};
+ OffsetDateTime, "TimestampSeconds<f64>", one_second, {expect![[r#"1.0"#]]};
+ OffsetDateTime, "TimestampMilliSeconds<i64>", one_second, {expect![[r#"1000"#]]};
+ OffsetDateTime, "TimestampMilliSeconds<f64>", one_second, {expect![[r#"1000.0"#]]};
+ OffsetDateTime, "TimestampMicroSeconds<i64>", one_second, {expect![[r#"1000000"#]]};
+ OffsetDateTime, "TimestampMicroSeconds<f64>", one_second, {expect![[r#"1000000.0"#]]};
+ OffsetDateTime, "TimestampNanoSeconds<i64>", one_second, {expect![[r#"1000000000"#]]};
+ OffsetDateTime, "TimestampNanoSeconds<f64>", one_second, {expect![[r#"1000000000.0"#]]};
+ };
+
+ smoketest! {
+ OffsetDateTime, "TimestampSecondsWithFrac", one_second, {expect![[r#"1.0"#]]};
+ OffsetDateTime, "TimestampSecondsWithFrac<String>", one_second, {expect![[r#""1""#]]};
+ OffsetDateTime, "TimestampMilliSecondsWithFrac", one_second, {expect![[r#"1000.0"#]]};
+ OffsetDateTime, "TimestampMilliSecondsWithFrac<String>", one_second, {expect![[r#""1000""#]]};
+ OffsetDateTime, "TimestampMicroSecondsWithFrac", one_second, {expect![[r#"1000000.0"#]]};
+ OffsetDateTime, "TimestampMicroSecondsWithFrac<String>", one_second, {expect![[r#""1000000""#]]};
+ OffsetDateTime, "TimestampNanoSecondsWithFrac", one_second, {expect![[r#"1000000000.0"#]]};
+ OffsetDateTime, "TimestampNanoSecondsWithFrac<String>", one_second, {expect![[r#""1000000000""#]]};
+ };
+
+ smoketest! {
+ OffsetDateTime, "TimestampSecondsWithFrac", zero, {expect![[r#"0.0"#]]};
+ OffsetDateTime, "TimestampSecondsWithFrac", zero + Duration::nanoseconds(500_000_000), {expect![[r#"0.5"#]]};
+ OffsetDateTime, "TimestampSecondsWithFrac", zero + Duration::seconds(1), {expect![[r#"1.0"#]]};
+ OffsetDateTime, "TimestampSecondsWithFrac", zero - Duration::nanoseconds(500_000_000), {expect![[r#"-0.5"#]]};
+ OffsetDateTime, "TimestampSecondsWithFrac", zero - Duration::seconds(1), {expect![[r#"-1.0"#]]};
+ };
+}
+
+#[test]
+fn test_naive_datetime_smoketest() {
+ let zero = unix_epoch_primitive();
+ let one_second = zero + Duration::seconds(1);
+
+ smoketest! {
+ PrimitiveDateTime, "TimestampSeconds<i64>", one_second, {expect![[r#"1"#]]};
+ PrimitiveDateTime, "TimestampSeconds<f64>", one_second, {expect![[r#"1.0"#]]};
+ PrimitiveDateTime, "TimestampMilliSeconds<i64>", one_second, {expect![[r#"1000"#]]};
+ PrimitiveDateTime, "TimestampMilliSeconds<f64>", one_second, {expect![[r#"1000.0"#]]};
+ PrimitiveDateTime, "TimestampMicroSeconds<i64>", one_second, {expect![[r#"1000000"#]]};
+ PrimitiveDateTime, "TimestampMicroSeconds<f64>", one_second, {expect![[r#"1000000.0"#]]};
+ PrimitiveDateTime, "TimestampNanoSeconds<i64>", one_second, {expect![[r#"1000000000"#]]};
+ PrimitiveDateTime, "TimestampNanoSeconds<f64>", one_second, {expect![[r#"1000000000.0"#]]};
+ };
+
+ smoketest! {
+ PrimitiveDateTime, "TimestampSecondsWithFrac", one_second, {expect![[r#"1.0"#]]};
+ PrimitiveDateTime, "TimestampSecondsWithFrac<String>", one_second, {expect![[r#""1""#]]};
+ PrimitiveDateTime, "TimestampMilliSecondsWithFrac", one_second, {expect![[r#"1000.0"#]]};
+ PrimitiveDateTime, "TimestampMilliSecondsWithFrac<String>", one_second, {expect![[r#""1000""#]]};
+ PrimitiveDateTime, "TimestampMicroSecondsWithFrac", one_second, {expect![[r#"1000000.0"#]]};
+ PrimitiveDateTime, "TimestampMicroSecondsWithFrac<String>", one_second, {expect![[r#""1000000""#]]};
+ PrimitiveDateTime, "TimestampNanoSecondsWithFrac", one_second, {expect![[r#"1000000000.0"#]]};
+ PrimitiveDateTime, "TimestampNanoSecondsWithFrac<String>", one_second, {expect![[r#""1000000000""#]]};
+ };
+
+ smoketest! {
+ PrimitiveDateTime, "TimestampSecondsWithFrac", zero, {expect![[r#"0.0"#]]};
+ PrimitiveDateTime, "TimestampSecondsWithFrac", zero + Duration::nanoseconds(500_000_000), {expect![[r#"0.5"#]]};
+ PrimitiveDateTime, "TimestampSecondsWithFrac", zero + Duration::seconds(1), {expect![[r#"1.0"#]]};
+ PrimitiveDateTime, "TimestampSecondsWithFrac", zero - Duration::nanoseconds(500_000_000), {expect![[r#"-0.5"#]]};
+ PrimitiveDateTime, "TimestampSecondsWithFrac", zero - Duration::seconds(1), {expect![[r#"-1.0"#]]};
+ };
+}
+
+#[test]
+fn test_offset_datetime_rfc2822() {
+ #[serde_as]
+ #[derive(Debug, PartialEq, Deserialize, Serialize)]
+ struct S(#[serde_as(as = "time_0_3::format_description::well_known::Rfc2822")] OffsetDateTime);
+
+ is_equal(
+ S(OffsetDateTime::UNIX_EPOCH),
+ expect![[r#""Thu, 01 Jan 1970 00:00:00 +0000""#]],
+ );
+
+ check_error_deserialization::<S>(
+ r#""Foobar""#,
+ expect![[r#"the 'weekday' component could not be parsed at line 1 column 8"#]],
+ );
+ check_error_deserialization::<S>(
+ r#""Fri, 2000""#,
+ expect![[r#"a character literal was not valid at line 1 column 11"#]],
+ );
+}
+
+#[test]
+fn test_offset_datetime_rfc3339() {
+ #[serde_as]
+ #[derive(Debug, PartialEq, Deserialize, Serialize)]
+ struct S(#[serde_as(as = "time_0_3::format_description::well_known::Rfc3339")] OffsetDateTime);
+
+ is_equal(
+ S(OffsetDateTime::UNIX_EPOCH),
+ expect![[r#""1970-01-01T00:00:00Z""#]],
+ );
+ check_deserialization::<S>(
+ S(
+ OffsetDateTime::from_unix_timestamp_nanos(482_196_050_520_000_000)
+ .unwrap()
+ .to_offset(UtcOffset::from_hms(0, 0, 0).unwrap()),
+ ),
+ r#""1985-04-12T23:20:50.52Z""#,
+ );
+ check_deserialization::<S>(
+ S(OffsetDateTime::from_unix_timestamp(851_042_397)
+ .unwrap()
+ .to_offset(UtcOffset::from_hms(-8, 0, 0).unwrap())),
+ r#""1996-12-19T16:39:57-08:00""#,
+ );
+ check_deserialization::<S>(
+ S(
+ OffsetDateTime::from_unix_timestamp_nanos(662_687_999_999_999_999)
+ .unwrap()
+ .to_offset(UtcOffset::from_hms(0, 0, 0).unwrap()),
+ ),
+ r#""1990-12-31T23:59:60Z""#,
+ );
+ check_deserialization::<S>(
+ S(
+ OffsetDateTime::from_unix_timestamp_nanos(662_687_999_999_999_999)
+ .unwrap()
+ .to_offset(UtcOffset::from_hms(-8, 0, 0).unwrap()),
+ ),
+ r#""1990-12-31T15:59:60-08:00""#,
+ );
+ check_deserialization::<S>(
+ S(
+ OffsetDateTime::from_unix_timestamp_nanos(-1_041_337_172_130_000_000)
+ .unwrap()
+ .to_offset(UtcOffset::from_hms(0, 20, 0).unwrap()),
+ ),
+ r#""1937-01-01T12:00:27.87+00:20""#,
+ );
+
+ check_error_deserialization::<S>(
+ r#""Foobar""#,
+ expect![[r#"the 'year' component could not be parsed at line 1 column 8"#]],
+ );
+ check_error_deserialization::<S>(
+ r#""2000-AA""#,
+ expect![[r#"the 'month' component could not be parsed at line 1 column 9"#]],
+ );
+}
+
+#[test]
+fn test_offset_datetime_iso8601() {
+ /// The default configuration for [`Iso8601`].
+ const DEFAULT_CONFIG: time_0_3::format_description::well_known::iso8601::EncodedConfig =
+ time_0_3::format_description::well_known::iso8601::Config::DEFAULT.encode();
+
+ #[serde_as]
+ #[derive(Debug, PartialEq, Deserialize, Serialize)]
+ struct S(
+ #[serde_as(as = "time_0_3::format_description::well_known::Iso8601<DEFAULT_CONFIG>")]
+ OffsetDateTime,
+ );
+
+ is_equal(
+ S(OffsetDateTime::UNIX_EPOCH),
+ expect![[r#""1970-01-01T00:00:00.000000000Z""#]],
+ );
+ check_deserialization::<S>(
+ S(
+ OffsetDateTime::from_unix_timestamp_nanos(482_196_050_520_000_000)
+ .unwrap()
+ .to_offset(UtcOffset::from_hms(0, 0, 0).unwrap()),
+ ),
+ r#""1985-04-12T23:20:50.52Z""#,
+ );
+ check_deserialization::<S>(
+ S(OffsetDateTime::from_unix_timestamp(851_042_397)
+ .unwrap()
+ .to_offset(UtcOffset::from_hms(-8, 0, 0).unwrap())),
+ r#""1996-12-19T16:39:57-08:00""#,
+ );
+ check_deserialization::<S>(
+ S(
+ OffsetDateTime::from_unix_timestamp_nanos(-1_041_337_172_130_000_000)
+ .unwrap()
+ .to_offset(UtcOffset::from_hms(0, 20, 0).unwrap()),
+ ),
+ r#""1937-01-01T12:00:27.87+00:20""#,
+ );
+
+ check_error_deserialization::<S>(
+ r#""Foobar""#,
+ expect![[r#"the 'year' component could not be parsed at line 1 column 8"#]],
+ );
+ check_error_deserialization::<S>(
+ r#""2000-AA""#,
+ expect!["unexpected trailing characters at line 1 column 9"],
+ );
+}
diff --git a/third_party/rust/serde_with/tests/utils.rs b/third_party/rust/serde_with/tests/utils.rs
new file mode 100644
index 0000000000..d9247ffff9
--- /dev/null
+++ b/third_party/rust/serde_with/tests/utils.rs
@@ -0,0 +1,79 @@
+#![allow(dead_code)]
+
+use core::fmt::Debug;
+use expect_test::Expect;
+use pretty_assertions::assert_eq;
+use serde::{de::DeserializeOwned, Serialize};
+
+#[track_caller]
+pub fn is_equal<T>(value: T, expected: Expect)
+where
+ T: Debug + DeserializeOwned + PartialEq + Serialize,
+{
+ let serialized = serde_json::to_string_pretty(&value).unwrap();
+ expected.assert_eq(&serialized);
+ assert_eq!(
+ value,
+ serde_json::from_str::<T>(&serialized).unwrap(),
+ "Deserialization differs from expected value."
+ );
+}
+
+/// Like [`is_equal`] but not pretty-print
+#[track_caller]
+pub fn is_equal_compact<T>(value: T, expected: Expect)
+where
+ T: Debug + DeserializeOwned + PartialEq + Serialize,
+{
+ let serialized = serde_json::to_string(&value).unwrap();
+ expected.assert_eq(&serialized);
+ assert_eq!(
+ value,
+ serde_json::from_str::<T>(&serialized).unwrap(),
+ "Deserialization differs from expected value."
+ );
+}
+
+#[track_caller]
+pub fn check_deserialization<T>(value: T, deserialize_from: &str)
+where
+ T: Debug + DeserializeOwned + PartialEq,
+{
+ assert_eq!(
+ value,
+ serde_json::from_str::<T>(deserialize_from).unwrap(),
+ "Deserialization differs from expected value."
+ );
+}
+
+#[track_caller]
+pub fn check_serialization<T>(value: T, serialize_to: Expect)
+where
+ T: Debug + Serialize,
+{
+ serialize_to.assert_eq(&serde_json::to_string_pretty(&value).unwrap());
+}
+
+#[track_caller]
+pub fn check_error_serialization<T>(value: T, error_msg: Expect)
+where
+ T: Debug + Serialize,
+{
+ error_msg.assert_eq(
+ &serde_json::to_string_pretty(&value)
+ .unwrap_err()
+ .to_string(),
+ );
+}
+
+#[track_caller]
+pub fn check_error_deserialization<T>(deserialize_from: &str, error_msg: Expect)
+where
+ T: Debug + DeserializeOwned,
+{
+ error_msg.assert_eq(
+ &serde_json::from_str::<T>(deserialize_from)
+ .unwrap_err()
+ .to_string(),
+ )
+}
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..be520a2a66
--- /dev/null
+++ b/third_party/rust/serde_with/tests/version_numbers.rs
@@ -0,0 +1,79 @@
+// Needed to suppress a 2021 incompatibility warning in the macro generated code
+// The non_fmt_panic lint is not yet available on most Rust versions
+#![allow(unknown_lints, non_fmt_panics)]
+
+use version_sync::{assert_contains_regex, assert_html_root_url_updated};
+
+#[test]
+fn test_changelog() {
+ assert_contains_regex!("CHANGELOG.md", r#"## \[{version}\]"#);
+}
+
+#[test]
+fn test_html_root_url() {
+ assert_html_root_url_updated!("src/lib.rs");
+}
+
+#[test]
+fn test_serde_with_macros_dependency() {
+ version_sync::assert_contains_regex!(
+ "../serde_with/Cargo.toml",
+ r#"^serde_with_macros = .*? version = "={version}""#
+ );
+ version_sync::assert_contains_regex!(
+ "../serde_with_macros/Cargo.toml",
+ r#"^version = "{version}""#
+ );
+}
+
+/// Check that all docs.rs links point to the current version
+///
+/// Parse all docs.rs links in `*.rs` and `*.md` files and check that they point to the current version.
+/// If a link should point to latest version this can be done by using `latest` in the version.
+/// The `*` version specifier is not allowed.
+///
+/// Arguably this should be part of version-sync. There is an open issue for this feature:
+/// https://github.com/mgeisler/version-sync/issues/72
+#[test]
+fn test_docs_rs_url_point_to_current_version() -> Result<(), Box<dyn std::error::Error>> {
+ let pkg_name = env!("CARGO_PKG_NAME");
+ let pkg_version = env!("CARGO_PKG_VERSION");
+
+ let re = regex::Regex::new(&format!(
+ "https?://docs.rs/{pkg_name}/((\\d[^/]+|\\*|latest))/"
+ ))?;
+ let mut error = false;
+
+ for entry in glob::glob("**/*.rs")?.chain(glob::glob("**/README.md")?) {
+ let entry = entry?;
+ let content = std::fs::read_to_string(&entry)?;
+ for (line_number, line) in content.split('\n').enumerate() {
+ for capture in re.captures_iter(line) {
+ match capture
+ .get(1)
+ .expect("Will exist if regex matches")
+ .as_str()
+ {
+ "latest" => {}
+ version if version != pkg_version => {
+ error = true;
+ println!(
+ "{}:{} pkg_version is {} but found URL {}",
+ entry.display(),
+ line_number + 1,
+ pkg_version,
+ capture.get(0).expect("Group 0 always exists").as_str()
+ )
+ }
+ _ => {}
+ }
+ }
+ }
+ }
+
+ if error {
+ panic!("Found wrong URLs in file(s)");
+ } else {
+ Ok(())
+ }
+}
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..bc7a78711e
--- /dev/null
+++ b/third_party/rust/serde_with/tests/with_prefix.rs
@@ -0,0 +1,164 @@
+#![allow(
+ // clippy is broken and shows wrong warnings
+ // clippy on stable does not know yet about the lint name
+ unknown_lints,
+ // https://github.com/rust-lang/rust-clippy/issues/8867
+ clippy::derive_partial_eq_without_eq,
+)]
+
+extern crate alloc;
+
+mod utils;
+
+use crate::utils::is_equal;
+use alloc::collections::BTreeMap;
+use core::iter::FromIterator;
+use expect_test::expect;
+use serde::{Deserialize, Serialize};
+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: HashMap::from_iter(vec![("t".to_owned(), "T".to_owned())]),
+ };
+
+ is_equal(
+ m,
+ expect![[r#"
+ {
+ "player1_name": "name1",
+ "player1_votes": 1,
+ "player2_name": "name2",
+ "player2_votes": 2,
+ "tag_t": "T"
+ }"#]],
+ );
+}
+
+#[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: HashMap::from_iter(vec![("t".to_owned(), "T".to_owned())]),
+ };
+
+ is_equal(
+ m,
+ expect![[r#"
+ {
+ "player1": {
+ "player1_name": "name1",
+ "player1_votes": 1
+ },
+ "player2": {
+ "player2_name": "name2",
+ "player2_votes": 2
+ },
+ "player3": null,
+ "tags": {
+ "tag_t": "T"
+ }
+ }"#]],
+ );
+}
+
+/// Ensure that with_prefix works for unit type enum variants.
+#[test]
+fn test_enum_unit_variant_with_prefix() {
+ #[derive(Hash, PartialEq, Eq, Debug, Serialize, Deserialize, Ord, PartialOrd)]
+ enum Foo {
+ One,
+ Two,
+ Three,
+ }
+
+ #[derive(Hash, PartialEq, Eq, Debug, Serialize, Deserialize, Ord, PartialOrd)]
+ struct Data {
+ stuff: String,
+
+ #[serde(flatten, with = "foo")]
+ foo: BTreeMap<Foo, i32>,
+ }
+ with_prefix!(foo "foo_");
+
+ let d = Data {
+ stuff: "Stuff".to_owned(),
+ foo: BTreeMap::from_iter(vec![(Foo::One, 1), (Foo::Two, 2), (Foo::Three, 3)]),
+ };
+
+ is_equal(
+ d,
+ expect![[r#"
+ {
+ "stuff": "Stuff",
+ "foo_One": 1,
+ "foo_Two": 2,
+ "foo_Three": 3
+ }"#]],
+ );
+}