Skip to content

Latest commit

 

History

History
499 lines (374 loc) · 10.9 KB

serde_as_transformations.md

File metadata and controls

499 lines (374 loc) · 10.9 KB

De/Serialize Transformations Available

This page lists the transformations implemented in this crate and supported by serde_as.

  1. Base64 encode bytes
  2. Big Array support
  3. Borrow from the input for Cow type
  4. Bytes with more efficiency
  5. Convert to an intermediate type using Into
  6. Convert to an intermediate type using TryInto
  7. Default from null
  8. De/Serialize into Vec, ignoring errors
  9. De/Serialize with FromStr and Display
  10. Duration as seconds
  11. Hex encode bytes
  12. Ignore deserialization errors
  13. Maps to Vec of enums
  14. Maps to Vec of tuples
  15. NaiveDateTime like UTC timestamp
  16. None as empty String
  17. One or many elements into Vec
  18. Pick first successful deserialization
  19. Timestamps as seconds since UNIX epoch
  20. Value into JSON String
  21. Vec of tuples to Maps
  22. Well-known time formats for OffsetDateTime

Base64 encode bytes

Base64

Requires the base64 feature. The character set and padding behavior can be configured.

// 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.

// Rust
#[serde_as(as = "[[_; 64]; 33]")]
value: [[u8; 64]; 33],

// JSON
"value": [[0,0,0,0,0,...], [0,0,0,...], ...],

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.

// 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.

// Rust
#[serde_as(as = "Bytes")]
value: Vec<u8>,

// JSON
"value": [0, 1, 2, 3, ...],

Convert to an intermediate type using Into

FromInto

// 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

// Rust
#[serde_as(as = "TryFromInto<i8>")]
value: u8,

// JSON
"value": 127,

Default from null

DefaultOnNull

// 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.

#[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

// 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

// Rust
#[serde_as(as = "serde_with::DurationSeconds<u64>")]
value: Duration,

// JSON
"value": 86400,

DurationSecondsWithFrac supports subsecond precision:

// Rust
#[serde_as(as = "serde_with::DurationSecondsWithFrac<f64>")]
value: Duration,

// JSON
"value": 1.234,

Different serialization formats are possible:

// 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.

// 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.

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",
  }
}

Maps to Vec of tuples

// Rust
#[serde_as(as = "Vec<(_, _)>")]
value: HashMap<String, u32>, // also works with BTreeMap

// JSON
"value": [
    ["hello", 1],
    ["world", 2]
],

The inverse operation is also available.

NaiveDateTime like UTC timestamp

Requires the chrono feature.

// 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

// 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

// 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

// 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

// Rust
#[serde_as(as = "serde_with::TimestampSeconds<i64>")]
value: SystemTime,

// JSON
"value": 86400,

TimestampSecondsWithFrac supports subsecond precision:

// Rust
#[serde_as(as = "serde_with::TimestampSecondsWithFrac<f64>")]
value: SystemTime,

// JSON
"value": 1.234,

Different serialization formats are possible:

// 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.

// 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

// 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 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.

// 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.