diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
commit | 43a97878ce14b72f0981164f87f2e35e14151312 (patch) | |
tree | 620249daf56c0258faa40cbdcf9cfba06de2a846 /third_party/rust/serde_with/src/guide | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/serde_with/src/guide')
3 files changed, 912 insertions, 0 deletions
diff --git a/third_party/rust/serde_with/src/guide/feature_flags.md b/third_party/rust/serde_with/src/guide/feature_flags.md new file mode 100644 index 0000000000..9e80177ad2 --- /dev/null +++ b/third_party/rust/serde_with/src/guide/feature_flags.md @@ -0,0 +1,62 @@ +# Available Feature Flags + +This crate has the following features which can be enabled. +Each entry will explain the feature in more detail. + +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` + +The `chrono` feature enables integration of `chrono` specific conversions. +This includes support for the timestamp and duration types. + +This pulls in `chrono` as a dependency. + +## `guide` + +The `guide` feature enables inclusion of this user guide. +The feature only changes the rustdoc output and enables no other effects. + +## `hex` + +The `hex` feature enables serializing data in hex format. + +This pulls in `hex` as a dependency. + +## `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. + +This pulls in `serde_json` as a dependency. + +## `macros` + +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. diff --git a/third_party/rust/serde_with/src/guide/serde_as.md b/third_party/rust/serde_with/src/guide/serde_as.md new file mode 100644 index 0000000000..76275f0047 --- /dev/null +++ b/third_party/rust/serde_with/src/guide/serde_as.md @@ -0,0 +1,332 @@ +# `serde_as` Annotation + +This is an alternative to serde's with-annotation. +It is more flexible and composable, but work with fewer types. + +The scheme is based on two new traits, [`SerializeAs`] and [`DeserializeAs`], which need to be implemented by all types which want to be compatible with `serde_as`. +The proc-macro attribute [`#[serde_as]`][crate::serde_as] exists as a usability boost for users. +The basic design of `serde_as` was developed by [@markazmierczak](https://github.com/markazmierczak). + +This page contains some general advice on the usage of `serde_as` and on implementing the necessary traits. +[**A list of all supported transformations enabled by `serde_as` is available on this page.**](crate::guide::serde_as_transformations) + +1. [Switching from serde's with to `serde_as`](#switching-from-serdes-with-to-serde_as) + 1. [Deserializing Optional Fields](#deserializing-optional-fields) + 2. [Gating `serde_as` on Features](#gating-serde_as-on-features) +2. [Implementing `SerializeAs` / `DeserializeAs`](#implementing-serializeas--deserializeas) + 1. [Using `#[serde_as]` on types without `SerializeAs` and `Serialize` implementations](#using-serde_as-on-types-without-serializeas-and-serialize-implementations) + 2. [Using `#[serde_as]` with serde's remote derives](#using-serde_as-with-serdes-remote-derives) +3. [Re-exporting `serde_as`](#re-exporting-serde_as) + +## Switching from serde's with to `serde_as` + +For the user, the main difference is that instead of + +```rust,ignore +#[serde(with = "...")] +``` + +you now have to write + +```rust,ignore +#[serde_as(as = "...")] +``` + +and place the `#[serde_as]` attribute *before* the `#[derive]` attribute. +You still need the `#[derive(Serialize, Deserialize)]` on the struct/enum. + +All together, this looks like: + +```rust +use serde::{Deserialize, Serialize}; +use serde_with::{serde_as, DisplayFromStr}; + +#[serde_as] +#[derive(Serialize, Deserialize)] +struct A { + #[serde_as(as = "DisplayFromStr")] + mime: mime::Mime, +} +``` + +The main advantage is that you can compose `serde_as` stuff, which is impossible with the with-annotation. +For example, the `mime` field from above could be nested in one or more data structures: + +```rust +# use std::collections::BTreeMap; +# use serde::{Deserialize, Serialize}; +# use serde_with::{serde_as, DisplayFromStr}; +# +#[serde_as] +#[derive(Serialize, Deserialize)] +struct A { + #[serde_as(as = "Option<BTreeMap<_, Vec<DisplayFromStr>>>")] + mime: Option<BTreeMap<String, Vec<mime::Mime>>>, +} +``` + +### Deserializing Optional Fields + +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. + +```rust +# use serde::{Deserialize, Serialize}; +# use serde_with::{serde_as, DisplayFromStr}; +# +#[serde_as] +#[derive(Serialize, Deserialize)] +struct A { + #[serde_as(as = "Option<DisplayFromStr>")] + // Allows deserialization without providing a value for `val` + #[serde(default)] + val: Option<u32>, +} +``` + +In the future, this behavior might change and `default` would be applied on `Option<T>` fields. +You can add your feedback at [serde_with#185]. + +### Gating `serde_as` on Features + +Gating `serde_as` behind optional features is currently not supported. +More details can be found in the corresponding issue [serde_with#355]. + +```rust,ignore +#[cfg_attr(feature="serde" ,serde_as)] +#[cfg_attr(feature="serde", derive(Serialize, Deserialize))] +struct StructC { + #[cfg_attr(feature="serde" ,serde_as(as = "Vec<(_, _)>"))] + map: HashMap<(i32,i32), i32>, +} +``` + +The `serde_as` proc-macro attribute will not recognize the `serde_as` attribute on the field and will not perform the necessary translation steps. +The problem can be avoided by forcing Rust to evaluate all cfg-expressions before running `serde_as`. +This is possible with the `#[cfg_eval]` attribute, which is considered for stabilization ([rust#82679], [rust#87221]). + +As a workaround, it is possible to remove the `serde_as` proc-macro attribute and perform the transformation manually. +The transformation steps are listed in the [`serde_as`] documentations. +For the example above, this means to replace the field attribute with: + +```rust,ignore +use serde_with::{As, Same}; + +#[cfg_attr(feature="serde", serde(with = "As::<Vec<(Same, Same)>>"))] +map: HashMap<(i32,i32), i32>, +``` + +[rust#82679]: https://github.com/rust-lang/rust/issues/82679 +[rust#87221]: https://github.com/rust-lang/rust/pull/87221 +[serde_with#355]: https://github.com/jonasbb/serde_with/issues/355 + +## Implementing `SerializeAs` / `DeserializeAs` + +You can support [`SerializeAs`] / [`DeserializeAs`] on your own types too. +Most "leaf" types do not need to implement these traits, since they are supported implicitly. +"Leaf" type refers to types which directly serialize like plain data types. +[`SerializeAs`] / [`DeserializeAs`] is very important for collection types, like `Vec` or `BTreeMap`, since they need special handling for the key/value de/serialization such that the conversions can be done on the key/values. +You also find them implemented on the conversion types, such as the [`DisplayFromStr`] type. +These make up the bulk of this crate and allow you to perform all the nice conversions to [hex strings], the [bytes to string converter], or [duration to UNIX epoch]. + +In many cases, conversion is only required from one serializable type to another one, without requiring the full power of the `Serialize` or `Deserialize` traits. +In these cases, the [`serde_conv!`] macro conveniently allows defining conversion types without the boilerplate. +The documentation of [`serde_conv!`] contains more details how to use it. + +The trait documentations for [`SerializeAs`] and [`DeserializeAs`] describe in details how to implement them for container types like `Box` or `Vec` and other types. + +### Using `#[serde_as]` on types without `SerializeAs` and `Serialize` implementations + +The `SerializeAs` and `DeserializeAs` traits can easily be used together with types from other crates without running into orphan rule problems. +This is a distinct advantage of the `serde_as` system. +For this example we assume we have a type `RemoteType` from a dependency which does not implement `Serialize` nor `SerializeAs`. +We assume we have a module containing a `serialize` and a `deserialize` function, which can be used in the `#[serde(with = "MODULE")]` annotation. +You find an example in the [official serde documentation](https://serde.rs/custom-date-format.html). + +Our goal is to serialize this `Data` struct. +Right now, we do not have anything we can use to replace `???` with, since `_` only works if `RemoteType` would implement `Serialize`, which it does not. + +```rust +# #[cfg(FALSE)] { +#[serde_as] +#[derive(serde::Serialize)] +struct Data { + #[serde_as(as = "Vec<???>")] + vec: Vec<RemoteType>, +} +# } +``` + +We need to create a new type for which we can implement `SerializeAs`, to replace the `???`. +The `SerializeAs` implementation is **always** written for a local type. +This allows it to seamlessly work with types from dependencies without running into orphan rule problems. + +```rust +# #[cfg(FALSE)] { +struct LocalType; + +impl SerializeAs<RemoteType> for LocalType { + fn serialize_as<S>(value: &RemoteType, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + MODULE::serialize(value, serializer) + } +} + +impl<'de> DeserializeAs<'de, RemoteType> for LocalType { + fn deserialize_as<D>(deserializer: D) -> Result<RemoteType, D::Error> + where + D: Deserializer<'de>, + { + MODULE::deserialize(deserializer) + } +} +# } +``` + +This is how the final implementation looks like. +We assumed we have a module `MODULE` with a `serialize` function already, which we use here to provide the implementation. +As can be seen, this is mostly boilerplate, since the most part is encapsulated in `$module::serialize`. +The final `Data` struct will now look like: + +```rust +# #[cfg(FALSE)] { +#[serde_as] +#[derive(serde::Serialize)] +struct Data { + #[serde_as(as = "Vec<LocalType>")] + vec: Vec<RemoteType>, +} +# } +``` + +### Using `#[serde_as]` with serde's remote derives + +A special case of the above section is using it on remote derives. +This is a special functionality of serde, where it derives the de/serialization code for a type from another crate if all fields are `pub`. +You can find all the details in the [official serde documentation](https://serde.rs/remote-derive.html). + +```rust +# #[cfg(FALSE)] { +// Pretend that this is somebody else's crate, not a module. +mod other_crate { + // Neither Serde nor the other crate provides Serialize and Deserialize + // impls for this struct. + pub struct Duration { + pub secs: i64, + pub nanos: i32, + } +} + +//////////////////////////////////////////////////////////////////////////////// + +use other_crate::Duration; + +// Serde calls this the definition of the remote type. It is just a copy of the +// remote data structure. The `remote` attribute gives the path to the actual +// type we intend to derive code for. +#[derive(serde::Serialize, serde::Deserialize)] +#[serde(remote = "Duration")] +struct DurationDef { + secs: i64, + nanos: i32, +} +# } +``` + +Our goal is now to use `Duration` within `serde_as`. +We use the existing `DurationDef` type and its `serialize` and `deserialize` functions. +We can write this implementation. +The implementation for `DeserializeAs` works analogue. + +```rust +# #[cfg(FALSE)] { +impl SerializeAs<Duration> for DurationDef { + fn serialize_as<S>(value: &Duration, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + DurationDef::serialize(value, serializer) + } +} +# } +``` + +This now allows us to use `Duration` for serialization. + +```rust +# #[cfg(FALSE)] { +use other_crate::Duration; + +#[serde_as] +#[derive(serde::Serialize)] +struct Data { + #[serde_as(as = "Vec<DurationDef>")] + vec: Vec<Duration>, +} +# } +``` + +## Re-exporting `serde_as` + +If `serde_as` is being used in a context where the `serde_with` crate is not available from the root +path, but is re-exported at some other path, the `crate = "..."` attribute argument should be used +to specify its path. This may be the case if `serde_as` is being used in a procedural macro - +otherwise, users of that macro would need to add `serde_with` to their own Cargo manifest. + +The `crate` argument will generally be used in conjunction with [`serde`'s own `crate` argument]. + +For example, a type definition may be defined in a procedural macro: + +```rust,ignore +// some_other_lib_derive/src/lib.rs + +use proc_macro::TokenStream; +use quote::quote; + +#[proc_macro] +pub fn define_some_type(_item: TokenStream) -> TokenStream { + let def = quote! { + #[serde(crate = "::some_other_lib::serde")] + #[::some_other_lib::serde_with::serde_as(crate = "::some_other_lib::serde_with")] + #[derive(::some_other_lib::serde::Deserialize)] + struct Data { + #[serde_as(as = "_")] + a: u32, + } + }; + + TokenStream::from(def) +} +``` + +This can be re-exported through a library which also re-exports `serde` and `serde_with`: + +```rust,ignore +// some_other_lib/src/lib.rs + +pub use serde; +pub use serde_with; +pub use some_other_lib_derive::define_some_type; +``` + +The procedural macro can be used by other crates without any additional imports: + +```rust,ignore +// consuming_crate/src/main.rs + +some_other_lib::define_some_type!(); +``` + +[`DeserializeAs`]: crate::DeserializeAs +[`DisplayFromStr`]: crate::DisplayFromStr +[`serde_as`]: crate::serde_as +[`serde_conv!`]: crate::serde_conv! +[`serde`'s own `crate` argument]: https://serde.rs/container-attrs.html#crate +[`SerializeAs`]: crate::SerializeAs +[bytes to string converter]: crate::BytesOrString +[duration to UNIX epoch]: crate::DurationSeconds +[hex strings]: crate::hex::Hex +[serde_with#185]: https://github.com/jonasbb/serde_with/issues/185 diff --git a/third_party/rust/serde_with/src/guide/serde_as_transformations.md b/third_party/rust/serde_with/src/guide/serde_as_transformations.md new file mode 100644 index 0000000000..9be67e154b --- /dev/null +++ b/third_party/rust/serde_with/src/guide/serde_as_transformations.md @@ -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 |