Bug 1773399 - Update serde_with to 1.14.0. r=emilio

Differential Revision: https://phabricator.services.mozilla.com/D148723
This commit is contained in:
Mike Hommey 2022-06-09 20:23:28 +00:00
Родитель 5c399b2466
Коммит 311f8b84a3
61 изменённых файлов: 12665 добавлений и 1129 удалений

4
Cargo.lock сгенерированный
Просмотреть файл

@ -4766,9 +4766,9 @@ dependencies = [
[[package]]
name = "serde_with"
version = "1.6.4"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b44be9227e214a0420707c9ca74c2d4991d9955bae9415a8f93f05cebf561be5"
checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff"
dependencies = [
"serde",
"serde_with_macros",

Просмотреть файл

@ -1330,7 +1330,7 @@ version = "0.7.1"
criteria = "safe-to-run"
[[unaudited.serde_with]]
version = "1.6.4"
version = "1.14.0"
criteria = "safe-to-deploy"
[[unaudited.serde_with_macros]]

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

470
third_party/rust/serde_with/CHANGELOG.md поставляемый
Просмотреть файл

@ -5,20 +5,436 @@ 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).
## [1.6.4]
## [Unreleased]
## [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]
## [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]
## [1.6.2] - 2021-01-30
### Added
@ -28,7 +444,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
Thanks to @lovasoa for suggesting and implementing it.
## [1.6.1]
## [1.6.1] - 2021-01-24
### Added
@ -41,7 +457,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
* Release `Sized` trait bound from `As`, `Same`, `SerializeAs`, and `SerializeAsWrap`.
Only the serialize part is relaxed.
## [1.6.0]
## [1.6.0] - 2020-11-22
### Added
@ -55,15 +471,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
* Bump minimum supported rust version to 1.40.0
## [1.5.1]
## [1.5.1] - 2020-10-07
### Fixed
* Depend on serde with the `derive` feature enabled.
The `derive` feature is required to deserliaze untagged enums which are used in the `DefaultOnError` helpers.
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]
## [1.5.0] - 2020-10-01
### Added
@ -85,7 +501,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
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 `Serialialize`.
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.
@ -113,7 +529,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
* 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]
## [1.5.0-alpha.2] - 2020-08-16
### Added
@ -129,7 +545,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
* 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]
## [1.5.0-alpha.1] - 2020-06-27
### Added
@ -154,7 +570,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
* The `with_prefix!` macro, to add a string prefixes during serialization, now also works with unit variant enum types. #115 #116
## [1.4.0]
## [1.4.0] - 2020-01-16
### Added
@ -169,22 +585,22 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
* 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]
## [1.3.1] - 2019-04-09
### Fixed
* Use `serde_with_macros` with proper dependencies specified.
## [1.3.0]
## [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 helpfull for APIs which have many optional fields.
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]
## [1.2.0] - 2019-03-04
### Added
@ -195,32 +611,32 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
* Bumped minimal Rust version to 1.30.0
## [1.1.0]
## [1.1.0] - 2019-02-18
### Added
* Serialize HashMap/BTreeMap as list of tuples
## [1.0.0]
## [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]
## [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]
## [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]
## [0.2.3] - 2018-11-08
### Added
@ -232,34 +648,34 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
* Improve Travis configuration
* Various clippy improvements
## [0.2.2]
## [0.2.2] - 2018-08-05
### Added
* `unwrap_or_skip` allows to transparently serialize the inner part of a `Some(T)`
* Add deserialization helpser for sets and maps, inspired by [comment](https://github.com/serde-rs/serde/issues/553#issuecomment-299711855)
* 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]
## [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]
## [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 to deserialize "#foo,#bar"
* String-based collections using `Display` and `FromStr`, allows deserializing "#foo,#bar"
## [0.1.0]
## [0.1.0] - 2017-08-17
### Added

141
third_party/rust/serde_with/Cargo.toml поставляемый
Просмотреть файл

