Trait serde_with::DeserializeAs[][src]

pub trait DeserializeAs<'de, T>: Sized {
    fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
    where
        D: Deserializer<'de>
; }
Expand description

A data structure that can be deserialized from any data format supported by Serde, analogue to Deserialize.

The trait is analogue to the serde::Deserialize trait, with the same meaning of input and output arguments. It can and should the implemented using the same code structure as the Deserialize trait. As such, the same advice for implementing Deserialize applies here.

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

This code shows how to implement Deserialize for Box:

impl<'de, T: Deserialize<'de>> Deserialize<'de> for Box<T> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        Ok(Box::new(Deserialize::deserialize(deserializer)?))
    }
}

and this code shows how to do the same using DeserializeAs:

impl<'de, T, U> DeserializeAs<'de, Box<T>> for Box<U>
where
    U: DeserializeAs<'de, T>,
{
    fn deserialize_as<D>(deserializer: D) -> Result<Box<T>, D::Error>
    where
        D: Deserializer<'de>,
    {
        Ok(Box::new(
            DeserializeAsWrap::<T, U>::deserialize(deserializer)?.into_inner(),
        ))
    }
}

It uses two type parameters, T and U instead of only one and performs the deserialization step using the DeserializeAsWrap type. The T type is the on the Rust side after deserialization, whereas the U type determines how the value will be deserialized. These two changes are usually enough to make a container type implement DeserializeAs.

DeserializeAsWrap is a piece of glue code which turns DeserializeAs into a serde compatible datatype, by converting all calls to deserialize into deserialize_as. This allows us to implement DeserializeAs such that it can be applied recursively throughout the whole data structure. This is mostly important for container types, such as Vec or BTreeMap. In a BTreeMap this allows us to specify two different serialization behaviors, one for key and one for value, using the DeserializeAs trait.

Implementing a converter Type

This shows a simplified implementation for DisplayFromStr.

struct DisplayFromStr;

impl<'de, T> DeserializeAs<'de, T> for DisplayFromStr
where
    T: FromStr,
    T::Err: Display,
{
    fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let s = String::deserialize(deserializer).map_err(Error::custom)?;
        s.parse().map_err(Error::custom)
    }
}

Required methods

Deserialize this value from the given Serde deserializer.

Implementations on Foreign Types

Implementors