Manually implementing Deserialize for a struct
Only when derive is not getting the job done.
The Deserialize
impl below corresponds to the following struct:
struct Duration {
secs: u64,
nanos: u32,
}
Deserializing a struct is somewhat more complicated than deserializing a
map in order to avoid allocating a String to hold the field
names. Instead there is a Field
enum which is deserialized from a &str
.
The implementation supports two possible ways that a struct may be represented by a data format: as a seq like in Postcard, and as a map like in JSON.
use std::fmt;
use serde::de::{self, Deserialize, Deserializer, Visitor, SeqAccess, MapAccess};
impl<'de> Deserialize<'de> for Duration {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
enum Field { Secs, Nanos }
// This part could also be generated independently by:
//
// #[derive(Deserialize)]
// #[serde(field_identifier, rename_all = "lowercase")]
// enum Field { Secs, Nanos }
impl<'de> Deserialize<'de> for Field {
fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
where
D: Deserializer<'de>,
{
struct FieldVisitor;
impl<'de> Visitor<'de> for FieldVisitor {
type Value = Field;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("`secs` or `nanos`")
}
fn visit_str<E>(self, value: &str) -> Result<Field, E>
where
E: de::Error,
{
match value {
"secs" => Ok(Field::Secs),
"nanos" => Ok(Field::Nanos),
_ => Err(de::Error::unknown_field(value, FIELDS)),
}
}
}
deserializer.deserialize_identifier(FieldVisitor)
}
}
struct DurationVisitor;
impl<'de> Visitor<'de> for DurationVisitor {
type Value = Duration;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct Duration")
}
fn visit_seq<V>(self, mut seq: V) -> Result<Duration, V::Error>
where
V: SeqAccess<'de>,
{
let secs = seq.next_element()?
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
let nanos = seq.next_element()?
.ok_or_else(|| de::Error::invalid_length(1, &self))?;
Ok(Duration::new(secs, nanos))
}
fn visit_map<V>(self, mut map: V) -> Result<Duration, V::Error>
where
V: MapAccess<'de>,
{
let mut secs = None;
let mut nanos = None;
while let Some(key) = map.next_key()? {
match key {
Field::Secs => {
if secs.is_some() {
return Err(de::Error::duplicate_field("secs"));
}
secs = Some(map.next_value()?);
}
Field::Nanos => {
if nanos.is_some() {
return Err(de::Error::duplicate_field("nanos"));
}
nanos = Some(map.next_value()?);
}
}
}
let secs = secs.ok_or_else(|| de::Error::missing_field("secs"))?;
let nanos = nanos.ok_or_else(|| de::Error::missing_field("nanos"))?;
Ok(Duration::new(secs, nanos))
}
}
const FIELDS: &[&str] = &["secs", "nanos"];
deserializer.deserialize_struct("Duration", FIELDS, DurationVisitor)
}
}