Attribute Macro serde_with::serde_as

source · []
#[serde_as]
Expand description

Convenience macro to use the serde_as system.

The serde_as system is designed as a more flexible alternative to serde’s with-annotation.

Example

use serde_with::{serde_as, DisplayFromStr};
use std::collections::HashMap;

#[serde_as]
#[derive(Serialize, Deserialize)]
struct Data {
    /// Serialize into number
    #[serde_as(as = "_")]
    a: u32,

    /// Serialize into String
    #[serde_as(as = "DisplayFromStr")]
    b: u32,

    /// Serialize into a map from String to String
    #[serde_as(as = "HashMap<DisplayFromStr, _>")]
    c: Vec<(u32, String)>,
}

Alternative path to serde_with crate

If serde_with is not available at the default path, its path should be specified with the crate argument. See re-exporting serde_as for more use case information.

#[serde_as(crate = "::some_other_lib::serde_with")]
#[derive(Deserialize)]
struct Data {
    #[serde_as(as = "_")]
    a: u32,
}

What this macro does

The serde_as macro only serves a convenience function. All the steps it performs, can easily be done manually, in case the cost of an attribute macro is deemed to high. The functionality can best be described with an example.

#[serde_as]
#[derive(serde::Serialize)]
struct Foo {
    #[serde_as(as = "Vec<_>")]
    bar: Vec<u32>,
}
  1. All the placeholder type _ will be replaced with ::serde_with::Same. The placeholder type _ marks all the places where the types Serialize implementation should be used. In the example, it means that the u32 values will serialize with the Serialize implementation of u32. The Same type implements SerializeAs whenever the underlying type implements Serialize and is used to make the two traits compatible.

    If you specify a custom path for serde_with via the crate attribute, the path to the Same type will be altered accordingly.

  2. Wrap the type from the annotation inside a ::serde_with::As. In the above example we know have something like ::serde_with::As::<Vec<::serde_with::Same>>. The As type acts as the opposite of the Same type. It allows using a SerializeAs type whenever a Serialize is required.

  3. Translate the *as attributes into the serde equivalent ones. #[serde_as(as = ...)] will become #[serde(with = ...)]. Similarly, serialize_as is translated to serialize_with.

    The field attributes will be kept on the struct/enum such that other macros can use them too.

  4. It searches #[serde_as(as = ...)] if there is a type named BorrowCow under any path. If BorrowCow is found, the attribute #[serde(borrow)] is added to the field. If #[serde(borrow)] or #[serde(borrow = "...")] is already present, this step will be skipped.

After all these steps, the code snippet will have transformed into roughly this.

#[derive(serde::Serialize)]
struct Foo {
    #[serde_as(as = "Vec<_>")]
    #[serde(with = "::serde_with::As::<Vec<::serde_with::Same>>")]
    bar: Vec<u32>,
}