summaryrefslogtreecommitdiffstats
path: root/third_party/rust/serde_with/src/guide.md
blob: 788d4c9201b843f84ce51d38c38c2cd3edfe5aaf (plain)
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# `serde_with` User Guide

This crate provides helper functions to extend and change how [`serde`] serializes different data types.
For example, you can serialize [a map as a sequence of tuples][crate::guide::serde_as#maps-to-vec-of-tuples], serialize [using the `Display` and `FromStr` traits][`DisplayFromStr`], or serialize [an empty `String` like `None`][NoneAsEmptyString].
`serde_with` covers types from the Rust Standard Library and some common crates like [`chrono`][serde_with_chrono].

[**A list of all supported transformations is available on this page.**](crate::guide::serde_as_transformations)

The crate offers four types of functionality.

## 1. A more flexible and composable replacement for the with annotation, called `serde_as`

This is an alternative to [serde's with-annotation][with-annotation], which adds flexibility and composability to the scheme.
The main downside is that it work with fewer types than [with-annotations][with-annotation].
However, all types from the Rust Standard Library should be supported in all combinations and any missing entry is a bug.

You mirror the type structure of the field you want to de/serialize.
You can specify converters for the inner types of a field, e.g., `Vec<DisplayFromStr>`.
The default de/serialization behavior can be restored by using `_` as a placeholder, e.g., `BTreeMap<_, DisplayFromStr>`.

The `serde_as` scheme is based on two new traits: [`SerializeAs`] and [`DeserializeAs`].  
[Check out the detailed page about `serde_as` and the available features.](crate::guide::serde_as)

### Example

```rust
# use serde::{Deserialize, Serialize};
# use serde_with::{serde_as, DisplayFromStr, Map};
# use std::net::Ipv4Addr;
#
#[serde_as]
# #[derive(Debug, PartialEq, Eq)]
#[derive(Deserialize, Serialize)]
struct Data {
    // Type does not implement Serialize or Deserialize
    #[serde_as(as = "DisplayFromStr")]
    address: Ipv4Addr,
    // Treat the Vec like a map with duplicates
    // Convert u32 into a String and keep the String the same type
    #[serde_as(as = "Map<DisplayFromStr, _>")]
    vec_as_map: Vec<(u32, String)>,
}

let data = Data {
    address: Ipv4Addr::new(192, 168, 0, 1),
    vec_as_map: vec![
        (123, "Hello".into()),
        (456, "World".into()),
        (123, "Hello".into()),
    ],
};

let json = r#"{
  "address": "192.168.0.1",
  "vec_as_map": {
    "123": "Hello",
    "456": "World",
    "123": "Hello"
  }
}"#;

// Test Serialization
assert_eq!(json, serde_json::to_string_pretty(&data).unwrap());
// Test Deserialization
assert_eq!(data, serde_json::from_str(json).unwrap());
```

## 2. proc-macros to make it easier to use both above parts

The proc-macros are an optional addition and improve the user experience for common tasks.
We have already seen how the `serde_as` attribute is used to define the serialization instructions.

The proc-macro attributes are defined in the [`serde_with_macros`] crate and re-exported from the root of this crate.
The proc-macros are optional, but enabled by default.
For further details, please refer to the documentation of each proc-macro.

## 3. Derive macros to implement `Deserialize` and `Serialize`

The derive macros work similar to the serde provided ones, but they do implement other de/serialization schemes.
For example, the derives [`DeserializeFromStr`] and [`SerializeDisplay`] require that the type also implement [`FromStr`] and [`Display`] and de/serializes from/to a string instead of the usual way of iterating over all fields.

[`Display`]: std::fmt::Display
[`FromStr`]: std::str::FromStr
[`serde_with_macros`]: serde_with_macros
[serde_with_chrono]: crate::chrono
[with-annotation]: https://serde.rs/field-attrs.html#with