@ -3,62 +3,122 @@
# 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
# to registry (e.g., crates.io) dependencies.
#
# If you believe there's an error in this file please file an
# issue against the rust-lang/cargo repository. If you're
# editing this file be aware that the upstream Cargo.toml
# will likely look very different (and much more reasonable)
# 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 = "2018"
rust-version = "1.53"
name = "serde_with"
version = "1.6.4"
authors = ["Jonas Bushart"]
include = ["src/**/*", "LICENSE-*", "README.*", "CHANGELOG.md"]
version = "1.14.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"]
keywords = [
"serde",
"utilities",
"serialization",
"deserialization",
]
categories = ["encoding"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/jonasbb/serde_with"
resolver = "2"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = [
"--cfg=docsrs",
"-Zunstable-options",
"--generate-link-to-definition",
]
[[test]]
name = "base64"
path = "tests/base64.rs"
required-features = [
"base64",
"macros",
]
[[test]]
name = "chrono"
path = "tests/chrono.rs"
required-features = ["chrono", "macros"]
required-features = [
"chrono",
"macros",
]
[[test]]
name = "hex"
path = "tests/hex.rs"
required-features = ["hex", "macros"]
required-features = [
"hex",
"macros",
]
[[test]]
name = "indexmap"
path = "tests/indexmap.rs"
required-features = [
"indexmap",
"macros",
]
[[test]]
name = "json"
path = "tests/json.rs"
required-features = ["json", "macros"]
required-features = [
"json",
"macros",
]
[[test]]
name = "serde_as"
path = "tests/serde_as.rs"
path = "tests/serde_as/lib.rs"
required-features = ["macros"]
[[test]]
name = "serde_as_duration"
path = "tests/serde_as_duration.rs"
required-features = ["macros"]
name = "time_0_3"
path = "tests/time_0_3.rs"
required-features = [
"macros",
"time_0_3",
]
[[test]]
name = "serde_as_macro"
path = "tests/serde_as_macro.rs"
name = "derives"
path = "tests/derives/lib.rs"
required-features = ["macros"]
[dependencies.base64_crate]
version = "0.13.0"
optional = true
package = "base64"
[dependencies.chrono_crate]
version = "0.4.1"
features = ["serde"]
features = [
"clock",
"serde",
"std",
]
optional = true
default-features = false
package = "chrono"
[dependencies.doc-comment]
@ -69,8 +129,14 @@ optional = true
version = "0.4.2"
optional = true
[dependencies.indexmap_crate]
version = "1.8"
features = ["serde-1"]
optional = true
package = "indexmap"
[dependencies.serde]
version = "1.0.75"
version = "1.0.122"
features = ["derive"]
[dependencies.serde_json]
@ -78,8 +144,15 @@ version = "1.0.1"
optional = true
[dependencies.serde_with_macros]
version = "1.4.1"
version = "1.5.2"
optional = true
[dependencies.time_0_3]
version = "~0.3"
features = ["serde-well-known"]
optional = true
package = "time"
[dev-dependencies.expect-test]
version = "1.0.0"
@ -93,37 +166,49 @@ version = "0.3.0"
version = "0.3.16"
[dev-dependencies.pretty_assertions]
version = "0.6.1"
version = "1.0.0"
[dev-dependencies.regex]
version = "1.3.9"
features = ["std"]
default-features = false
[dev-dependencies.rmp-serde]
version = "1.1.0"
[dev-dependencies.ron]
version = "0.6"
version = "0.7"
[dev-dependencies.rustversion]
version = "1.0.0"
[dev-dependencies.serde-xml-rs]
version = "0.4.1"
[dev-dependencies.serde_derive]
version = "1.0.75"
version = "0.5.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.8.21"
[dev-dependencies.version-sync]
version = "0.9.1"
[features]
base64 = ["base64_crate"]
chrono = ["chrono_crate"]
default = ["macros"]
guide = ["doc-comment", "macros"]
guide = [
"doc-comment",
"macros",
]
indexmap = ["indexmap_crate"]
json = ["serde_json"]
macros = ["serde_with_macros"]
[badges.maintenance]
status = "actively-developed"

61
third_party/rust/serde_with/README.md поставляемый
Просмотреть файл

@ -1,17 +1,21 @@
# Custom de/serialization functions for Rust's [serde](https://serde.rs)
[![docs.rs badge](https://docs.rs/serde_with/badge.svg)](https://docs.rs/serde_with/)
[![crates.io badge](https://img.shields.io/crates/v/serde_with.svg)](https://crates.io/crates/serde_with/)
[![Build Status](https://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)
[![Binder](https://img.shields.io/badge/Try%20on%20-binder-579ACA.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFkAAABZCAMAAABi1XidAAAB8lBMVEX///9XmsrmZYH1olJXmsr1olJXmsrmZYH1olJXmsr1olJXmsrmZYH1olL1olJXmsr1olJXmsrmZYH1olL1olJXmsrmZYH1olJXmsr1olL1olJXmsrmZYH1olL1olJXmsrmZYH1olL1olL0nFf1olJXmsrmZYH1olJXmsq8dZb1olJXmsrmZYH1olJXmspXmspXmsr1olL1olJXmsrmZYH1olJXmsr1olL1olJXmsrmZYH1olL1olLeaIVXmsrmZYH1olL1olL1olJXmsrmZYH1olLna31Xmsr1olJXmsr1olJXmsrmZYH1olLqoVr1olJXmsr1olJXmsrmZYH1olL1olKkfaPobXvviGabgadXmsqThKuofKHmZ4Dobnr1olJXmsr1olJXmspXmsr1olJXmsrfZ4TuhWn1olL1olJXmsqBi7X1olJXmspZmslbmMhbmsdemsVfl8ZgmsNim8Jpk8F0m7R4m7F5nLB6jbh7jbiDirOEibOGnKaMhq+PnaCVg6qWg6qegKaff6WhnpKofKGtnomxeZy3noG6dZi+n3vCcpPDcpPGn3bLb4/Mb47UbIrVa4rYoGjdaIbeaIXhoWHmZYHobXvpcHjqdHXreHLroVrsfG/uhGnuh2bwj2Hxk17yl1vzmljzm1j0nlX1olL3AJXWAAAAbXRSTlMAEBAQHx8gICAuLjAwMDw9PUBAQEpQUFBXV1hgYGBkcHBwcXl8gICAgoiIkJCQlJicnJ2goKCmqK+wsLC4usDAwMjP0NDQ1NbW3Nzg4ODi5+3v8PDw8/T09PX29vb39/f5+fr7+/z8/Pz9/v7+zczCxgAABC5JREFUeAHN1ul3k0UUBvCb1CTVpmpaitAGSLSpSuKCLWpbTKNJFGlcSMAFF63iUmRccNG6gLbuxkXU66JAUef/9LSpmXnyLr3T5AO/rzl5zj137p136BISy44fKJXuGN/d19PUfYeO67Znqtf2KH33Id1psXoFdW30sPZ1sMvs2D060AHqws4FHeJojLZqnw53cmfvg+XR8mC0OEjuxrXEkX5ydeVJLVIlV0e10PXk5k7dYeHu7Cj1j+49uKg7uLU61tGLw1lq27ugQYlclHC4bgv7VQ+TAyj5Zc/UjsPvs1sd5cWryWObtvWT2EPa4rtnWW3JkpjggEpbOsPr7F7EyNewtpBIslA7p43HCsnwooXTEc3UmPmCNn5lrqTJxy6nRmcavGZVt/3Da2pD5NHvsOHJCrdc1G2r3DITpU7yic7w/7Rxnjc0kt5GC4djiv2Sz3Fb2iEZg41/ddsFDoyuYrIkmFehz0HR2thPgQqMyQYb2OtB0WxsZ3BeG3+wpRb1vzl2UYBog8FfGhttFKjtAclnZYrRo9ryG9uG/FZQU4AEg8ZE9LjGMzTmqKXPLnlWVnIlQQTvxJf8ip7VgjZjyVPrjw1te5otM7RmP7xm+sK2Gv9I8Gi++BRbEkR9EBw8zRUcKxwp73xkaLiqQb+kGduJTNHG72zcW9LoJgqQxpP3/Tj//c3yB0tqzaml05/+orHLksVO+95kX7/7qgJvnjlrfr2Ggsyx0eoy9uPzN5SPd86aXggOsEKW2Prz7du3VID3/tzs/sSRs2w7ovVHKtjrX2pd7ZMlTxAYfBAL9jiDwfLkq55Tm7ifhMlTGPyCAs7RFRhn47JnlcB9RM5T97ASuZXIcVNuUDIndpDbdsfrqsOppeXl5Y+XVKdjFCTh+zGaVuj0d9zy05PPK3QzBamxdwtTCrzyg/2Rvf2EstUjordGwa/kx9mSJLr8mLLtCW8HHGJc2R5hS219IiF6PnTusOqcMl57gm0Z8kanKMAQg0qSyuZfn7zItsbGyO9QlnxY0eCuD1XL2ys/MsrQhltE7Ug0uFOzufJFE2PxBo/YAx8XPPdDwWN0MrDRYIZF0mSMKCNHgaIVFoBbNoLJ7tEQDKxGF0kcLQimojCZopv0OkNOyWCCg9XMVAi7ARJzQdM2QUh0gmBozjc3Skg6dSBRqDGYSUOu66Zg+I2fNZs/M3/f/Grl/XnyF1Gw3VKCez0PN5IUfFLqvgUN4C0qNqYs5YhPL+aVZYDE4IpUk57oSFnJm4FyCqqOE0jhY2SMyLFoo56zyo6becOS5UVDdj7Vih0zp+tcMhwRpBeLyqtIjlJKAIZSbI8SGSF3k0pA3mR5tHuwPFoa7N7reoq2bqCsAk1HqCu5uvI1n6JuRXI+S1Mco54YmYTwcn6Aeic+kssXi8XpXC4V3t7/ADuTNKaQJdScAAAAAElFTkSuQmCC)](https://mybinder.org/v2/gist/jonasbb/18b9aece4c17f617b1c2b3946d29eeb0/HEAD?filepath=serde-with-demo.ipynb)
---
This crate provides custom de/serialization helpers to use in combination with [serde's with-annotation][with-annotation] and with the improved [`serde_as`][user guide]-annotation.
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`][] or [`serde_with::rust::display_fromstr`][display_fromstr] 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>`.
@ -22,7 +26,7 @@ Some common use cases are:
**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.
For bugs, please open a [new issue](https://github.com/jonasbb/serde_with/issues/new) on GitHub.
## Use `serde_with` in your Project
@ -30,7 +34,7 @@ Add this to your `Cargo.toml`:
```toml
[dependencies.serde_with]
version = "1.6.4"
version = "1.14.0"
features = [ "..." ]
```
@ -40,6 +44,7 @@ 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 place *before* the `#[derive]`.
### `DisplayFromStr`
@ -59,10 +64,39 @@ Foo {bar: 12}
{"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 to circumvent this restriction, even for nested types and nested arrays.
```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]>,
}
// 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])
};
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 place *before* the `#[derive]`.
```rust
#[skip_serializing_none]
@ -124,14 +158,15 @@ Foo {
}
```
[`DisplayFromStr`]: https://docs.rs/serde_with/1.6.4/serde_with/struct.DisplayFromStr.html
[`with_prefix!`]: https://docs.rs/serde_with/1.6.4/serde_with/macro.with_prefix.html
[display_fromstr]: https://docs.rs/serde_with/1.6.4/serde_with/rust/display_fromstr/index.html
[feature flags]: https://docs.rs/serde_with/1.6.4/serde_with/guide/feature_flags/index.html
[skip_serializing_none]: https://docs.rs/serde_with/1.6.4/serde_with/attr.skip_serializing_none.html
[StringWithSeparator]: https://docs.rs/serde_with/1.6.4/serde_with/rust/struct.StringWithSeparator.html
[user guide]: https://docs.rs/serde_with/1.6.4/serde_with/guide/index.html
[`DisplayFromStr`]: https://docs.rs/serde_with/1.14.0/serde_with/struct.DisplayFromStr.html
[`with_prefix!`]: https://docs.rs/serde_with/1.14.0/serde_with/macro.with_prefix.html
[display_fromstr]: https://docs.rs/serde_with/1.14.0/serde_with/rust/display_fromstr/index.html
[feature flags]: https://docs.rs/serde_with/1.14.0/serde_with/guide/feature_flags/index.html
[skip_serializing_none]: https://docs.rs/serde_with/1.14.0/serde_with/attr.skip_serializing_none.html
[StringWithSeparator]: https://docs.rs/serde_with/1.14.0/serde_with/rust/struct.StringWithSeparator.html
[user guide]: https://docs.rs/serde_with/1.14.0/serde_with/guide/index.html
[with-annotation]: https://serde.rs/field-attrs.html#with
[as-annotation]: https://docs.rs/serde_with/1.14.0/serde_with/guide/serde_as/index.html
## License
@ -144,6 +179,10 @@ 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

18
third_party/rust/serde_with/README.tpl поставляемый
Просмотреть файл

@ -1,18 +0,0 @@
# Custom de/serialization functions for Rust's [serde](https://serde.rs)
{{readme}}
## License
Licensed under either of
* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
## Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall
be dual licensed as above, without any additional terms or conditions.

205
third_party/rust/serde_with/src/base64.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,205 @@
//! 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::{formats, DeserializeAs, SerializeAs};
use alloc::{format, string::String, vec::Vec};
use core::{
convert::{TryFrom, TryInto},
default::Default,
marker::PhantomData,
};
use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
/// 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 `CHARSET` is a type implementing [`CharacterSet`].
/// `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/
#[derive(Copy, Clone, Debug, Default)]
pub struct Base64<CHARSET: CharacterSet = Standard, PADDING: formats::Format = formats::Padded>(
PhantomData<(CHARSET, PADDING)>,
);
impl<T, CHARSET> SerializeAs<T> for Base64<CHARSET, formats::Padded>
where
T: AsRef<[u8]>,
CHARSET: CharacterSet,
{
fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
base64_crate::encode_config(source, base64_crate::Config::new(CHARSET::charset(), true))
.serialize(serializer)
}
}
impl<T, CHARSET> SerializeAs<T> for Base64<CHARSET, formats::Unpadded>
where
T: AsRef<[u8]>,
CHARSET: CharacterSet,
{
fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
base64_crate::encode_config(source, base64_crate::Config::new(CHARSET::charset(), false))
.serialize(serializer)
}
}
impl<'de, T, CHARSET, FORMAT> DeserializeAs<'de, T> for Base64<CHARSET, FORMAT>
where
T: TryFrom<Vec<u8>>,
CHARSET: CharacterSet,
FORMAT: formats::Format,
{
fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
{
String::deserialize(deserializer)
.and_then(|s| {
base64_crate::decode_config(
&*s,
base64_crate::Config::new(CHARSET::charset(), false),
)
.map_err(Error::custom)
})
.and_then(|vec: Vec<u8>| {
let length = vec.len();
vec.try_into().map_err(|_e: T::Error| {
Error::custom(format!(
"Can't convert a Byte Vector of length {} to the output type.",
length
))
})
})
}
}
/// A base64 character set from [this list](base64_crate::CharacterSet).
pub trait CharacterSet {
/// Return a specific character set.
///
/// Return one enum variant of the [`base64::CharacterSet`](base64_crate::CharacterSet) enum.
fn charset() -> base64_crate::CharacterSet;
}
/// The standard character set (uses `+` and `/`).
///
/// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-3).
#[derive(Copy, Clone, Debug, Default)]
pub struct Standard;
impl CharacterSet for Standard {
fn charset() -> base64_crate::CharacterSet {
base64_crate::CharacterSet::Standard
}
}
/// The URL safe character set (uses `-` and `_`).
///
/// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-3).
#[derive(Copy, Clone, Debug, Default)]
pub struct UrlSafe;
impl CharacterSet for UrlSafe {
fn charset() -> base64_crate::CharacterSet {
base64_crate::CharacterSet::UrlSafe
}
}
/// The `crypt(3)` character set (uses `./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`).
///
/// Not standardized, but folk wisdom on the net asserts that this alphabet is what crypt uses.
#[derive(Copy, Clone, Debug, Default)]
pub struct Crypt;
impl CharacterSet for Crypt {
fn charset() -> base64_crate::CharacterSet {
base64_crate::CharacterSet::Crypt
}
}
/// The bcrypt character set (uses `./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`).
#[derive(Copy, Clone, Debug, Default)]
pub struct Bcrypt;
impl CharacterSet for Bcrypt {
fn charset() -> base64_crate::CharacterSet {
base64_crate::CharacterSet::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).
#[derive(Copy, Clone, Debug, Default)]
pub struct ImapMutf7;
impl CharacterSet for ImapMutf7 {
fn charset() -> base64_crate::CharacterSet {
base64_crate::CharacterSet::ImapMutf7
}
}
/// The character set used in BinHex 4.0 files.
///
/// See [BinHex 4.0 Definition](http://files.stairways.com/other/binhex-40-specs-info.txt).
#[derive(Copy, Clone, Debug, Default)]
pub struct BinHex;
impl CharacterSet for BinHex {
fn charset() -> base64_crate::CharacterSet {
base64_crate::CharacterSet::BinHex
}
}

298
third_party/rust/serde_with/src/chrono.rs поставляемый
Просмотреть файл

@ -8,22 +8,33 @@ use crate::{
de::DeserializeAs,
formats::{Flexible, Format, Strict, Strictness},
ser::SerializeAs,
utils, DurationSeconds, DurationSecondsWithFrac, TimestampSeconds, TimestampSecondsWithFrac,
utils::duration::{DurationSigned, Sign},
DurationMicroSeconds, DurationMicroSecondsWithFrac, DurationMilliSeconds,
DurationMilliSecondsWithFrac, DurationNanoSeconds, DurationNanoSecondsWithFrac,
DurationSeconds, DurationSecondsWithFrac, TimestampMicroSeconds, TimestampMicroSecondsWithFrac,
TimestampMilliSeconds, TimestampMilliSecondsWithFrac, TimestampNanoSeconds,
TimestampNanoSecondsWithFrac, TimestampSeconds, TimestampSecondsWithFrac,
};
use chrono_crate::{DateTime, Duration, Local, NaiveDateTime, Utc};
use alloc::{format, string::String, vec::Vec};
use chrono_crate::{DateTime, Duration, Local, NaiveDateTime, TimeZone, Utc};
use core::fmt;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use utils::duration::{DurationSigned, Sign};
/// Create a [`DateTime`] for the Unix Epoch using the [`Utc`] timezone
fn unix_epoch_utc() -> DateTime<Utc> {
DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(0, 0), Utc)
}
/// Create a [`DateTime`] for the Unix Epoch using the [`Utc`] timezone
/// Create a [`DateTime`] for the Unix Epoch using the [`Local`] timezone
fn unix_epoch_local() -> DateTime<Local> {
DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(0, 0), Utc).with_timezone(&Local)
}
/// Create a [`NaiveDateTime`] for the Unix Epoch
fn unix_epoch_naive() -> NaiveDateTime {
NaiveDateTime::from_timestamp(0, 0)
}
/// 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.
@ -32,7 +43,7 @@ fn unix_epoch_local() -> DateTime<Local> {
///
/// ```
/// # use chrono_crate::{DateTime, Utc};
/// # use serde_derive::Deserialize;
/// # use serde::Deserialize;
/// #
/// #[derive(Debug, Deserialize)]
/// struct S {
@ -47,8 +58,8 @@ fn unix_epoch_local() -> DateTime<Local> {
/// // and strings with numbers, for high-precision values
/// assert!(serde_json::from_str::<S>(r#"{ "date": "1478563200.123" }"#).is_ok());
/// ```
///
pub mod datetime_utc_ts_seconds_from_any {
use super::*;
use chrono_crate::{DateTime, NaiveDateTime, Utc};
use serde::de::{Deserializer, Error, Unexpected, Visitor};
@ -61,7 +72,7 @@ pub mod datetime_utc_ts_seconds_from_any {
impl<'de> Visitor<'de> for Helper {
type Value = DateTime<Utc>;
fn expecting(&self, formatter: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.write_str("an integer, float, or string with optional subsecond precision.")
}
@ -121,7 +132,7 @@ pub mod datetime_utc_ts_seconds_from_any {
match *parts.as_slice() {
[seconds] => {
if let Ok(seconds) = i64::from_str_radix(seconds, 10) {
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))
@ -136,7 +147,7 @@ pub mod datetime_utc_ts_seconds_from_any {
}
}
[seconds, subseconds] => {
if let Ok(seconds) = i64::from_str_radix(seconds, 10) {
if let Ok(seconds) = seconds.parse() {
let subseclen = subseconds.chars().count() as u32;
if subseclen > 9 {
return Err(Error::custom(format!(
@ -145,7 +156,7 @@ pub mod datetime_utc_ts_seconds_from_any {
)));
}
if let Ok(mut subseconds) = u32::from_str_radix(subseconds, 10) {
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);
@ -229,13 +240,14 @@ where
macro_rules! use_duration_signed_ser {
(
$ty:ty =>
$main_trait:ident $internal_trait:ident =>
$source_to_dur:ident =>
$({
$format:ty, $strictness:ty =>
$($tbound:ident: $bound:path $(,)?)*
})*
{
$ty:ty; $converter:ident =>
$({
$format:ty, $strictness:ty =>
$($tbound:ident: $bound:ident $(,)?)*
})*
}
) => {
$(
impl<$($tbound ,)*> SerializeAs<$ty> for $main_trait<$format, $strictness>
@ -246,7 +258,7 @@ macro_rules! use_duration_signed_ser {
where
S: Serializer,
{
let dur: DurationSigned = $source_to_dur(source);
let dur: DurationSigned = $converter(source);
$internal_trait::<$format, $strictness>::serialize_as(
&dur,
serializer,
@ -255,56 +267,107 @@ macro_rules! use_duration_signed_ser {
}
)*
};
(
$( $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: chrono_crate::TimeZone,
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!(
Duration =>
DurationSeconds DurationSeconds =>
duration_into_duration_signed =>
{i64, STRICTNESS => STRICTNESS: Strictness}
{f64, STRICTNESS => STRICTNESS: Strictness}
{String, STRICTNESS => STRICTNESS: Strictness}
DurationSeconds DurationSeconds,
DurationMilliSeconds DurationMilliSeconds,
DurationMicroSeconds DurationMicroSeconds,
DurationNanoSeconds DurationNanoSeconds,
=> {
Duration; duration_into_duration_signed =>
{i64, STRICTNESS => STRICTNESS: Strictness}
{f64, STRICTNESS => STRICTNESS: Strictness}
{String, STRICTNESS => STRICTNESS: Strictness}
}
);
use_duration_signed_ser!(
DateTime<TZ> =>
TimestampSeconds DurationSeconds =>
datetime_to_duration =>
{i64, STRICTNESS => TZ: chrono_crate::offset::TimeZone, STRICTNESS: Strictness}
{f64, STRICTNESS => TZ: chrono_crate::offset::TimeZone, STRICTNESS: Strictness}
{String, STRICTNESS => TZ: chrono_crate::offset::TimeZone, STRICTNESS: Strictness}
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}
{String, STRICTNESS => TZ: TimeZone, STRICTNESS: Strictness}
}
);
use_duration_signed_ser!(
Duration =>
DurationSecondsWithFrac DurationSecondsWithFrac =>
duration_into_duration_signed =>
{f64, STRICTNESS => STRICTNESS: Strictness}
{String, STRICTNESS => STRICTNESS: Strictness}
TimestampSeconds DurationSeconds,
TimestampMilliSeconds DurationMilliSeconds,
TimestampMicroSeconds DurationMicroSeconds,
TimestampNanoSeconds DurationNanoSeconds,
=> {
NaiveDateTime; naive_datetime_to_duration =>
{i64, STRICTNESS => STRICTNESS: Strictness}
{f64, STRICTNESS => STRICTNESS: Strictness}
{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}
{String, STRICTNESS => STRICTNESS: Strictness}
}
);
use_duration_signed_ser!(
DateTime<TZ> =>
TimestampSecondsWithFrac DurationSecondsWithFrac =>
datetime_to_duration =>
{f64, STRICTNESS => TZ: chrono_crate::offset::TimeZone, STRICTNESS: Strictness}
{String, STRICTNESS => TZ: chrono_crate::offset::TimeZone, STRICTNESS: Strictness}
TimestampSecondsWithFrac DurationSecondsWithFrac,
TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
=> {
DateTime<TZ>; datetime_to_duration =>
{f64, STRICTNESS => TZ: TimeZone, STRICTNESS: Strictness}
{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}
{String, STRICTNESS => STRICTNESS: Strictness}
}
);
macro_rules! use_duration_signed_de {
(
$ty:ty =>
$main_trait:ident $internal_trait:ident =>
$dur_to_result:ident =>
$({
$format:ty, $strictness:ty =>
$($tbound:ident: $bound: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
@ -315,11 +378,16 @@ macro_rules! use_duration_signed_de {
D: Deserializer<'de>,
{
let dur: DurationSigned = $internal_trait::<$format, $strictness>::deserialize_as(deserializer)?;
$dur_to_result::<D>(dur)
$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>
@ -336,57 +404,113 @@ where
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!(
Duration =>
DurationSeconds DurationSeconds =>
duration_from_duration_signed =>
{i64, Strict =>}
{f64, Strict =>}
{String, Strict =>}
{FORMAT, Flexible => FORMAT: Format}
DurationSeconds DurationSeconds,
DurationMilliSeconds DurationMilliSeconds,
DurationMicroSeconds DurationMicroSeconds,
DurationNanoSeconds DurationNanoSeconds,
=> {
Duration; duration_from_duration_signed =>
{i64, Strict =>}
{f64, Strict =>}
{String, Strict =>}
{FORMAT, Flexible => FORMAT: Format}
}
);
use_duration_signed_de!(
DateTime<Utc> =>
TimestampSeconds DurationSeconds =>
duration_to_datetime_utc =>
{i64, Strict =>}
{f64, Strict =>}
{String, Strict =>}
{FORMAT, Flexible => FORMAT: Format}
TimestampSeconds DurationSeconds,
TimestampMilliSeconds DurationMilliSeconds,
TimestampMicroSeconds DurationMicroSeconds,
TimestampNanoSeconds DurationNanoSeconds,
=> {
DateTime<Utc>; duration_to_datetime_utc =>
{i64, Strict =>}
{f64, Strict =>}
{String, Strict =>}
{FORMAT, Flexible => FORMAT: Format}
}
);
use_duration_signed_de!(
DateTime<Local> =>
TimestampSeconds DurationSeconds =>
duration_to_datetime_local =>
{i64, Strict =>}
{f64, Strict =>}
{String, Strict =>}
{FORMAT, Flexible => FORMAT: Format}
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 =>}
{f64, Strict =>}
{String, Strict =>}
{FORMAT, Flexible => FORMAT: Format}
}
);
// Duration/Timestamp WITH FRACTIONS
use_duration_signed_de!(
Duration =>
DurationSecondsWithFrac DurationSecondsWithFrac =>
duration_from_duration_signed =>
{f64, Strict =>}
{String, Strict =>}
{FORMAT, Flexible => FORMAT: Format}
DurationSecondsWithFrac DurationSecondsWithFrac,
DurationMilliSecondsWithFrac DurationMilliSecondsWithFrac,
DurationMicroSecondsWithFrac DurationMicroSecondsWithFrac,
DurationNanoSecondsWithFrac DurationNanoSecondsWithFrac,
=> {
Duration; duration_from_duration_signed =>
{f64, Strict =>}
{String, Strict =>}
{FORMAT, Flexible => FORMAT: Format}
}
);
use_duration_signed_de!(
DateTime<Utc> =>
TimestampSecondsWithFrac DurationSecondsWithFrac =>
duration_to_datetime_utc =>
{f64, Strict =>}
{String, Strict =>}
{FORMAT, Flexible => FORMAT: Format}
TimestampSecondsWithFrac DurationSecondsWithFrac,
TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
=> {
DateTime<Utc>; duration_to_datetime_utc =>
{f64, Strict =>}
{String, Strict =>}
{FORMAT, Flexible => FORMAT: Format}
}
);
use_duration_signed_de!(
DateTime<Local> =>
TimestampSecondsWithFrac DurationSecondsWithFrac =>
duration_to_datetime_local =>
{f64, Strict =>}
{String, Strict =>}
{FORMAT, Flexible => FORMAT: Format}
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 =>}
{String, Strict =>}
{FORMAT, Flexible => FORMAT: Format}
}
);

5
third_party/rust/serde_with/src/content/mod.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,5 @@
//! Import of the unstable private `Content` type from `serde`.
//!
//! <https://github.com/serde-rs/serde/blob/55a7cedd737278a9d75a2efd038c6f38b8c38bd6/serde/src/private/ser.rs#L338-L997>
pub(crate) mod ser;

623
third_party/rust/serde_with/src/content/ser.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,623 @@
//! 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 alloc::{borrow::ToOwned, boxed::Box, string::String, vec::Vec};
use core::marker::PhantomData;
use serde::ser::{self, Serialize, Serializer};
#[derive(Debug)]
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 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) => {
use serde::ser::SerializeTuple;
let mut tuple = serializer.serialize_tuple(elements.len())?;
for e in elements {
tuple.serialize_element(e)?;
}
tuple.end()
}
Content::TupleStruct(n, ref fields) => {
use serde::ser::SerializeTupleStruct;
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) => {
use serde::ser::SerializeTupleVariant;
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) => {
use serde::ser::SerializeMap;
let mut map = serializer.serialize_map(Some(entries.len()))?;
for &(ref k, ref v) in entries {
map.serialize_entry(k, v)?;
}
map.end()
}
Content::Struct(n, ref fields) => {
use serde::ser::SerializeStruct;
let mut s = serializer.serialize_struct(n, fields.len())?;
for &(k, ref v) in fields {
s.serialize_field(k, v)?;
}
s.end()
}
Content::StructVariant(n, i, v, ref fields) => {
use serde::ser::SerializeStructVariant;
let mut sv = serializer.serialize_struct_variant(n, i, v, fields.len())?;
for &(k, ref 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: ser::Error,
{
type Ok = Content;
type Error = E;
type SerializeSeq = SerializeSeq<E>;
type SerializeTuple = SerializeTuple<E>;
type SerializeTupleStruct = SerializeTupleStruct<E>;
type SerializeTupleVariant = SerializeTupleVariant<E>;
type SerializeMap = SerializeMap<E>;
type SerializeStruct = SerializeStruct<E>;
type SerializeStructVariant = SerializeStructVariant<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(SerializeSeq {
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(SerializeTuple {
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(SerializeTupleStruct {
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(SerializeTupleVariant {
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(SerializeMap {
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(SerializeStruct {
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(SerializeStructVariant {
is_human_readable: self.is_human_readable,
name,
variant_index,
variant,
fields: Vec::with_capacity(len),
error: PhantomData,
})
}
}
pub(crate) struct SerializeSeq<E> {
is_human_readable: bool,
elements: Vec<Content>,
error: PhantomData<E>,
}
impl<E> ser::SerializeSeq for SerializeSeq<E>
where
E: ser::Error,
{
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 SerializeTuple<E> {
is_human_readable: bool,
elements: Vec<Content>,
error: PhantomData<E>,
}
impl<E> ser::SerializeTuple for SerializeTuple<E>
where
E: ser::Error,
{
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 SerializeTupleStruct<E> {
is_human_readable: bool,
name: &'static str,
fields: Vec<Content>,
error: PhantomData<E>,
}
impl<E> ser::SerializeTupleStruct for SerializeTupleStruct<E>
where
E: ser::Error,
{
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 SerializeTupleVariant<E> {
is_human_readable: bool,
name: &'static str,
variant_index: u32,
variant: &'static str,
fields: Vec<Content>,
error: PhantomData<E>,
}
impl<E> ser::SerializeTupleVariant for SerializeTupleVariant<E>
where
E: ser::Error,
{
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 SerializeMap<E> {
is_human_readable: bool,
entries: Vec<(Content, Content)>,
key: Option<Content>,
error: PhantomData<E>,
}
impl<E> ser::SerializeMap for SerializeMap<E>
where
E: ser::Error,
{
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 SerializeStruct<E> {
is_human_readable: bool,
name: &'static str,
fields: Vec<(&'static str, Content)>,
error: PhantomData<E>,
}
impl<E> ser::SerializeStruct for SerializeStruct<E>
where
E: ser::Error,
{
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 SerializeStructVariant<E> {
is_human_readable: bool,
name: &'static str,
variant_index: u32,
variant: &'static str,
fields: Vec<(&'static str, Content)>,
error: PhantomData<E>,
}
impl<E> ser::SerializeStructVariant for SerializeStructVariant<E>
where
E: ser::Error,
{
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,
))
}
}

338
third_party/rust/serde_with/src/de/const_arrays.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,338 @@
use super::*;
use crate::utils::{MapIter, SeqIter};
use alloc::{borrow::Cow, boxed::Box, collections::BTreeMap, string::String, vec::Vec};
use core::{convert::TryInto, fmt, mem::MaybeUninit};
use serde::de::*;
use std::collections::HashMap;
// TODO this should probably be moved into the utils module when const generics are available for MSRV
/// # 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>
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: Error,
{
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
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(Error::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) })
}
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>,
{
array_from_iterator(
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))
}
}
macro_rules! tuple_seq_as_map_impl_intern {
($tyorig:ty, $ty:ident <KAs, VAs>) => {
#[allow(clippy::implicit_hasher)]
impl<'de, K, KAs, V, VAs, const N: usize> DeserializeAs<'de, $tyorig> for $ty<KAs, VAs>
where
KAs: DeserializeAs<'de, K>,
VAs: DeserializeAs<'de, V>,
{
fn deserialize_as<D>(deserializer: D) -> Result<$tyorig, 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>,
{
array_from_iterator(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_impl_intern!([(K, V); N], BTreeMap<KAs, VAs>);
tuple_seq_as_map_impl_intern!([(K, V); N], HashMap<KAs, VAs>);
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>,
{
array_from_iterator(SeqIter::new(seq), &self)
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: Error,
{
v.try_into()
.map_err(|_| Error::invalid_length(v.len(), &self))
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: Error,
{
v.as_bytes()
.try_into()
.map_err(|_| Error::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: Error,
{
v.try_into()
.map_err(|_| Error::invalid_length(v.len(), &self))
}
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
where
E: Error,
{
v.as_bytes()
.try_into()
.map_err(|_| Error::invalid_length(v.len(), &self))
}
}
deserializer.deserialize_bytes(ArrayVisitor::<N>)
}
}
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: Error,
{
Ok(Cow::Borrowed(
v.try_into()
.map_err(|_| Error::invalid_length(v.len(), &self))?,
))
}
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
where
E: Error,
{
Ok(Cow::Borrowed(
v.as_bytes()
.try_into()
.map_err(|_| Error::invalid_length(v.len(), &self))?,
))
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: Error,
{
Ok(Cow::Owned(
v.to_vec()
.try_into()
.map_err(|_| Error::invalid_length(v.len(), &self))?,
))
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: Error,
{
Ok(Cow::Owned(
v.as_bytes()
.to_vec()
.try_into()
.map_err(|_| Error::invalid_length(v.len(), &self))?,
))
}
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
where
E: Error,
{
let len = v.len();
Ok(Cow::Owned(
v.try_into()
.map_err(|_| Error::invalid_length(len, &self))?,
))
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: Error,
{
let len = v.len();
Ok(Cow::Owned(
v.into_bytes()
.try_into()
.map_err(|_| Error::invalid_length(len, &self))?,
))
}
fn visit_seq<V>(self, seq: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
Ok(Cow::Owned(array_from_iterator(SeqIter::new(seq), &self)?))
}
}
deserializer.deserialize_bytes(CowVisitor)
}
}
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)
}
}
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)
}
}

1022
third_party/rust/serde_with/src/de/impls.rs поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

85
third_party/rust/serde_with/src/de/legacy_arrays.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,85 @@
use super::*;
use core::fmt;
use serde::de::*;
macro_rules! array_impl {
($len:literal $($idx:tt)*) => {
impl<'de, T, As> DeserializeAs<'de, [T; $len]> for [As; $len]
where
As: DeserializeAs<'de, T>,
{
fn deserialize_as<D>(deserializer: D) -> Result<[T; $len], D::Error>
where
D: Deserializer<'de>,
{
struct ArrayVisitor<T>(PhantomData<T>);
impl<'de, T, As> Visitor<'de>
for ArrayVisitor<DeserializeAsWrap<T, As>>
where
As: DeserializeAs<'de, T>,
{
type Value = [T; $len];
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(concat!("an array of size ", $len))
}
#[allow(non_snake_case)]
// Because of 0-size arrays
#[allow(unused_variables, unused_mut)]
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
Ok([$(
match seq.next_element::<DeserializeAsWrap<T, As>>()? {
Some(value) => value.into_inner(),
None => return Err(Error::invalid_length($idx, &self)),
},
)*])
}
}
deserializer.deserialize_tuple(
$len,
ArrayVisitor::<DeserializeAsWrap<T, As>>(PhantomData),
)
}
}
};
}
array_impl!(0);
array_impl!(1 0);
array_impl!(2 0 1);
array_impl!(3 0 1 2);
array_impl!(4 0 1 2 3);
array_impl!(5 0 1 2 3 4);
array_impl!(6 0 1 2 3 4 5);
array_impl!(7 0 1 2 3 4 5 6);
array_impl!(8 0 1 2 3 4 5 6 7);
array_impl!(9 0 1 2 3 4 5 6 7 8);
array_impl!(10 0 1 2 3 4 5 6 7 8 9);
array_impl!(11 0 1 2 3 4 5 6 7 8 9 10);
array_impl!(12 0 1 2 3 4 5 6 7 8 9 10 11);
array_impl!(13 0 1 2 3 4 5 6 7 8 9 10 11 12);
array_impl!(14 0 1 2 3 4 5 6 7 8 9 10 11 12 13);
array_impl!(15 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14);
array_impl!(16 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15);
array_impl!(17 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16);
array_impl!(18 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17);
array_impl!(19 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18);
array_impl!(20 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19);
array_impl!(21 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20);
array_impl!(22 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21);
array_impl!(23 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22);
array_impl!(24 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23);
array_impl!(25 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);
array_impl!(26 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);
array_impl!(27 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);
array_impl!(28 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);
array_impl!(29 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);
array_impl!(30 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);
array_impl!(31 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);
array_impl!(32 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);

9
third_party/rust/serde_with/src/de/mod.rs поставляемый
Просмотреть файл

@ -7,7 +7,8 @@
//!
//! [user guide]: crate::guide
pub(crate) mod impls;
mod const_arrays;
mod impls;
use super::*;
@ -20,7 +21,7 @@ use super::*;
/// # 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`][].
/// 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.
///
@ -99,9 +100,11 @@ use super::*;
/// # 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.
@ -117,7 +120,7 @@ pub struct DeserializeAsWrap<T, U> {
marker: PhantomData<U>,
}
impl<'de, T, U> DeserializeAsWrap<T, U> {
impl<T, U> DeserializeAsWrap<T, U> {
/// Return the inner value of type `T`.
pub fn into_inner(self) -> T {
self.value

Просмотреть файл

@ -1,7 +1,8 @@
use std::{
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
hash::{BuildHasher, Hash},
};
use alloc::collections::{BTreeMap, BTreeSet};
use core::hash::{BuildHasher, Hash};
#[cfg(feature = "indexmap")]
use indexmap_crate::{IndexMap, IndexSet};
use std::collections::{HashMap, HashSet};
pub trait PreventDuplicateInsertsSet<T> {
fn new(size_hint: Option<usize>) -> Self;
@ -36,6 +37,26 @@ where
}
}
#[cfg(feature = "indexmap")]
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,
@ -70,6 +91,26 @@ where
}
}
#[cfg(feature = "indexmap")]
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,

Просмотреть файл

@ -1,7 +1,8 @@
use std::{
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
hash::{BuildHasher, Hash},
};
use alloc::collections::{BTreeMap, BTreeSet};
use core::hash::{BuildHasher, Hash};
#[cfg(feature = "indexmap")]
use indexmap_crate::IndexMap;
use std::collections::{HashMap, HashSet};
#[deprecated = "This is serde's default behavior."]
pub trait DuplicateInsertsFirstWinsSet<T> {
@ -83,6 +84,34 @@ where
}
}
#[cfg(feature = "indexmap")]
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_crate::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,
@ -94,7 +123,7 @@ where
#[inline]
fn insert(&mut self, key: K, value: V) {
use std::collections::btree_map::Entry;
use alloc::collections::btree_map::Entry;
match self.entry(key) {
// we want to keep the first value, so do nothing

Просмотреть файл

@ -1,7 +1,8 @@
use std::{
collections::{BTreeSet, HashSet},
hash::{BuildHasher, Hash},
};
use alloc::collections::BTreeSet;
use core::hash::{BuildHasher, Hash};
#[cfg(feature = "indexmap")]
use indexmap_crate::IndexSet;
use std::collections::HashSet;
pub trait DuplicateInsertsLastWinsSet<T> {
fn new(size_hint: Option<usize>) -> Self;
@ -30,6 +31,27 @@ where
}
}
#[cfg(feature = "indexmap")]
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,

888
third_party/rust/serde_with/src/enum_map.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,888 @@
use crate::{
content::ser::{Content, ContentSerializer},
DeserializeAs, SerializeAs,
};
use alloc::{string::ToString, vec::Vec};
use core::{fmt, marker::PhantomData};
use serde::{
de::{DeserializeSeed, EnumAccess, Error, MapAccess, SeqAccess, VariantAccess, Visitor},
ser,
ser::{Impossible, SerializeMap, SerializeSeq, SerializeStructVariant, SerializeTupleVariant},
Deserialize, Deserializer, Serialize, Serializer,
};
/// 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::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_with::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::EnumMap;
///
/// # #[derive(Debug, Clone, PartialEq, Eq)]
/// #[derive(Serialize, Deserialize)]
/// enum EnumValue {
/// Int(i32),
/// String(String),
/// Unit,
/// }
///
/// #[serde_with::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#"
/// <VecEnumValues>
/// <vec>
/// <Int>123</Int>
/// <String>FooBar</String>
/// <Int>456</Int>
/// <String>XXX</String>
/// <Unit></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);
/// # }
/// ```
#[derive(Debug, Copy, Clone)]
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>(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 or enum values")
}
fn visit_map<A: MapAccess<'de>>(self, map: A) -> Result<Self::Value, A::Error> {
Vec::deserialize(SeqDeserializer(map))
}
}
deserializer.deserialize_map(EnumMapVisitor(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 serialize_bool(self, _v: bool) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_i8(self, _v: i8) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_i16(self, _v: i16) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_i32(self, _v: i32) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_i64(self, _v: i64) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_i128(self, _v: i128) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_u8(self, _v: u8) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_u16(self, _v: u16) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_u32(self, _v: u32) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_u64(self, _v: u64) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_u128(self, _v: u128) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_f32(self, _v: f32) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_f64(self, _v: f64) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_char(self, _v: char) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_str(self, _v: &str) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_bytes(self, _v: &[u8]) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<Self::Ok, Self::Error>
where
T: Serialize,
{
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::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(ser::Error::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(ser::Error::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(ser::Error::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(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_tuple_struct(
self,
_name: &'static str,
_len: usize,
) -> Result<Self::SerializeTupleStruct, Self::Error> {
Err(ser::Error::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(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_struct(
self,
_name: &'static str,
_len: usize,
) -> Result<Self::SerializeStruct, Self::Error> {
Err(ser::Error::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(ser::Error::custom("wrong type for EnumMap"))
}
}
/// Serialize a single element but turn the sequence into a map logic.
///
/// It uses [`SerializeEnumAsMapElement`] 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 serialize_bool(self, _v: bool) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_i8(self, _v: i8) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_i16(self, _v: i16) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_i32(self, _v: i32) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_i64(self, _v: i64) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_i128(self, _v: i128) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_u8(self, _v: u8) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_u16(self, _v: u16) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_u32(self, _v: u32) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_u64(self, _v: u64) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_u128(self, _v: u128) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_f32(self, _v: f32) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_f64(self, _v: f64) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_char(self, _v: char) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_str(self, _v: &str) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_bytes(self, _v: &[u8]) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<Self::Ok, Self::Error>
where
T: Serialize,
{
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
Err(ser::Error::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(ser::Error::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(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
Err(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_tuple_struct(
self,
_name: &'static str,
_len: usize,
) -> Result<Self::SerializeTupleStruct, Self::Error> {
Err(ser::Error::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(ser::Error::custom("wrong type for EnumMap"))
}
fn serialize_struct(
self,
_name: &'static str,
_len: usize,
) -> Result<Self::SerializeStruct, Self::Error> {
Err(ser::Error::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>(M);
impl<'de, M> Deserializer<'de> for SeqDeserializer<M>
where
M: MapAccess<'de>,
{
type Error = M::Error;
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>,
{
match seed.deserialize(EnumDeserializer(&mut self.0)) {
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.0.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>(M);
impl<'de, M> Deserializer<'de> for EnumDeserializer<M>
where
M: MapAccess<'de>,
{
type Error = M::Error;
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.0.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(Error::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.0.next_value()
}
fn newtype_variant_seed<T>(mut self, seed: T) -> Result<T::Value, Self::Error>
where
T: DeserializeSeed<'de>,
{
self.0.next_value_seed(seed)
}
fn tuple_variant<V>(mut self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.0.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.0.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)
}
}

Просмотреть файл

@ -9,10 +9,6 @@
/// required on the field such that the helper works. The serialization format will always be
/// flattened.
///
/// **Note**:
/// This macro requires that the crate `serde_with` is in scope with that exact name.
/// If you import `serde_with` with a different name, you need to temporarily rename it for this macro to work.
///
/// # Examples
///
/// ```rust
@ -34,7 +30,6 @@
/// // 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} "#;
@ -55,20 +50,20 @@
/// ```
#[macro_export]
macro_rules! flattened_maybe {
// TODO Change $field to literal, once the compiler version is bumped enough.
($fn:ident, $field:expr) => {
($fn:ident, $field:literal) => {
fn $fn<'de, T, D>(deserializer: D) -> ::std::result::Result<T, D::Error>
where
T: serde_with::serde::Deserialize<'de>,
D: serde_with::serde::Deserializer<'de>,
T: $crate::serde::Deserialize<'de>,
D: $crate::serde::Deserializer<'de>,
{
use ::std::{
option::Option::{self, None, Some},
result::Result::{self, Err, Ok},
};
use $crate::serde;
#[derive(serde_with::serde::Deserialize)]
#[serde(crate = "serde_with::serde")]
#[derive($crate::serde::Deserialize)]
#[serde(crate = "serde")]
pub struct Both<T> {
#[serde(flatten)]
flat: Option<T>,
@ -76,11 +71,11 @@ macro_rules! flattened_maybe {
not_flat: Option<T>,
}
let both: Both<T> = serde_with::serde::Deserialize::deserialize(deserializer)?;
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(serde_with::serde::de::Error::missing_field($field)),
(Some(_), Some(_)) => Err(serde_with::serde::de::Error::custom(concat!(
(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"

12
third_party/rust/serde_with/src/formats.rs поставляемый
Просмотреть файл

@ -1,5 +1,7 @@
//! Specify the format and how lenient the deserialization is
use alloc::string::String;
/// Specify how to serialize/deserialize a type
///
/// The format specifier allows to configure how a value is serialized/deserialized.
@ -66,6 +68,16 @@ create_format!(
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

20
third_party/rust/serde_with/src/guide.md поставляемый
Просмотреть файл

@ -1,9 +1,11 @@
# `serde_with` User Guide
This crate provides helper functions to extend and change how [`serde`] serializes different datatypes.
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` *(v1.5.0+)*
@ -18,7 +20,7 @@ The `serde_as` scheme is based on two new traits: [`SerializeAs`] and [`Deserial
### Example
```rust
# use serde_derive::{Deserialize, Serialize};
# use serde::{Deserialize, Serialize};
# use serde_with::{serde_as, DisplayFromStr};
# use std::collections::HashMap;
# use std::net::Ipv4Addr;
@ -62,12 +64,12 @@ assert_eq!(data, serde_json::from_str(json).unwrap());
## 2. Integration with serde's with-annotation
[serde's with-annotation][with-annotation] allows to specify a different serialization or deserialization function for a field.
It is usefull to adapt the serialization of existing types to the requirements of a protocol.
[serde's with-annotation][with-annotation] allows specifying a different serialization or deserialization function for a field.
It is useful to adapt the serialization of existing types to the requirements of a protocol.
Most modules in this crate can be used together with the with-annotation.
The annotation approach has one big drawback, in that it is very inflexible.
It allows to specify arbitrary serialization code, but the code has to perform the correct transformations.
It allows specifying arbitrary serialization code, but the code has to perform the correct transformations.
It is not possible to combine multiple of those functions.
One common use case for this is the serialization of collections like `Vec`.
If you have a field of type `T`, you can apply the with-annotation, but if you have a field of type `Vec<T>`, there is no way to re-use the same functions for the with-annotation.
@ -78,7 +80,7 @@ The example shows a similar setup as in the `serde_as` example above, but using
### Example
```rust
# use serde_derive::{Deserialize, Serialize};
# use serde::{Deserialize, Serialize};
# use std::net::Ipv4Addr;
#
# #[derive(Debug, PartialEq, Eq)]
@ -118,16 +120,16 @@ assert_eq!(data, serde_json::from_str(json).unwrap());
## 3. proc-macros to make it easier to use both above parts
The proc-macros are an optional addition and improve the user exerience for common tasks.
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 futher details, please refer to the documentation of each proc-macro.
For further details, please refer to the documentation of each proc-macro.
## 4. 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.
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.
## Migrating from the with-annotations to `serde_as`

Просмотреть файл

@ -3,11 +3,20 @@
This crate has the following features which can be enabled.
Each entry will explain the feature in more detail.
1. [`chrono`](#chrono)
2. [`guide`](#guide)
3. [`hex`](#hex)
4. [`json`](#json)
5. [`macros`](#macros)
1. [`base64`](#base64)
2. [`chrono`](#chrono)
3. [`guide`](#guide)
4. [`hex`](#hex)
5. [`indexmap`](#indexmap)
6. [`json`](#json)
7. [`macros`](#macros)
8. [`time_0_3`](#time_0_3)
## `base64`
The `base64` feature enables serializing data in base64 format.
This pulls in `base64` as a dependency.
## `chrono`
@ -27,6 +36,11 @@ The `hex` feature enables serializing data in hex format.
This pulls in `hex` as a dependency.
## `indexmap`
The `indexmap` feature enables implementations of `indexmap` specific checks.
This includes support for checking duplicate keys
## `json`
The `json` features enables JSON conversions from the `json` module.
@ -39,3 +53,10 @@ 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.

Просмотреть файл

@ -1,36 +1,26 @@
# `serde_as` Annotation
This is an alternative to serde's with-annotation.
It is more flexible and composable but work with fewer types.
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 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 site contains some general advice how to use this crate and then lists the implemented conversions for `serde_as`.
The basic design of the system was done 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. [Implementing `SerializeAs` / `DeserializeAs`](#implementing-serializeas--deserializeas)
3. [Using `#[serde_as]` on types without `SerializeAs` and `Serialize` implementations](#using-serde_as-on-types-without-serializeas-and-serialize-implementations)
4. [Using `#[serde_as]` with serde's remote derives](#using-serde_as-with-serdes-remote-derives)
5. [Re-exporting `serde_as`](#re-exporting-serde_as)
2. [De/Serialize Implementations Available](#deserialize-implementations-available)
1. [Bytes / `Vec<u8>` to hex string](#bytes--vecu8-to-hex-string)
2. [`Default` from `null`](#default-from-null)
3. [De/Serialize with `FromStr` and `Display`](#deserialize-with-fromstr-and-display)
4. [`Duration` as seconds](#duration-as-seconds)
5. [Ignore deserialization errors](#ignore-deserialization-errors)
6. [`Maps` to `Vec` of tuples](#maps-to-vec-of-tuples)
7. [`NaiveDateTime` like UTC timestamp](#naivedatetime-like-utc-timestamp)
8. [`None` as empty `String`](#none-as-empty-string)
9. [Timestamps as seconds since UNIX epoch](#timestamps-as-seconds-since-unix-epoch)
10. [Value into JSON String](#value-into-json-string)
11. [`Vec` of tuples to `Maps`](#vec-of-tuples-to-maps)
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
For the user, the main difference is that instead of
```rust,ignore
#[serde(with = "...")]
@ -45,7 +35,7 @@ you now have to write
and place the `#[serde_as]` attribute *before* the `#[derive]` attribute.
You still need the `#[derive(Serialize, Deserialize)]` on the struct/enum.
All together this looks like:
All together, this looks like:
```rust
use serde::{Deserialize, Serialize};
@ -59,7 +49,7 @@ struct A {
}
```
The main advantage is that you can compose `serde_as` stuff, which is not possible with the with-annotation.
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
@ -77,7 +67,7 @@ struct A {
### Deserializing Optional Fields
During deserialization serde treats fields of `Option<T>` as optional and does not require them to be present.
During deserialization, serde treats fields of `Option<T>` as optional and does not require them to be present.
This breaks when adding either the `serde_as` annotation or serde's `with` annotation.
The default behavior can be restored by adding serde's `default` attribute.
@ -95,18 +85,55 @@ struct A {
}
```
In the future this behavior might change and `default` would be applied on `Option<T>` fields.
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].
### Implementing `SerializeAs` / `DeserializeAs`
### 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.
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 they key/value de/serialization such that the conversions can be done on the key/values.
[`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
@ -118,7 +145,7 @@ We assume we have a module containing a `serialize` and a `deserialize` function
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.
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)] {
@ -137,7 +164,7 @@ This allows it to seamlessly work with types from dependencies without running i
```rust
# #[cfg(FALSE)] {
struct Localtype;
struct LocalType;
impl SerializeAs<RemoteType> for LocalType {
fn serialize_as<S>(value: &RemoteType, serializer: S) -> Result<S::Ok, S::Error>
@ -147,12 +174,21 @@ impl SerializeAs<RemoteType> for LocalType {
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`.
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
@ -169,7 +205,7 @@ struct Data {
### 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`.
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
@ -200,8 +236,8 @@ struct DurationDef {
# }
```
Our goal is it now to use `Duration` within `serde_as`.
We make use of the existing `DurationDef` type and its `serialize` and `deserialize` functions.
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.
@ -233,7 +269,7 @@ struct Data {
# }
```
### Re-exporting `serde_as`
## 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
@ -276,7 +312,7 @@ pub use serde_with;
pub use some_other_lib_derive::define_some_type;
```
And the procedural macro can be used by other crates without any additional imports:
The procedural macro can be used by other crates without any additional imports:
```rust,ignore
// consuming_crate/src/main.rs
@ -284,236 +320,13 @@ And the procedural macro can be used by other crates without any additional impo
some_other_lib::define_some_type!();
```
## De/Serialize Implementations Available
### Bytes / `Vec<u8>` to hex string
[`Hex`]
Requires the `hex` feature.
```ignore
// Rust
#[serde_as(as = "serde_with::hex::Hex")]
value: Vec<u8>,
// JSON
"value": "deadbeef",
```
### `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 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.
### Ignore deserialization errors
Check the documentation for [`DefaultOnError`].
### `Maps` to `Vec` of tuples
```ignore
// Rust
#[serde_as(as = "Vec<(_, _)>")]
value: HashMap<String, u32>, // also works with BTreeMap
// 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
```
### 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>`] and [`chrono::DateTime<Local>`] with the `chrono` feature.
### 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}",
```
### `Vec` of tuples to `Maps`
```ignore
// Rust
#[serde_as(as = "HashMap<_, _>")] // also works with BTreeMap
value: Vec<(String, u32)>,
// JSON
"value": {
"hello": 1,
"world": 2
},
```
The [inverse operation](#maps-to-vec-of-tuples) is also available.
[`chrono::DateTime<Local>`]: chrono_crate::DateTime
[`chrono::DateTime<Utc>`]: chrono_crate::DateTime
[`chrono::Duration`]: https://docs.rs/chrono/latest/chrono/struct.Duration.html
[`DefaultOnError`]: crate::DefaultOnError
[`DefaultOnNull`]: crate::DefaultOnNull
[`DeserializeAs`]: crate::DeserializeAs
[`DisplayFromStr`]: crate::DisplayFromStr
[`DurationSeconds`]: crate::DurationSeconds
[`DurationSecondsWithFrac`]: crate::DurationSecondsWithFrac
[`Hex`]: crate::hex::Hex
[`JsonString`]: crate::json::JsonString
[`NoneAsEmptyString`]: crate::NoneAsEmptyString
[`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
[`serde`'s own `crate` argument]: https://serde.rs/container-attrs.html#crate

Просмотреть файл

@ -0,0 +1,518 @@
# 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. [Pick first successful deserialization](#pick-first-successful-deserialization)
20. [Timestamps as seconds since UNIX epoch](#timestamps-as-seconds-since-unix-epoch)
21. [Value into JSON String](#value-into-json-string)
22. [`Vec` of tuples to `Maps`](#vec-of-tuples-to-maps)
23. [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 = "Vec<(_, _)>")]
value: HashMap<String, u32>, // also works with BTreeMap
// 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
```
## 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",
```
## 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 availble 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}",
```
## `Vec` of tuples to `Maps`
```ignore
// Rust
#[serde_as(as = "HashMap<_, _>")] // also works with BTreeMap
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.
Two formats are supported, [`time::format_description::well_known::Rfc2822`] and [`time::format_description::well_known::Rfc3339`].
```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,
// JSON
"rfc_2822": "Fri, 21 Nov 1997 09:55:06 -0600",
"rfc_3339": "1997-11-21T09:55:06-06:00",
```
These conversions are availble 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_crate::DateTime
[`chrono::DateTime<Utc>`]: chrono_crate::DateTime
[`chrono::Duration`]: https://docs.rs/chrono/latest/chrono/struct.Duration.html
[`chrono::NaiveDateTime`]: chrono_crate::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
[`NoneAsEmptyString`]: crate::NoneAsEmptyString
[`OneOrMany`]: crate::OneOrMany
[`PickFirst`]: crate::PickFirst
[`time::Duration`]: time_0_3::Duration
[`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

75
third_party/rust/serde_with/src/hex.rs поставляемый
Просмотреть файл

@ -1,19 +1,25 @@
//! 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::{
de::DeserializeAs,
formats::{Format, Lowercase, Uppercase},
ser::SerializeAs,
};
use alloc::{borrow::Cow, format, vec::Vec};
use core::{
convert::{TryFrom, TryInto},
marker::PhantomData,
};
use serde::{de::Error, Deserialize, Deserializer, Serializer};
use std::{borrow::Cow, marker::PhantomData};
/// 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 `From<Vec<u8>>` for deserialization.
/// 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 [`Lowercase`] and [`Uppercase`].
@ -22,9 +28,8 @@ use std::{borrow::Cow, marker::PhantomData};
/// # Example
///
/// ```rust
///
/// # #[cfg(feature = "macros")] {
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde::{Deserialize, Serialize};
/// # use serde_json::json;
/// # use serde_with::serde_as;
/// #
@ -48,13 +53,55 @@ use std::{borrow::Cow, marker::PhantomData};
/// let b = b"Hello World!";
///
/// // Hex with lowercase letters
/// assert_eq!(json!("48656c6c6f20576f726c6421"), serde_json::to_value(BytesLowercase(b.to_vec())).unwrap());
/// 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());
/// 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());
/// 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();
/// # }
/// ```
#[derive(Copy, Clone, Debug, Default)]
@ -86,7 +133,7 @@ where
impl<'de, T, FORMAT> DeserializeAs<'de, T> for Hex<FORMAT>
where
T: From<Vec<u8>>,
T: TryFrom<Vec<u8>>,
FORMAT: Format,
{
fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
@ -95,6 +142,14 @@ where
{
<Cow<'de, str> as Deserialize<'de>>::deserialize(deserializer)
.and_then(|s| hex::decode(&*s).map_err(Error::custom))
.map(Into::into)
.and_then(|vec: Vec<u8>| {
let length = vec.len();
vec.try_into().map_err(|_e: T::Error| {
Error::custom(format!(
"Can't convert a Byte Vector of length {} to the output type.",
length
))
})
})
}
}

16
third_party/rust/serde_with/src/json.rs поставляемый
Просмотреть файл

@ -12,7 +12,7 @@ use serde::{de::DeserializeOwned, Deserializer, Serialize, Serializer};
/// # Examples
///
/// ```
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde::{Deserialize, Serialize};
/// #
/// #[derive(Deserialize, Serialize)]
/// struct A {
@ -30,14 +30,17 @@ use serde::{de::DeserializeOwned, Deserializer, Serialize, Serializer};
/// let x = A {
/// other_struct: B { value: 10 },
/// };
/// assert_eq!(r#"{"other_struct":"{\"value\":10}"}"#, serde_json::to_string(&x).unwrap());
/// assert_eq!(
/// r#"{"other_struct":"{\"value\":10}"}"#,
/// serde_json::to_string(&x).unwrap()
/// );
/// ```
pub mod nested {
use core::{fmt, marker::PhantomData};
use serde::{
de::{DeserializeOwned, Deserializer, Error, Visitor},
ser::{self, Serialize, Serializer},
};
use std::{fmt, marker::PhantomData};
/// Deserialize value from a string which is valid JSON
pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
@ -93,7 +96,7 @@ pub mod nested {
///
/// ```
/// # #[cfg(feature = "macros")] {
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde::{Deserialize, Serialize};
/// # use serde_with::{serde_as, json::JsonString};
/// #
/// #[serde_as]
@ -113,7 +116,10 @@ pub mod nested {
/// let x = A {
/// other_struct: B { value: 10 },
/// };
/// assert_eq!(r#"{"other_struct":"{\"value\":10}"}"#, serde_json::to_string(&x).unwrap());
/// assert_eq!(
/// r#"{"other_struct":"{\"value\":10}"}"#,
/// serde_json::to_string(&x).unwrap()
/// );
/// # }
/// ```
#[derive(Copy, Clone, Debug, Default)]

871
third_party/rust/serde_with/src/lib.rs поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

500
third_party/rust/serde_with/src/rust.rs поставляемый
Просмотреть файл

@ -1,23 +1,30 @@
//! De/Serialization for Rust's builtin and std types
use crate::Separator;
use serde::{
de::{Deserialize, DeserializeOwned, Deserializer, Error, MapAccess, SeqAccess, Visitor},
ser::{Serialize, SerializeMap, SerializeSeq, Serializer},
use crate::{utils, Separator};
#[cfg(doc)]
use alloc::collections::BTreeMap;
use alloc::{
string::{String, ToString},
vec::Vec,
};
use std::{
use core::{
cmp::Eq,
collections::{BTreeMap, HashMap},
fmt::{self, Display},
hash::{BuildHasher, Hash},
hash::Hash,
iter::FromIterator,
marker::PhantomData,
str::FromStr,
};
use serde::{
de::{Deserialize, DeserializeOwned, Deserializer, Error, MapAccess, SeqAccess, Visitor},
ser::{Serialize, Serializer},
};
#[cfg(doc)]
use std::collections::HashMap;
/// De/Serialize using [`Display`] and [`FromStr`] implementation
///
/// This allows to deserialize a string as a number.
/// 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.
///
@ -30,7 +37,7 @@ use std::{
///
/// ```rust
/// # #[cfg(feature = "macros")] {
/// # use serde_derive::Deserialize;
/// # use serde::Deserialize;
/// # use serde_with::{serde_as, DisplayFromStr};
/// #
/// #[serde_as]
@ -45,7 +52,7 @@ use std::{
/// # Examples
///
/// ```rust
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde::{Deserialize, Serialize};
/// #
/// #[derive(Deserialize, Serialize)]
/// struct A {
@ -66,7 +73,10 @@ use std::{
/// mime: mime::STAR_STAR,
/// number: 777,
/// };
/// assert_eq!(r#"{"mime":"*/*","number":"777"}"#, serde_json::to_string(&x).unwrap());
/// assert_eq!(
/// r#"{"mime":"*/*","number":"777"}"#,
/// serde_json::to_string(&x).unwrap()
/// );
/// ```
///
/// [`DeserializeFromStr`]: serde_with_macros::DeserializeFromStr
@ -75,7 +85,6 @@ use std::{
/// [`SerializeDisplay`]: serde_with_macros::SerializeDisplay
pub mod display_fromstr {
use super::*;
use std::str::FromStr;
/// Deserialize T using [`FromStr`]
pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
@ -114,7 +123,7 @@ pub mod display_fromstr {
T: Display,
S: Serializer,
{
serializer.serialize_str(&*value.to_string())
serializer.collect_str(&value)
}
}
@ -146,7 +155,7 @@ pub mod display_fromstr {
/// # Examples
///
/// ```
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde::{Deserialize, Serialize};
/// #
/// use std::collections::BTreeSet;
/// use std::net::Ipv4Addr;
@ -179,22 +188,16 @@ pub mod display_fromstr {
/// ].into_iter().collect(),
/// bs: vec![false, true],
/// };
/// assert_eq!(r#"{"addresses":["127.53.0.1","127.53.0.2","127.53.1.1"],"bs":["false","true"]}"#, serde_json::to_string(&x).unwrap());
/// assert_eq!(
/// r#"{"addresses":["127.53.0.1","127.53.0.2","127.53.1.1"],"bs":["false","true"]}"#,
/// serde_json::to_string(&x).unwrap()
/// );
/// ```
///
/// [`DisplayFromStr`]: crate::DisplayFromStr
/// [`serde_as`]: crate::guide::serde_as
pub mod seq_display_fromstr {
use serde::{
de::{Deserializer, Error, SeqAccess, Visitor},
ser::{SerializeSeq, Serializer},
};
use std::{
fmt::{self, Display},
iter::{FromIterator, IntoIterator},
marker::PhantomData,
str::FromStr,
};
use super::*;
/// Deserialize collection T using [FromIterator] and [FromStr] for each element
pub fn deserialize<'de, D, T, I>(deserializer: D) -> Result<T, D::Error>
@ -217,20 +220,15 @@ pub mod seq_display_fromstr {
write!(formatter, "a sequence")
}
fn visit_seq<A>(self, mut access: A) -> Result<Self::Value, A::Error>
fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut values = access
.size_hint()
.map(Self::Value::with_capacity)
.unwrap_or_else(Self::Value::new);
while let Some(value) = access.next_element::<&str>()? {
values.push(value.parse::<S>().map_err(Error::custom)?);
}
Ok(values)
utils::SeqIter::new(seq)
.map(|res| {
res.and_then(|value: &str| value.parse::<S>().map_err(Error::custom))
})
.collect()
}
}
@ -246,13 +244,21 @@ pub mod seq_display_fromstr {
for<'a> &'a T: IntoIterator<Item = &'a I>,
I: Display,
{
let iter = value.into_iter();
let (_, to) = iter.size_hint();
let mut seq = serializer.serialize_seq(to)?;
for item in iter {
seq.serialize_element(&item.to_string())?;
struct SerializeString<'a, I>(&'a I);
impl<'a, I> Serialize for SerializeString<'a, I>
where
I: Display,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.collect_str(self.0)
}
}
seq.end()
serializer.collect_seq(value.into_iter().map(SerializeString))
}
}
@ -271,7 +277,7 @@ pub mod seq_display_fromstr {
///
/// ```rust
/// # #[cfg(feature = "macros")] {
/// # use serde_derive::Deserialize;
/// # use serde::Deserialize;
/// # use serde_with::{serde_as, SpaceSeparator, StringWithSeparator};
/// #
/// #[serde_as]
@ -286,7 +292,7 @@ pub mod seq_display_fromstr {
/// # Examples
///
/// ```
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde::{Deserialize, Serialize};
/// #
/// use serde_with::{CommaSeparator, SpaceSeparator};
/// use std::collections::BTreeSet;
@ -310,7 +316,10 @@ pub mod seq_display_fromstr {
/// 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());
/// assert_eq!(
/// r#"{"tags":"1 2 3","more_tags":""}"#,
/// serde_json::to_string(&x).unwrap()
/// );
/// ```
///
/// [`serde_as`]: crate::guide::serde_as
@ -375,7 +384,7 @@ where
/// # Examples
///
/// ```rust
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde::{Deserialize, Serialize};
/// #
/// # #[derive(Debug, PartialEq, Eq)]
/// #[derive(Deserialize, Serialize)]
@ -389,18 +398,18 @@ where
/// }
/// // 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());
/// 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());
/// 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());
/// 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 {
@ -446,7 +455,7 @@ pub mod double_option {
/// # Example
///
/// ```rust
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde::{Deserialize, Serialize};
/// #
/// # #[derive(Debug, Eq, PartialEq)]
/// #[derive(Deserialize, Serialize)]
@ -462,7 +471,7 @@ pub mod double_option {
///
/// // Transparently add/remove Some() wrapper
/// # let pretty_config = ron::ser::PrettyConfig::new()
/// # .with_new_line("\n".into());
/// # .new_line("\n".into());
/// let s = r#"(
/// mandatory: 1,
/// optional: 2,
@ -477,7 +486,7 @@ pub mod double_option {
/// // Missing values are deserialized as `None`
/// // while `None` values are skipped during serialization.
/// # let pretty_config = ron::ser::PrettyConfig::new()
/// # .with_new_line("\n".into());
/// # .new_line("\n".into());
/// let s = r#"(
/// mandatory: 1,
/// )"#;
@ -531,7 +540,7 @@ pub mod unwrap_or_skip {
///
/// ```rust
/// # use std::{collections::HashSet, iter::FromIterator};
/// # use serde_derive::Deserialize;
/// # use serde::Deserialize;
/// #
/// # #[derive(Debug, Eq, PartialEq)]
/// #[derive(Deserialize)]
@ -629,7 +638,7 @@ pub mod sets_duplicate_value_is_error {
/// # Example
///
/// ```rust
/// # use serde_derive::Deserialize;
/// # use serde::Deserialize;
/// # use std::collections::HashMap;
/// #
/// # #[derive(Debug, Eq, PartialEq)]
@ -866,7 +875,7 @@ pub mod sets_last_value_wins {
/// # Example
///
/// ```rust
/// # use serde_derive::Deserialize;
/// # use serde::Deserialize;
/// # use std::collections::HashMap;
/// #
/// # #[derive(Debug, Eq, PartialEq)]
@ -958,9 +967,9 @@ pub mod maps_first_key_wins {
}
}
/// De/Serialize a [`Option`]`<`[`String`]`>` type while transforming the empty string to [`None`]
/// 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.
/// 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.
///
/// ## Converting to `serde_as`
@ -969,7 +978,7 @@ pub mod maps_first_key_wins {
///
/// ```rust
/// # #[cfg(feature = "macros")] {
/// # use serde_derive::Deserialize;
/// # use serde::Deserialize;
/// # use serde_with::{serde_as, NoneAsEmptyString};
/// #
/// #[serde_as]
@ -984,7 +993,7 @@ pub mod maps_first_key_wins {
/// # Examples
///
/// ```
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde::{Deserialize, Serialize};
/// # use serde_json::json;
/// # use serde_with::rust::string_empty_as_none;
/// #
@ -1081,7 +1090,144 @@ pub mod string_empty_as_none {
}
}
/// De/Serialize a [`HashMap`] into a list of tuples
/// De/Serialize a Map into a list of tuples
///
/// Some formats, like JSON, have limitations on the type of keys for maps.
/// In case of JSON, keys are restricted to strings.
/// Rust features more powerful keys, for example tuple, which can not be serialized to JSON.
///
/// This helper serializes the Map into a list of tuples, which does not have the same type restrictions.
/// The module can be applied on any type implementing `IntoIterator<Item = (&'a K, &'a V)>` and `FromIterator<(K, V)>`, with `K` and `V` being the key and value types.
/// From the standard library both [`HashMap`] and [`BTreeMap`] fullfil the condition and can be used here.
///
/// ## Converting to `serde_as`
///
/// If the map is of type [`HashMap`] or [`BTreeMap`] the same functionality can be expressed more clearly using the [`serde_as`] macro.
/// The `_` is a placeholder which works for any type which implements [`Serialize`]/[`Deserialize`], such as the tuple and `u32` type.
///
/// ```rust
/// # #[cfg(feature = "macros")] {
/// # use serde::{Deserialize, Serialize};
/// # use serde_with::serde_as;
/// # use std::collections::{BTreeMap, HashMap};
/// #
/// #[serde_as]
/// #[derive(Deserialize, Serialize)]
/// struct A {
/// #[serde_as(as = "Vec<(_, _)>")]
/// hashmap: HashMap<(String, u32), u32>,
/// #[serde_as(as = "Vec<(_, _)>")]
/// btreemap: BTreeMap<(String, u32), u32>,
/// }
/// # }
/// ```
///
/// # Examples
///
/// ```
/// # use serde::{Deserialize, Serialize};
/// # use serde_json::json;
/// # use std::collections::BTreeMap;
/// #
/// #[derive(Deserialize, Serialize)]
/// struct A {
/// #[serde(with = "serde_with::rust::map_as_tuple_list")]
/// s: BTreeMap<(String, u32), u32>,
/// }
///
/// let v: A = serde_json::from_value(json!({
/// "s": [
/// [["Hello", 123], 0],
/// [["World", 456], 1]
/// ]
/// })).unwrap();
///
/// assert_eq!(2, v.s.len());
/// assert_eq!(1, v.s[&("World".to_string(), 456)]);
/// ```
///
/// The helper is generic over the hasher type of the [`HashMap`] and works with different variants, such as `FnvHashMap`.
///
/// ```
/// # use serde::{Deserialize, Serialize};
/// # use serde_json::json;
/// #
/// use fnv::FnvHashMap;
///
/// #[derive(Deserialize, Serialize)]
/// struct A {
/// #[serde(with = "serde_with::rust::map_as_tuple_list")]
/// s: FnvHashMap<u32, bool>,
/// }
///
/// let v: A = serde_json::from_value(json!({
/// "s": [
/// [0, false],
/// [1, true]
/// ]
/// })).unwrap();
///
/// assert_eq!(2, v.s.len());
/// assert_eq!(true, v.s[&1]);
/// ```
///
/// [`serde_as`]: crate::guide::serde_as
pub mod map_as_tuple_list {
// Trait bounds based on this answer: https://stackoverflow.com/a/66600486/15470286
use super::*;
/// Serialize the map as a list of tuples
pub fn serialize<'a, T, K, V, S>(map: T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: IntoIterator<Item = (&'a K, &'a V)>,
T::IntoIter: ExactSizeIterator,
K: Serialize + 'a,
V: Serialize + 'a,
{
serializer.collect_seq(map)
}
/// Deserialize a map from a list of tuples
pub fn deserialize<'de, T, K, V, D>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
T: FromIterator<(K, V)>,
K: Deserialize<'de>,
V: Deserialize<'de>,
{
struct SeqVisitor<T, K, V>(PhantomData<(T, K, V)>);
impl<'de, T, K, V> Visitor<'de> for SeqVisitor<T, K, V>
where
T: FromIterator<(K, V)>,
K: Deserialize<'de>,
V: Deserialize<'de>,
{
type Value = T;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a list of key-value pairs")
}
fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
utils::SeqIter::new(seq).collect()
}
}
deserializer.deserialize_seq(SeqVisitor(PhantomData))
}
}
/// DEPRECATED De/Serialize a [`HashMap`] into a list of tuples
///
/// Use the [`map_as_tuple_list`] module which is more general than this.
/// It should work with everything convertible to and from an `Iterator` including [`BTreeMap`] and [`HashMap`].
///
/// ---
///
/// Some formats, like JSON, have limitations on the type of keys for maps.
/// In case of JSON, keys are restricted to strings.
@ -1098,7 +1244,7 @@ pub mod string_empty_as_none {
///
/// ```rust
/// # #[cfg(feature = "macros")] {
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde::{Deserialize, Serialize};
/// # use serde_with::serde_as;
/// # use std::collections::HashMap;
/// #
@ -1114,7 +1260,7 @@ pub mod string_empty_as_none {
/// # Examples
///
/// ```
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde::{Deserialize, Serialize};
/// # use serde_json::json;
/// # use std::collections::HashMap;
/// #
@ -1138,7 +1284,7 @@ pub mod string_empty_as_none {
/// The helper is generic over the hasher type of the [`HashMap`] and works with different variants, such as `FnvHashMap`.
///
/// ```
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde::{Deserialize, Serialize};
/// # use serde_json::json;
/// #
/// use fnv::FnvHashMap;
@ -1161,65 +1307,31 @@ pub mod string_empty_as_none {
/// ```
///
/// [`serde_as`]: crate::guide::serde_as
#[deprecated(
since = "1.8.0",
note = "Use the more general map_as_tuple_list module."
)]
pub mod hashmap_as_tuple_list {
use super::{SerializeSeq, *}; // Needed to remove the unused import warning in the parent scope
/// Serialize the [`HashMap`] as a list of tuples
pub fn serialize<K, V, S, BH>(map: &HashMap<K, V, BH>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
K: Eq + Hash + Serialize,
V: Serialize,
BH: BuildHasher,
{
let mut seq = serializer.serialize_seq(Some(map.len()))?;
for item in map.iter() {
seq.serialize_element(&item)?;
}
seq.end()
}
/// Deserialize a [`HashMap`] from a list of tuples
pub fn deserialize<'de, K, V, BH, D>(deserializer: D) -> Result<HashMap<K, V, BH>, D::Error>
where
D: Deserializer<'de>,
K: Eq + Hash + Deserialize<'de>,
V: Deserialize<'de>,
BH: BuildHasher + Default,
{
deserializer.deserialize_seq(HashMapVisitor(PhantomData))
}
#[allow(clippy::type_complexity)]
struct HashMapVisitor<K, V, BH>(PhantomData<fn() -> HashMap<K, V, BH>>);
impl<'de, K, V, BH> Visitor<'de> for HashMapVisitor<K, V, BH>
where
K: Deserialize<'de> + Eq + Hash,
V: Deserialize<'de>,
BH: BuildHasher + Default,
{
type Value = HashMap<K, V, BH>;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a list of key-value pairs")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut map =
HashMap::with_capacity_and_hasher(seq.size_hint().unwrap_or(0), BH::default());
while let Some((key, value)) = seq.next_element()? {
map.insert(key, value);
}
Ok(map)
}
}
#[doc(inline)]
#[deprecated(
since = "1.8.0",
note = "Use the more general map_as_tuple_list::deserialize function."
)]
pub use super::map_as_tuple_list::deserialize;
#[doc(inline)]
#[deprecated(
since = "1.8.0",
note = "Use the more general map_as_tuple_list::serialize function."
)]
pub use super::map_as_tuple_list::serialize;
}
/// De/Serialize a [`BTreeMap`] into a list of tuples
/// DEPRECATED De/Serialize a [`BTreeMap`] into a list of tuples
///
/// Use the [`map_as_tuple_list`] module which is more general than this.
/// It should work with everything convertible to and from an `Iterator` including [`BTreeMap`] and [`HashMap`].
///
/// ---
///
/// Some formats, like JSON, have limitations on the type of keys for maps.
/// In case of JSON, keys are restricted to strings.
@ -1236,7 +1348,7 @@ pub mod hashmap_as_tuple_list {
///
/// ```rust
/// # #[cfg(feature = "macros")] {
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde::{Deserialize, Serialize};
/// # use serde_with::serde_as;
/// # use std::collections::BTreeMap;
/// #
@ -1252,7 +1364,7 @@ pub mod hashmap_as_tuple_list {
/// # Examples
///
/// ```
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde::{Deserialize, Serialize};
/// # use serde_json::json;
/// # use std::collections::BTreeMap;
/// #
@ -1274,58 +1386,23 @@ pub mod hashmap_as_tuple_list {
/// ```
///
/// [`serde_as`]: crate::guide::serde_as
#[deprecated(
since = "1.8.0",
note = "Use the more general map_as_tuple_list module."
)]
pub mod btreemap_as_tuple_list {
use super::*;
/// Serialize the [`BTreeMap`] as a list of tuples
pub fn serialize<K, V, S>(map: &BTreeMap<K, V>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
K: Eq + Hash + Serialize,
V: Serialize,
{
let mut seq = serializer.serialize_seq(Some(map.len()))?;
for item in map.iter() {
seq.serialize_element(&item)?;
}
seq.end()
}
/// Deserialize a [`BTreeMap`] from a list of tuples
pub fn deserialize<'de, K, V, D>(deserializer: D) -> Result<BTreeMap<K, V>, D::Error>
where
D: Deserializer<'de>,
K: Deserialize<'de> + Ord,
V: Deserialize<'de>,
{
deserializer.deserialize_seq(BTreeMapVisitor(PhantomData))
}
#[allow(clippy::type_complexity)]
struct BTreeMapVisitor<K, V>(PhantomData<fn() -> BTreeMap<K, V>>);
impl<'de, K, V> Visitor<'de> for BTreeMapVisitor<K, V>
where
K: Deserialize<'de> + Ord,
V: Deserialize<'de>,
{
type Value = BTreeMap<K, V>;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a list of key-value pairs")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut map = BTreeMap::default();
while let Some((key, value)) = seq.next_element()? {
map.insert(key, value);
}
Ok(map)
}
}
#[doc(inline)]
#[deprecated(
since = "1.8.0",
note = "Use the more general map_as_tuple_list::deserialize function."
)]
pub use super::map_as_tuple_list::deserialize;
#[doc(inline)]
#[deprecated(
since = "1.8.0",
note = "Use the more general map_as_tuple_list::serialize function."
)]
pub use super::map_as_tuple_list::serialize;
}
/// This serializes a list of tuples into a map and back
@ -1344,7 +1421,7 @@ pub mod btreemap_as_tuple_list {
///
/// ```rust
/// # #[cfg(feature = "macros")] {
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde::{Deserialize, Serialize};
/// # use serde_with::serde_as;
/// # use std::collections::BTreeMap;
/// #
@ -1362,7 +1439,7 @@ pub mod btreemap_as_tuple_list {
/// `Wrapper` does not implement [`Hash`] nor [`Ord`], thus prohibiting the use [`HashMap`] or [`BTreeMap`].
///
/// ```
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde::{Deserialize, Serialize};
/// #
/// #[derive(Debug, Deserialize, Serialize, Default)]
/// struct S {
@ -1397,7 +1474,7 @@ pub mod btreemap_as_tuple_list {
/// In this example, the serialized format contains duplicate keys, which is not supported with [`HashMap`] or [`BTreeMap`].
///
/// ```
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde::{Deserialize, Serialize};
/// #
/// #[derive(Debug, Deserialize, Serialize, PartialEq, Default)]
/// struct S {
@ -1425,7 +1502,7 @@ pub mod btreemap_as_tuple_list {
///
/// [`serde_as`]: crate::guide::serde_as
pub mod tuple_list_as_map {
use super::{SerializeMap, *}; // Needed to remove the unused import warning in the parent scope
use super::*;
/// Serialize any iteration of tuples into a map.
pub fn serialize<'a, I, K, V, S>(iter: I, serializer: S) -> Result<S::Ok, S::Error>
@ -1436,12 +1513,9 @@ pub mod tuple_list_as_map {
V: Serialize + 'a,
S: Serializer,
{
let iter = iter.into_iter();
let mut map = serializer.serialize_map(Some(iter.len()))?;
for (key, value) in iter {
map.serialize_entry(&key, &value)?;
}
map.end()
// Convert &(K, V) to (&K, &V) for collect_map.
let iter = iter.into_iter().map(|(k, v)| (k, v));
serializer.collect_map(iter)
}
/// Deserialize a map into an iterator of tuples.
@ -1474,34 +1548,7 @@ pub mod tuple_list_as_map {
where
A: MapAccess<'de>,
{
let iter = MapIter(map, PhantomData);
iter.collect()
}
}
struct MapIter<'de, A, K, V>(A, PhantomData<(&'de (), A, K, V)>);
impl<'de, A, K, V> Iterator for MapIter<'de, A, K, V>
where
A: MapAccess<'de>,
K: Deserialize<'de>,
V: Deserialize<'de>,
{
type Item = Result<(K, V), A::Error>;
fn next(&mut self) -> Option<Self::Item> {
match self.0.next_entry() {
Ok(Some(x)) => Some(Ok(x)),
Ok(None) => None,
Err(err) => Some(Err(err)),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
match self.0.size_hint() {
Some(size) => (size, Some(size)),
None => (0, None),
}
utils::MapIter::new(map).collect()
}
}
}
@ -1518,7 +1565,7 @@ pub mod tuple_list_as_map {
///
/// ```rust
/// # #[cfg(feature = "macros")] {
/// # use serde_derive::Deserialize;
/// # use serde::Deserialize;
/// # use serde_with::{serde_as, BytesOrString};
/// #
/// #[serde_as]
@ -1532,7 +1579,7 @@ pub mod tuple_list_as_map {
///
/// # Example
/// ```rust
/// # use serde_derive::{Deserialize, Serialize};
/// # use serde::{Deserialize, Serialize};
/// #
/// #[derive(Debug, Deserialize, Serialize, PartialEq, Default)]
/// struct S {
@ -1576,7 +1623,7 @@ pub mod tuple_list_as_map {
pub mod bytes_or_string {
use super::*;
/// Deserialize a [`Vec`]`<u8>` from either bytes or string
/// Deserialize a [`Vec<u8>`] from either bytes or string
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
@ -1609,15 +1656,11 @@ pub mod bytes_or_string {
Ok(v.into_bytes())
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut res = Vec::with_capacity(seq.size_hint().unwrap_or(0));
while let Some(value) = seq.next_element()? {
res.push(value);
}
Ok(res)
utils::SeqIter::new(seq).collect()
}
}
}
@ -1631,11 +1674,11 @@ pub mod bytes_or_string {
/// ## Converting to `serde_as`
///
/// The same functionality can be more clearly expressed via [`DefaultOnError`] and using the [`serde_as`] macro.
/// It can be combined with other convertes as shown.
/// It can be combined with other converts as shown.
///
/// ```rust
/// # #[cfg(feature = "macros")] {
/// # use serde_derive::Deserialize;
/// # use serde::Deserialize;
/// # use serde_with::{serde_as, DefaultOnError, DisplayFromStr};
/// #
/// #[serde_as]
@ -1655,7 +1698,7 @@ pub mod bytes_or_string {
/// # Examples
///
/// ```
/// # use serde_derive::Deserialize;
/// # use serde::Deserialize;
/// #
/// #[derive(Deserialize)]
/// struct A {
@ -1685,7 +1728,7 @@ pub mod bytes_or_string {
/// Deserializing missing values can be supported by adding the `default` field attribute:
///
/// ```
/// # use serde_derive::Deserialize;
/// # use serde::Deserialize;
/// #
/// #[derive(Deserialize)]
/// struct B {
@ -1693,7 +1736,6 @@ pub mod bytes_or_string {
/// value: u32,
/// }
///
///
/// let b: B = serde_json::from_str(r#"{ }"#).unwrap();
/// assert_eq!(0, b.value);
/// ```
@ -1744,7 +1786,7 @@ pub mod default_on_error {
///
/// ```rust
/// # #[cfg(feature = "macros")] {
/// # use serde_derive::Deserialize;
/// # use serde::Deserialize;
/// # use serde_with::{serde_as, DefaultOnNull, DisplayFromStr};
/// #
/// #[serde_as]
@ -1764,7 +1806,7 @@ pub mod default_on_error {
/// # Examples
///
/// ```
/// # use serde_derive::Deserialize;
/// # use serde::Deserialize;
/// #
/// #[derive(Deserialize)]
/// struct A {

90
third_party/rust/serde_with/src/ser/const_arrays.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,90 @@
use super::*;
use alloc::{borrow::Cow, boxed::Box, collections::BTreeMap};
use std::collections::HashMap;
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,
{
use serde::ser::SerializeTuple;
let mut arr = serializer.serialize_tuple(N)?;
for elem in array {
arr.serialize_element(&SerializeAsWrap::<T, As>::new(elem))?;
}
arr.end()
}
}
macro_rules! tuple_seq_as_map_impl_intern {
($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_impl_intern!([(K, V); N], BTreeMap<K, V>);
tuple_seq_as_map_impl_intern!([(K, V); N], HashMap<K, V>);
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)
}
}
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)
}
}
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())
}
}
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())
}
}

524
third_party/rust/serde_with/src/ser/impls.rs поставляемый
Просмотреть файл

@ -1,13 +1,33 @@
use utils::duration::DurationSigned;
use super::*;
use crate::{formats::Strictness, rust::StringWithSeparator, Separator};
use std::{
collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque},
fmt::Display,
hash::{BuildHasher, Hash},
time::{Duration, SystemTime},
use crate::{
formats::Strictness, rust::StringWithSeparator, utils::duration::DurationSigned, Separator,
};
use alloc::{
borrow::Cow,
boxed::Box,
collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque},
rc::{Rc, Weak as RcWeak},
string::{String, ToString},
sync::{Arc, Weak as ArcWeak},
vec::Vec,
};
use core::{
cell::{Cell, RefCell},
convert::TryInto,
fmt::Display,
time::Duration,
};
#[cfg(feature = "indexmap")]
use indexmap_crate::{IndexMap, IndexSet};
use serde::ser::Error;
use std::{
collections::{HashMap, HashSet},
sync::{Mutex, RwLock},
time::SystemTime,
};
///////////////////////////////////////////////////////////////////////////////
// region: Simple Wrapper types (e.g., Box, Option)
impl<'a, T, U> SerializeAs<&'a T> for &'a U
where
@ -23,6 +43,20 @@ where
}
}
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)
}
}
impl<T, U> SerializeAs<Box<T>> for Box<U>
where
U: SerializeAs<T>,
@ -50,13 +84,142 @@ where
}
}
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)
}
}
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)
}
}
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)
}
}
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")),
}
}
}
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")),
}
}
}
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)
}
}
// endregion
///////////////////////////////////////////////////////////////////////////////
// region: Collection Types (e.g., Maps, Sets, Vec)
macro_rules! seq_impl {
($ty:ident < T $(: $tbound1:ident $(+ $tbound2:ident)*)* $(, $typaram:ident : $bound:ident $(+ $bound2:ident)*)* >) => {
($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 $(+ $bound2)*,)*
$($typaram: ?Sized + $bound,)*
{
fn serialize_as<S>(source: &$ty<T $(, $typaram)*>, serializer: S) -> Result<S::Ok, S::Error>
where
@ -70,14 +233,16 @@ macro_rules! seq_impl {
type BoxedSlice<T> = Box<[T]>;
type Slice<T> = [T];
seq_impl!(BinaryHeap<T: Ord + Sized>);
seq_impl!(BinaryHeap<T>);
seq_impl!(BoxedSlice<T>);
seq_impl!(BTreeSet<T: Ord + Sized>);
seq_impl!(HashSet<T: Eq + Hash + Sized, H: BuildHasher + Sized>);
seq_impl!(BTreeSet<T>);
seq_impl!(HashSet<T, H: Sized>);
seq_impl!(LinkedList<T>);
seq_impl!(Slice<T>);
seq_impl!(Vec<T>);
seq_impl!(VecDeque<T>);
#[cfg(feature = "indexmap")]
seq_impl!(IndexSet<T, H: Sized>);
macro_rules! map_impl {
($ty:ident < K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound:ident)* >) => {
@ -85,8 +250,8 @@ macro_rules! map_impl {
where
KU: SerializeAs<K>,
VU: SerializeAs<V>,
$(K: $kbound1 $(+ $kbound2)*,)*
$($typaram: $bound,)*
$(K: ?Sized + $kbound1 $(+ $kbound2)*,)*
$($typaram: ?Sized + $bound,)*
{
fn serialize_as<S>(source: &$ty<K, V $(, $typaram)*>, serializer: S) -> Result<S::Ok, S::Error>
where
@ -98,20 +263,10 @@ macro_rules! map_impl {
}
}
map_impl!(BTreeMap<K: Ord, V>);
map_impl!(HashMap<K: Eq + Hash, V, H: BuildHasher>);
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,
{
crate::rust::display_fromstr::serialize(source, serializer)
}
}
map_impl!(BTreeMap<K, V>);
map_impl!(HashMap<K, V, H: Sized>);
#[cfg(feature = "indexmap")]
map_impl!(IndexMap<K, V, H: Sized>);
macro_rules! tuple_impl {
($len:literal $($n:tt $t:ident $tas:ident)+) => {
@ -151,75 +306,8 @@ 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
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);
macro_rules! array_impl {
($len:literal) => {
impl<T, As> SerializeAs<[T; $len]> for [As; $len]
where
As: SerializeAs<T>,
{
fn serialize_as<S>(array: &[T; $len], serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use serde::ser::SerializeTuple;
let mut arr = serializer.serialize_tuple($len)?;
for elem in array {
arr.serialize_element(&SerializeAsWrap::<T, As>::new(elem))?;
}
arr.end()
}
}
};
}
array_impl!(0);
array_impl!(1);
array_impl!(2);
array_impl!(3);
array_impl!(4);
array_impl!(5);
array_impl!(6);
array_impl!(7);
array_impl!(8);
array_impl!(9);
array_impl!(10);
array_impl!(11);
array_impl!(12);
array_impl!(13);
array_impl!(14);
array_impl!(15);
array_impl!(16);
array_impl!(17);
array_impl!(18);
array_impl!(19);
array_impl!(20);
array_impl!(21);
array_impl!(22);
array_impl!(23);
array_impl!(24);
array_impl!(25);
array_impl!(26);
array_impl!(27);
array_impl!(28);
array_impl!(29);
array_impl!(30);
array_impl!(31);
array_impl!(32);
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)
}
}
macro_rules! map_as_tuple_seq {
($ty:ident < K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound:ident)* >) => {
($ty:ident < K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V >) => {
impl<K, KAs, V, VAs> SerializeAs<$ty<K, V>> for Vec<(KAs, VAs)>
where
KAs: SerializeAs<K>,
@ -239,8 +327,51 @@ macro_rules! map_as_tuple_seq {
}
};
}
map_as_tuple_seq!(BTreeMap<K: Ord, V>);
map_as_tuple_seq!(HashMap<K: Eq + Hash, V, H: BuildHasher>);
map_as_tuple_seq!(BTreeMap<K, V>);
// TODO HashMap with a custom hasher support would be better, but results in "unconstrained type parameter"
map_as_tuple_seq!(HashMap<K, V>);
#[cfg(feature = "indexmap")]
map_as_tuple_seq!(IndexMap<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,
{
crate::rust::display_fromstr::serialize(source, serializer)
}
}
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<AsRefStr> SerializeAs<Option<AsRefStr>> for NoneAsEmptyString
where
@ -286,19 +417,14 @@ macro_rules! tuple_seq_as_map_impl {
tuple_seq_as_map_impl! {
BinaryHeap<(K, V)>,
BTreeSet<(K, V)>,
HashSet<(K, V)>,
LinkedList<(K, V)>,
Option<(K, V)>,
Vec<(K, V)>,
VecDeque<(K, V)>,
}
tuple_seq_as_map_impl! {
[(K, V); 0], [(K, V); 1], [(K, V); 2], [(K, V); 3], [(K, V); 4], [(K, V); 5], [(K, V); 6],
[(K, V); 7], [(K, V); 8], [(K, V); 9], [(K, V); 10], [(K, V); 11], [(K, V); 12], [(K, V); 13],
[(K, V); 14], [(K, V); 15], [(K, V); 16], [(K, V); 17], [(K, V); 18], [(K, V); 19], [(K, V); 20],
[(K, V); 21], [(K, V); 22], [(K, V); 23], [(K, V); 24], [(K, V); 25], [(K, V); 26], [(K, V); 27],
[(K, V); 28], [(K, V); 29], [(K, V); 30], [(K, V); 31], [(K, V); 32],
}
tuple_seq_as_map_impl!(HashSet<(K, V)>);
#[cfg(feature = "indexmap")]
tuple_seq_as_map_impl!(IndexSet<(K, V)>);
impl<T, TAs> SerializeAs<T> for DefaultOnError<TAs>
where
@ -349,10 +475,10 @@ macro_rules! use_signed_duration {
(
$main_trait:ident $internal_trait:ident =>
{
$ty:ty; $converter:ident =>
$ty:ty =>
$({
$format:ty, $strictness:ty =>
$($tbound:ident: $bound:ident)*
$($tbound:ident: $bound:ident $(,)?)*
})*
}
) => {
@ -386,7 +512,7 @@ use_signed_duration!(
DurationMicroSeconds DurationMicroSeconds,
DurationNanoSeconds DurationNanoSeconds,
=> {
Duration; to_std_duration =>
Duration =>
{u64, STRICTNESS => STRICTNESS: Strictness}
{f64, STRICTNESS => STRICTNESS: Strictness}
{String, STRICTNESS => STRICTNESS: Strictness}
@ -398,7 +524,7 @@ use_signed_duration!(
DurationMicroSecondsWithFrac DurationMicroSecondsWithFrac,
DurationNanoSecondsWithFrac DurationNanoSecondsWithFrac,
=> {
Duration; to_std_duration =>
Duration =>
{f64, STRICTNESS => STRICTNESS: Strictness}
{String, STRICTNESS => STRICTNESS: Strictness}
}
@ -410,7 +536,7 @@ use_signed_duration!(
TimestampMicroSeconds DurationMicroSeconds,
TimestampNanoSeconds DurationNanoSeconds,
=> {
SystemTime; to_system_time =>
SystemTime =>
{i64, STRICTNESS => STRICTNESS: Strictness}
{f64, STRICTNESS => STRICTNESS: Strictness}
{String, STRICTNESS => STRICTNESS: Strictness}
@ -422,7 +548,7 @@ use_signed_duration!(
TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
=> {
SystemTime; to_system_time =>
SystemTime =>
{f64, STRICTNESS => STRICTNESS: Strictness}
{String, STRICTNESS => STRICTNESS: Strictness}
}
@ -439,3 +565,175 @@ where
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)
}
}
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)
}
}
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)
}
}
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<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),
}
}
}
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)
}
}
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)
}
}
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)
}
}
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)
}
}
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)
}
}
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)
}
}
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())
}
}
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

34
third_party/rust/serde_with/src/ser/legacy_arrays.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,34 @@
use super::*;
use alloc::collections::BTreeMap;
use std::collections::HashMap;
macro_rules! array_impl {
($($len:literal)+) => {$(
impl<T, As> SerializeAs<[T; $len]> for [As; $len]
where
As: SerializeAs<T>,
{
fn serialize_as<S>(array: &[T; $len], serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use serde::ser::SerializeTuple;
let mut arr = serializer.serialize_tuple($len)?;
for elem in array {
arr.serialize_element(&SerializeAsWrap::<T, As>::new(elem))?;
}
arr.end()
}
}
)+};
}
array_impl!(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 32);
tuple_seq_as_map_impl! {
[(K, V); 0], [(K, V); 1], [(K, V); 2], [(K, V); 3], [(K, V); 4], [(K, V); 5], [(K, V); 6],
[(K, V); 7], [(K, V); 8], [(K, V); 9], [(K, V); 10], [(K, V); 11], [(K, V); 12], [(K, V); 13],
[(K, V); 14], [(K, V); 15], [(K, V); 16], [(K, V); 17], [(K, V); 18], [(K, V); 19], [(K, V); 20],
[(K, V); 21], [(K, V); 22], [(K, V); 23], [(K, V); 24], [(K, V); 25], [(K, V); 26], [(K, V); 27],
[(K, V); 28], [(K, V); 29], [(K, V); 30], [(K, V); 31], [(K, V); 32],
}

8
third_party/rust/serde_with/src/ser/mod.rs поставляемый
Просмотреть файл

@ -7,6 +7,8 @@
//!
//! [user guide]: crate::guide
mod const_arrays;
#[macro_use]
mod impls;
use super::*;
@ -20,7 +22,7 @@ use super::*;
/// # 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`][].
/// 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.
///
@ -84,7 +86,7 @@ use super::*;
/// where
/// S: serde::Serializer,
/// {
/// serializer.serialize_str(&source.to_string())
/// serializer.collect_str(&source)
/// }
/// }
/// #
@ -96,9 +98,11 @@ use super::*;
/// # }
/// ```
///
/// [`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.

147
third_party/rust/serde_with/src/serde_conv.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,147 @@
/// 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};
///
/// #[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_with::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;
#[allow(clippy::ptr_arg)]
impl $m {
$vis fn serialize<S>(x: &$t, serializer: S) -> ::std::result::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) -> ::std::result::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) -> ::std::result::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) -> ::std::result::Result<$t, D::Error>
where
D: $crate::serde::Deserializer<'de>,
{
Self::deserialize(deserializer)
}
}
};
}

382
third_party/rust/serde_with/src/time_0_3.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,382 @@
//! 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::{
de::DeserializeAs,
formats::{Flexible, Format, Strict, Strictness},
ser::SerializeAs,
utils::duration::{DurationSigned, Sign},
DurationMicroSeconds, DurationMicroSecondsWithFrac, DurationMilliSeconds,
DurationMilliSecondsWithFrac, DurationNanoSeconds, DurationNanoSecondsWithFrac,
DurationSeconds, DurationSecondsWithFrac, TimestampMicroSeconds, TimestampMicroSecondsWithFrac,
TimestampMilliSeconds, TimestampMilliSecondsWithFrac, TimestampNanoSeconds,
TimestampNanoSecondsWithFrac, TimestampSeconds, TimestampSecondsWithFrac,
};
use alloc::{format, string::String};
use serde::{de, ser::Error as _, Deserializer, Serialize, Serializer};
use std::{convert::TryInto, fmt, time::Duration as StdDuration};
use time_0_3::{
format_description::well_known::{Rfc2822, Rfc3339},
Duration, 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: &Duration) -> DurationSigned {
let std_dur = StdDuration::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<Duration, D::Error>
where
D: Deserializer<'de>,
{
let mut dur: Duration = match sdur.duration.try_into() {
Ok(dur) => dur,
Err(msg) => {
return Err(de::Error::custom(format!(
"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,
=> {
Duration; duration_into_duration_signed =>
{i64, STRICTNESS => STRICTNESS: Strictness}
{f64, STRICTNESS => STRICTNESS: Strictness}
{String, STRICTNESS => STRICTNESS: Strictness}
}
);
use_duration_signed_ser!(
TimestampSeconds DurationSeconds,
TimestampMilliSeconds DurationMilliSeconds,
TimestampMicroSeconds DurationMicroSeconds,
TimestampNanoSeconds DurationNanoSeconds,
=> {
OffsetDateTime; offset_datetime_to_duration =>
{i64, STRICTNESS => STRICTNESS: Strictness}
{f64, STRICTNESS => STRICTNESS: Strictness}
{String, STRICTNESS => STRICTNESS: Strictness}
}
);
use_duration_signed_ser!(
TimestampSeconds DurationSeconds,
TimestampMilliSeconds DurationMilliSeconds,
TimestampMicroSeconds DurationMicroSeconds,
TimestampNanoSeconds DurationNanoSeconds,
=> {
PrimitiveDateTime; primitive_datetime_to_duration =>
{i64, STRICTNESS => STRICTNESS: Strictness}
{f64, STRICTNESS => STRICTNESS: Strictness}
{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}
{String, STRICTNESS => STRICTNESS: Strictness}
}
);
use_duration_signed_ser!(
TimestampSecondsWithFrac DurationSecondsWithFrac,
TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
=> {
OffsetDateTime; offset_datetime_to_duration =>
{f64, STRICTNESS => STRICTNESS: Strictness}
{String, STRICTNESS => STRICTNESS: Strictness}
}
);
use_duration_signed_ser!(
TimestampSecondsWithFrac DurationSecondsWithFrac,
TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
=> {
PrimitiveDateTime; primitive_datetime_to_duration =>
{f64, STRICTNESS => STRICTNESS: Strictness}
{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_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,
=> {
Duration; duration_from_duration_signed =>
{i64, Strict =>}
{f64, Strict =>}
{String, Strict =>}
{FORMAT, Flexible => FORMAT: Format}
}
);
use_duration_signed_de!(
TimestampSeconds DurationSeconds,
TimestampMilliSeconds DurationMilliSeconds,
TimestampMicroSeconds DurationMicroSeconds,
TimestampNanoSeconds DurationNanoSeconds,
=> {
OffsetDateTime; duration_to_offset_datetime =>
{i64, Strict =>}
{f64, Strict =>}
{String, Strict =>}
{FORMAT, Flexible => FORMAT: Format}
}
);
use_duration_signed_de!(
TimestampSeconds DurationSeconds,
TimestampMilliSeconds DurationMilliSeconds,
TimestampMicroSeconds DurationMicroSeconds,
TimestampNanoSeconds DurationNanoSeconds,
=> {
PrimitiveDateTime; duration_to_primitive_datetime =>
{i64, Strict =>}
{f64, Strict =>}
{String, Strict =>}
{FORMAT, Flexible => FORMAT: Format}
}
);
// Duration/Timestamp WITH FRACTIONS
use_duration_signed_de!(
DurationSecondsWithFrac DurationSecondsWithFrac,
DurationMilliSecondsWithFrac DurationMilliSecondsWithFrac,
DurationMicroSecondsWithFrac DurationMicroSecondsWithFrac,
DurationNanoSecondsWithFrac DurationNanoSecondsWithFrac,
=> {
Duration; duration_from_duration_signed =>
{f64, Strict =>}
{String, Strict =>}
{FORMAT, Flexible => FORMAT: Format}
}
);
use_duration_signed_de!(
TimestampSecondsWithFrac DurationSecondsWithFrac,
TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
=> {
OffsetDateTime; duration_to_offset_datetime =>
{f64, Strict =>}
{String, Strict =>}
{FORMAT, Flexible => FORMAT: Format}
}
);
use_duration_signed_de!(
TimestampSecondsWithFrac DurationSecondsWithFrac,
TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
=> {
PrimitiveDateTime; duration_to_primitive_datetime =>
{f64, Strict =>}
{String, Strict =>}
{FORMAT, Flexible => FORMAT: Format}
}
);
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)
}
}
impl<'de> DeserializeAs<'de, OffsetDateTime> for Rfc2822 {
fn deserialize_as<D>(deserializer: D) -> Result<OffsetDateTime, D::Error>
where
D: Deserializer<'de>,
{
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = OffsetDateTime;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a RFC2822-formatted `OffsetDateTime`")
}
fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
Self::Value::parse(value, &Rfc2822).map_err(E::custom)
}
}
deserializer.deserialize_str(Visitor)
}
}
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)
}
}
impl<'de> DeserializeAs<'de, OffsetDateTime> for Rfc3339 {
fn deserialize_as<D>(deserializer: D) -> Result<OffsetDateTime, D::Error>
where
D: Deserializer<'de>,
{
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = OffsetDateTime;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a RFC3339-formatted `OffsetDateTime`")
}
fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
Self::Value::parse(value, &Rfc3339).map_err(E::custom)
}
}
deserializer.deserialize_str(Visitor)
}
}

39
third_party/rust/serde_with/src/utils.rs поставляемый
Просмотреть файл

@ -1,13 +1,13 @@
pub(crate) mod duration;
use crate::de::{DeserializeAs, DeserializeAsWrap};
use serde::de::{MapAccess, SeqAccess};
use std::marker::PhantomData;
use alloc::string::String;
use core::marker::PhantomData;
use serde::de::{Deserialize, MapAccess, SeqAccess};
/// Re-Implementation of `serde::private::de::size_hint::cautious`
#[inline]
pub(crate) fn size_hint_cautious(hint: Option<usize>) -> usize {
std::cmp::min(hint.unwrap_or(0), 4096)
core::cmp::min(hint.unwrap_or(0), 4096)
}
pub(crate) const NANOS_PER_SEC: u32 = 1_000_000_000;
@ -16,12 +16,12 @@ pub(crate) const NANOS_PER_SEC: u32 = 1_000_000_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, KAs, V, VAs> {
pub(crate) struct MapIter<'de, A, K, V> {
pub(crate) access: A,
marker: PhantomData<(&'de (), K, KAs, V, VAs)>,
marker: PhantomData<(&'de (), K, V)>,
}
impl<'de, A, K, KAs, V, VAs> MapIter<'de, A, K, KAs, V, VAs> {
impl<'de, A, K, V> MapIter<'de, A, K, V> {
pub(crate) fn new(access: A) -> Self
where
A: MapAccess<'de>,
@ -33,14 +33,13 @@ impl<'de, A, K, KAs, V, VAs> MapIter<'de, A, K, KAs, V, VAs> {
}
}
impl<'de, A, K, KAs, V, VAs> Iterator for MapIter<'de, A, K, KAs, V, VAs>
impl<'de, A, K, V> Iterator for MapIter<'de, A, K, V>
where
A: MapAccess<'de>,
KAs: DeserializeAs<'de, K>,
VAs: DeserializeAs<'de, V>,
K: Deserialize<'de>,
V: Deserialize<'de>,
{
#[allow(clippy::type_complexity)]
type Item = Result<(DeserializeAsWrap<K, KAs>, DeserializeAsWrap<V, VAs>), A::Error>;
type Item = Result<(K, V), A::Error>;
fn next(&mut self) -> Option<Self::Item> {
self.access.next_entry().transpose()
@ -54,12 +53,12 @@ where
}
}
pub(crate) struct SeqIter<'de, A, K, KAs, V, VAs> {
pub(crate) struct SeqIter<'de, A, T> {
access: A,
marker: PhantomData<(&'de (), K, KAs, V, VAs)>,
marker: PhantomData<(&'de (), T)>,
}
impl<'de, A, K, KAs, V, VAs> SeqIter<'de, A, K, KAs, V, VAs> {
impl<'de, A, T> SeqIter<'de, A, T> {
pub(crate) fn new(access: A) -> Self
where
A: SeqAccess<'de>,
@ -71,14 +70,12 @@ impl<'de, A, K, KAs, V, VAs> SeqIter<'de, A, K, KAs, V, VAs> {
}
}
impl<'de, A, K, KAs, V, VAs> Iterator for SeqIter<'de, A, K, KAs, V, VAs>
impl<'de, A, T> Iterator for SeqIter<'de, A, T>
where
A: SeqAccess<'de>,
KAs: DeserializeAs<'de, K>,
VAs: DeserializeAs<'de, V>,
T: Deserialize<'de>,
{
#[allow(clippy::type_complexity)]
type Item = Result<(DeserializeAsWrap<K, KAs>, DeserializeAsWrap<V, VAs>), A::Error>;
type Item = Result<T, A::Error>;
fn next(&mut self) -> Option<Self::Item> {
self.access.next_element().transpose()
@ -92,7 +89,7 @@ where
}
}
pub(crate) fn duration_as_secs_f64(dur: &std::time::Duration) -> f64 {
pub(crate) fn duration_as_secs_f64(dur: &core::time::Duration) -> f64 {
(dur.as_secs() as f64) + (dur.subsec_nanos() as f64) / (NANOS_PER_SEC as f64)
}

Просмотреть файл

@ -6,15 +6,17 @@ use crate::{
DurationMilliSecondsWithFrac, DurationNanoSeconds, DurationNanoSecondsWithFrac,
DurationSeconds, DurationSecondsWithFrac, SerializeAs,
};
use alloc::{
format,
string::{String, ToString},
vec::Vec,
};
use core::{fmt, ops::Neg, time::Duration};
use serde::{
de::{self, Unexpected, Visitor},
ser, Deserialize, Deserializer, Serialize, Serializer,
};
use std::{
fmt,
ops::Neg,
time::{Duration, SystemTime},
};
use std::time::SystemTime;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub(crate) enum Sign {
@ -58,12 +60,12 @@ impl DurationSigned {
}
}
#[cfg(feature = "chrono")]
#[cfg(any(feature = "chrono", feature = "time_0_3"))]
pub(crate) fn with_duration(sign: Sign, duration: Duration) -> Self {
Self { sign, duration }
}
pub(crate) fn to_system_time<'de, D>(&self) -> Result<SystemTime, D::Error>
pub(crate) fn to_system_time<'de, D>(self) -> Result<SystemTime, D::Error>
where
D: Deserializer<'de>,
{
@ -76,7 +78,7 @@ impl DurationSigned {
})
}
pub(crate) fn to_std_duration<'de, D>(&self) -> Result<Duration, D::Error>
pub(crate) fn to_std_duration<'de, D>(self) -> Result<Duration, D::Error>
where
D: Deserializer<'de>,
{
@ -111,7 +113,7 @@ impl From<&SystemTime> for DurationSigned {
}
}
impl std::ops::Mul<u32> for DurationSigned {
impl core::ops::Mul<u32> for DurationSigned {
type Output = DurationSigned;
fn mul(mut self, rhs: u32) -> Self::Output {
@ -120,7 +122,7 @@ impl std::ops::Mul<u32> for DurationSigned {
}
}
impl std::ops::Div<u32> for DurationSigned {
impl core::ops::Div<u32> for DurationSigned {
type Output = DurationSigned;
fn div(mut self, rhs: u32) -> Self::Output {
@ -306,7 +308,7 @@ struct DurationVisitorFlexible;
impl<'de> Visitor<'de> for DurationVisitorFlexible {
type Value = DurationSigned;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> ::std::fmt::Result {
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("an integer, a float, or a string containing a number")
}
@ -493,14 +495,14 @@ fn parse_float_into_time_parts(mut value: &str) -> Result<(Sign, u64, u32), Pars
let parts: Vec<_> = value.split('.').collect();
match *parts.as_slice() {
[seconds] => {
if let Ok(seconds) = u64::from_str_radix(seconds, 10) {
if let Ok(seconds) = seconds.parse() {
Ok((sign, seconds, 0))
} else {
Err(ParseFloatError::InvalidValue)
}
}
[seconds, subseconds] => {
if let Ok(seconds) = u64::from_str_radix(seconds, 10) {
if let Ok(seconds) = seconds.parse() {
let subseclen = subseconds.chars().count() as u32;
if subseclen > 9 {
return Err(ParseFloatError::Custom(format!(
@ -509,7 +511,7 @@ fn parse_float_into_time_parts(mut value: &str) -> Result<(Sign, u64, u32), Pars
)));
}
if let Ok(mut subseconds) = u32::from_str_radix(subseconds, 10) {
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))

Просмотреть файл

@ -1,5 +1,5 @@
use std::fmt;
use alloc::string::String;
use core::fmt;
use serde::{
de::{self, DeserializeSeed, Deserializer, IgnoredAny, IntoDeserializer, MapAccess, Visitor},
forward_to_deserialize_any,
@ -9,6 +9,10 @@ use serde::{
/// 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
@ -31,7 +35,7 @@ use serde::{
/// }
/// ```
///
/// In Rust we would ideally like to model this data as a pair of `Player`
/// 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
@ -53,7 +57,7 @@ use serde::{
/// An implementation of the Challonge API would use `with_prefix!` like this:
///
/// ```rust
/// use serde_derive::{Deserialize, Serialize};
/// use serde::{Deserialize, Serialize};
/// use serde_with::with_prefix;
///
/// #[derive(Serialize, Deserialize)]
@ -71,7 +75,8 @@ use serde::{
/// }
///
/// with_prefix!(prefix_player1 "player1_");
/// with_prefix!(prefix_player2 "player2_");
/// // 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",
@ -103,15 +108,14 @@ use serde::{
/// [issue-with_prefix-deny_unknown_fields]: https://github.com/jonasbb/serde_with/issues/57
#[macro_export]
macro_rules! with_prefix {
($module:ident $prefix:expr) => {
mod $module {
use $crate::{
serde::{Deserialize, Deserializer, Serialize, Serializer},
with_prefix::WithPrefix,
};
($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) -> Result<S::Ok, S::Error>
pub fn serialize<T, S>(object: &T, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
where
T: Serialize,
S: Serializer,
@ -123,7 +127,7 @@ macro_rules! with_prefix {
}
#[allow(dead_code)]
pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
pub fn deserialize<'de, T, D>(deserializer: D) -> ::std::result::Result<T, D::Error>
where
T: Deserialize<'de>,
D: Deserializer<'de>,
@ -489,16 +493,15 @@ where
{
type Error = A::Error;
// Use `strip_prefix` with Rust 1.45
#[allow(clippy::manual_strip)]
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
where
K: DeserializeSeed<'de>,
{
while let Some(s) = self.delegate.next_key::<String>()? {
if s.starts_with(self.prefix) {
let without_prefix = s[self.prefix.len()..].into_deserializer();
return seed.deserialize(without_prefix).map(Some);
if let Some(without_prefix) = s.strip_prefix(self.prefix) {
return seed
.deserialize(without_prefix.into_deserializer())
.map(Some);
}
self.delegate.next_value::<IgnoredAny>()?;
}
@ -581,8 +584,6 @@ where
{
type Error = A::Error;
// Use `strip_prefix` with Rust 1.45
#[allow(clippy::manual_strip)]
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
where
K: DeserializeSeed<'de>,
@ -592,9 +593,10 @@ where
return seed.deserialize(without_prefix).map(Some);
}
while let Some(s) = self.delegate.next_key::<String>()? {
if s.starts_with(self.prefix) {
let without_prefix = s[self.prefix.len()..].into_deserializer();
return seed.deserialize(without_prefix).map(Some);
if let Some(without_prefix) = s.strip_prefix(self.prefix) {
return seed
.deserialize(without_prefix.into_deserializer())
.map(Some);
}
self.delegate.next_value::<IgnoredAny>()?;
}

144
third_party/rust/serde_with/tests/base64.rs поставляемый Normal file
Просмотреть файл

@ -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![[r#"Encoded text cannot have a 6-bit remainder. at line 1 column 5"#]],
);
check_error_deserialization::<BDefault>(
r#"["zz"]"#,
expect![[r#"Invalid last symbol 122, offset 1. at line 1 column 6"#]],
);
#[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!!==""##]],
);
}

740
third_party/rust/serde_with/tests/chrono.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,740 @@
#![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_crate::{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(secs, nsecs), Utc)
}
#[test]
fn json_datetime_from_any_to_string_deserialization() {
#[derive(Debug, PartialEq, Deserialize)]
struct S(#[serde(with = "serde_with::chrono::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(0, 0), 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(0, 0), 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(0, 0), 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(0, 0), 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(0, 0);
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"#]]};
};
}

Просмотреть файл

@ -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"
]"#,
);
}

15
third_party/rust/serde_with/tests/derives/lib.rs поставляемый Normal file
Просмотреть файл

@ -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::*;

39
third_party/rust/serde_with/tests/derives/serialize_display.rs поставляемый Normal file
Просмотреть файл

@ -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<-"
]"#]],
);
}

93
third_party/rust/serde_with/tests/hex.rs поставляемый Normal file
Просмотреть файл

@ -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"]"#,
);
}

285
third_party/rust/serde_with/tests/indexmap.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,285 @@
#![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_crate::{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 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 SI(
#[serde_as(as = "std::collections::HashMap<DisplayFromStr, DisplayFromStr>")]
IndexSet<(u32, IpAddr)>,
);
is_equal(
SI(IndexSet::from_iter(vec![(1, ip), (10, ip), (200, ip2)])),
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"#]],
);
}

41
third_party/rust/serde_with/tests/json.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,41 @@
#![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};
#[test]
fn test_nested_json() {
#[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\"}"
}"#]],
);
}

676
third_party/rust/serde_with/tests/rust.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,676 @@
#![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, LinkedList, VecDeque};
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::{de::DeserializeOwned, Deserialize, Serialize};
use serde_with::CommaSeparator;
#[test]
fn string_collection() {
#[derive(Debug, PartialEq, Deserialize, Serialize)]
struct S(
#[serde(with = "serde_with::rust::StringWithSeparator::<CommaSeparator>")] Vec<String>,
);
is_equal(S(vec![]), expect![[r#""""#]]);
is_equal(
S(vec![
"A".to_string(),
"B".to_string(),
"c".to_string(),
"D".to_string(),
]),
expect![[r#""A,B,c,D""#]],
);
is_equal(
S(vec!["".to_string(), "".to_string(), "".to_string()]),
expect![[r#"",,""#]],
);
is_equal(
S(vec!["AVeryLongString".to_string()]),
expect![[r#""AVeryLongString""#]],
);
}
#[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);
}
#[test]
fn test_map_as_tuple_list() {
#[derive(Debug, Deserialize, Serialize, PartialEq)]
struct Hash(#[serde(with = "serde_with::rust::map_as_tuple_list")] HashMap<String, u8>);
is_equal(
Hash(HashMap::from_iter(vec![
("ABC".to_string(), 1),
("Hello".to_string(), 0),
("World".to_string(), 20),
])),
expect![[r#"
[
[
"ABC",
1
],
[
"Hello",
0
],
[
"World",
20
]
]"#]],
);
is_equal(
Hash(HashMap::from_iter(vec![("Hello".to_string(), 0)])),
expect![[r#"
[
[
"Hello",
0
]
]"#]],
);
is_equal(Hash(HashMap::default()), expect![[r#"[]"#]]);
// Test parse error, only single element instead of tuple
check_error_deserialization::<Hash>(
r#"[ [1] ]"#,
expect![[r#"invalid type: integer `1`, expected a string at line 1 column 4"#]],
);
#[derive(Debug, Deserialize, Serialize, PartialEq)]
struct BTree(#[serde(with = "serde_with::rust::map_as_tuple_list")] BTreeMap<String, u8>);
is_equal(
BTree(BTreeMap::from_iter(vec![
("ABC".to_string(), 1),
("Hello".to_string(), 0),
("World".to_string(), 20),
])),
expect![[r#"
[
[
"ABC",
1
],
[
"Hello",
0
],
[
"World",
20
]
]"#]],
);
is_equal(
BTree(BTreeMap::from_iter(vec![("Hello".to_string(), 0)])),
expect![[r#"
[
[
"Hello",
0
]
]"#]],
);
is_equal(BTree(BTreeMap::default()), expect![[r#"[]"#]]);
// Test parse error, only single element instead of tuple
check_error_deserialization::<BTree>(
r#"[ [1] ]"#,
expect![[r#"invalid type: integer `1`, expected a string at line 1 column 4"#]],
);
}
#[test]
fn tuple_list_as_map_vec() {
#[derive(Debug, PartialEq, Deserialize, Serialize)]
struct S(
#[serde(with = "serde_with::rust::tuple_list_as_map")] Vec<(Wrapper<i32>, Wrapper<String>)>,
);
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(transparent)]
struct Wrapper<T>(T);
is_equal(
S(vec![
(Wrapper(1), Wrapper("Hi".into())),
(Wrapper(2), Wrapper("Cake".into())),
(Wrapper(99), Wrapper("Lie".into())),
]),
expect![[r#"
{
"1": "Hi",
"2": "Cake",
"99": "Lie"
}"#]],
);
is_equal(S(Vec::new()), expect![[r#"{}"#]]);
check_error_deserialization::<S>(
r#"[]"#,
expect![[r#"invalid type: sequence, expected a map at line 1 column 0"#]],
);
check_error_deserialization::<S>(
r#"null"#,
expect![[r#"invalid type: null, expected a map at line 1 column 4"#]],
);
}
#[test]
fn tuple_list_as_map_linkedlist() {
#[derive(Debug, PartialEq, Deserialize, Serialize)]
struct S(
#[serde(with = "serde_with::rust::tuple_list_as_map")]
LinkedList<(Wrapper<i32>, Wrapper<String>)>,
);
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(transparent)]
struct Wrapper<T>(T);
is_equal(
S(LinkedList::from_iter(vec![
(Wrapper(1), Wrapper("Hi".into())),
(Wrapper(2), Wrapper("Cake".into())),
(Wrapper(99), Wrapper("Lie".into())),
])),
expect![[r#"
{
"1": "Hi",
"2": "Cake",
"99": "Lie"
}"#]],
);
is_equal(S(LinkedList::new()), expect![[r#"{}"#]]);
check_error_deserialization::<S>(
r#"[]"#,
expect![[r#"invalid type: sequence, expected a map at line 1 column 0"#]],
);
check_error_deserialization::<S>(
r#"null"#,
expect![[r#"invalid type: null, expected a map at line 1 column 4"#]],
);
}
#[test]
fn tuple_list_as_map_vecdeque() {
#[derive(Debug, PartialEq, Deserialize, Serialize)]
struct S(
#[serde(with = "serde_with::rust::tuple_list_as_map")]
VecDeque<(Wrapper<i32>, Wrapper<String>)>,
);
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(transparent)]
struct Wrapper<T>(T);
is_equal(
S(VecDeque::from_iter(vec![
(Wrapper(1), Wrapper("Hi".into())),
(Wrapper(2), Wrapper("Cake".into())),
(Wrapper(99), Wrapper("Lie".into())),
])),
expect![[r#"
{
"1": "Hi",
"2": "Cake",
"99": "Lie"
}"#]],
);
is_equal(S(VecDeque::new()), expect![[r#"{}"#]]);
check_error_deserialization::<S>(
r#"[]"#,
expect![[r#"invalid type: sequence, expected a map at line 1 column 0"#]],
);
check_error_deserialization::<S>(
r#"null"#,
expect![[r#"invalid type: null, expected a map at line 1 column 4"#]],
);
}
#[test]
fn test_string_empty_as_none() {
#[derive(Debug, PartialEq, Deserialize, Serialize)]
struct S(#[serde(with = "serde_with::rust::string_empty_as_none")] Option<String>);
is_equal(S(Some("str".to_string())), expect![[r#""str""#]]);
check_deserialization(S(None), r#""""#);
check_deserialization(S(None), r#"null"#);
}
#[test]
fn test_default_on_error() {
#[derive(Debug, PartialEq, Deserialize, Serialize)]
struct S<T>(#[serde(with = "serde_with::rust::default_on_error")] T)
where
T: Default + Serialize + DeserializeOwned;
is_equal(S(123), expect![[r#"123"#]]);
is_equal(S("Hello World".to_string()), expect![[r#""Hello World""#]]);
is_equal(
S(vec![1, 2, 3]),
expect![[r#"
[
1,
2,
3
]"#]],
);
check_deserialization(S(0), r#"{}"#);
check_deserialization(S(0), r#"[]"#);
check_deserialization(S(0), r#"null"#);
check_deserialization(S(0), r#""A""#);
check_deserialization(S("".to_string()), r#"{}"#);
check_deserialization(S("".to_string()), r#"[]"#);
check_deserialization(S("".to_string()), r#"null"#);
check_deserialization(S("".to_string()), r#"0"#);
check_deserialization(S::<Vec<i32>>(vec![]), r#"{}"#);
check_deserialization(S::<Vec<i32>>(vec![]), r#"null"#);
check_deserialization(S::<Vec<i32>>(vec![]), r#"0"#);
check_deserialization(S::<Vec<i32>>(vec![]), r#""A""#);
}
#[test]
fn test_default_on_null() {
#[derive(Debug, PartialEq, Deserialize, Serialize)]
struct S<T>(#[serde(with = "serde_with::rust::default_on_null")] T)
where
T: Default + Serialize + DeserializeOwned;
is_equal(S(123), expect![[r#"123"#]]);
is_equal(S("Hello World".to_string()), expect![[r#""Hello World""#]]);
is_equal(
S(vec![1, 2, 3]),
expect![[r#"
[
1,
2,
3
]"#]],
);
check_deserialization(S(0), r#"null"#);
check_deserialization(S("".to_string()), r#"null"#);
check_deserialization(S::<Vec<i32>>(vec![]), r#"null"#);
}

44
third_party/rust/serde_with/tests/serde_as/collections.rs поставляемый Normal file
Просмотреть файл

@ -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#"{}"#]]);
}

130
third_party/rust/serde_with/tests/serde_as/default_on.rs поставляемый Normal file
Просмотреть файл

@ -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"#]],
);
}

459
third_party/rust/serde_with/tests/serde_as/enum_map.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,459 @@
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{:02x}", byte).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#"<VecEnumValues><vec><Int>123</Int><String>FooBar</String><Int>456</Int><String>XXX</String><Unit></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: ~
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);
}

187
third_party/rust/serde_with/tests/serde_as/frominto.rs поставляемый Normal file
Просмотреть файл

@ -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"#]]);
}

1129
third_party/rust/serde_with/tests/serde_as/lib.rs поставляемый Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

272
third_party/rust/serde_with/tests/serde_as/map_tuple_list.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,272 @@
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 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 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 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
}"#]],
);
}

134
third_party/rust/serde_with/tests/serde_as/pickfirst.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,134 @@
use super::*;
use serde_with::{CommaSeparator, PickFirst, SpaceSeparator, 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 data"#]],
);
#[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 data"#]],
);
#[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 data"#]],
);
}

191
third_party/rust/serde_with/tests/serde_as/serde_as_macro.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,191 @@
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"
}"#]],
);
}

52
third_party/rust/serde_with/tests/serde_as/serde_conv.rs поставляемый Normal file
Просмотреть файл

@ -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"#]],
);
}

521
third_party/rust/serde_with/tests/serde_as/time.rs поставляемый Normal file
Просмотреть файл

@ -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""#]]};
};
}

229
third_party/rust/serde_with/tests/time_0_3.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,229 @@
#![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"#]],
);
}

79
third_party/rust/serde_with/tests/utils.rs поставляемый Normal file
Просмотреть файл

@ -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(),
)
}

80
third_party/rust/serde_with/tests/version_numbers.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,80 @@
// Needed to supress a 2021 incompatability warning in the macro generated code
// The non_fmt_panic lint is not yet available on most Rust versions
#![allow(unknown_lints, non_fmt_panics)]
use version_sync::{
assert_contains_regex, assert_html_root_url_updated, assert_markdown_deps_updated,
};
#[test]
fn test_readme_deps() {
assert_markdown_deps_updated!("README.md");
}
#[test]
fn test_readme_deps_in_lib() {
assert_contains_regex!("src/lib.rs", r#"^//! version = "{version}""#);
}
#[test]
fn test_changelog() {
assert_contains_regex!("CHANGELOG.md", r#"## \[{version}\]"#);
}
#[test]
fn test_html_root_url() {
assert_html_root_url_updated!("src/lib.rs");
}
/// 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/{}/((\\d[^/]+|\\*|latest))/",
pkg_name
))?;
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(())
}
}

164
third_party/rust/serde_with/tests/with_prefix.rs поставляемый Normal file
Просмотреть файл

@ -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
}"#]],
);
}