diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /third_party/rust/serde_with | |
parent | Initial commit. (diff) | |
download | firefox-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')
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 + }"#]], + ); +} |