[][src]Module microserde::de

Deserialization traits.

Deserialization in microserde works by returning a "place" into which data may be written through the methods of the Visitor trait object.

Use the make_place! macro to acquire a "place" type. A library may use a single place type across all of its Deserialize impls, or each impl or each module may use a private place type. There is no difference.

A place is simply:

struct Place<T> {
    out: Option<T>,
}

Upon successful deserialization the output object is written as Some(T) into the out field of the place.

Deserializing a primitive

The Visitor trait has a method corresponding to each supported primitive type.

use microserde::{make_place, Result};
use microserde::de::{Deserialize, Visitor};

make_place!(Place);

struct MyBoolean(bool);

// The Visitor trait has a selection of methods corresponding to different
// data types. We override the ones that our Rust type supports
// deserializing from, and write the result into the `out` field of our
// output place.
//
// These methods may perform validation and decide to return an error.
impl Visitor for Place<MyBoolean> {
    fn boolean(&mut self, b: bool) -> Result<()> {
        self.out = Some(MyBoolean(b));
        Ok(())
    }
}

impl Deserialize for MyBoolean {
    fn begin(out: &mut Option<Self>) -> &mut dyn Visitor {
        // All Deserialize impls will look exactly like this. There is no
        // other correct implementation of Deserialize.
        Place::new(out)
    }
}

Deserializing a sequence

In the case of a sequence (JSON array), the visitor method returns a builder that can hand out places to write sequence elements one element at a time.

use microserde::{make_place, Result};
use microserde::de::{Deserialize, Seq, Visitor};
use std::mem;

make_place!(Place);

struct MyVec<T>(Vec<T>);

impl<T: Deserialize> Visitor for Place<MyVec<T>> {
    fn seq(&mut self) -> Result<Box<dyn Seq + '_>> {
        Ok(Box::new(VecBuilder {
            out: &mut self.out,
            vec: Vec::new(),
            element: None,
        }))
    }
}

struct VecBuilder<'a, T: 'a> {
    // At the end, output will be written here.
    out: &'a mut Option<MyVec<T>>,
    // Previous elements are accumulated here.
    vec: Vec<T>,
    // Next element will be placed here.
    element: Option<T>,
}

impl<'a, T: Deserialize> Seq for VecBuilder<'a, T> {
    fn element(&mut self) -> Result<&mut dyn Visitor> {
        // Free up the place by transfering the most recent element
        // into self.vec.
        self.vec.extend(self.element.take());
        // Hand out a place to write the next element.
        Ok(Deserialize::begin(&mut self.element))
    }

    fn finish(&mut self) -> Result<()> {
        // Transfer the last element.
        self.vec.extend(self.element.take());
        // Move the output object into self.out.
        let vec = mem::replace(&mut self.vec, Vec::new());
        *self.out = Some(MyVec(vec));
        Ok(())
    }
}

impl<T: Deserialize> Deserialize for MyVec<T> {
    fn begin(out: &mut Option<Self>) -> &mut dyn Visitor {
        // As mentioned, all Deserialize impls will look like this.
        Place::new(out)
    }
}

Deserializing a map or struct

This code demonstrates what is generated for structs by #[derive(Deserialize)].

use microserde::{make_place, Result};
use microserde::de::{Deserialize, Map, Visitor};

make_place!(Place);

// The struct that we would like to deserialize.
struct Demo {
    code: u32,
    message: String,
}

impl Visitor for Place<Demo> {
    fn map(&mut self) -> Result<Box<dyn Map + '_>> {
        // Like for sequences, we produce a builder that can hand out places
        // to write one struct field at a time.
        Ok(Box::new(DemoBuilder {
            code: None,
            message: None,
            out: &mut self.out,
        }))
    }
}

struct DemoBuilder<'a> {
    code: Option<u32>,
    message: Option<String>,
    out: &'a mut Option<Demo>,
}

impl<'a> Map for DemoBuilder<'a> {
    fn key(&mut self, k: &str) -> Result<&mut dyn Visitor> {
        // Figure out which field is being deserialized and return a place
        // to write it.
        //
        // The code here ignores unrecognized fields but an implementation
        // would be free to return an error instead. Similarly an
        // implementation may want to check for duplicate fields by
        // returning an error if the current field already has a value.
        match k {
            "code" => Ok(Deserialize::begin(&mut self.code)),
            "message" => Ok(Deserialize::begin(&mut self.message)),
            _ => Ok(Visitor::ignore()),
        }
    }

    fn finish(&mut self) -> Result<()> {
        // Make sure we have every field and then write the output object
        // into self.out.
        let code = self.code.take().ok_or(microserde::Error)?;
        let message = self.message.take().ok_or(microserde::Error)?;
        *self.out = Some(Demo { code, message });
        Ok(())
    }
}

impl Deserialize for Demo {
    fn begin(out: &mut Option<Self>) -> &mut dyn Visitor {
        // All Deserialize impls look like this.
        Place::new(out)
    }
}

Traits

Deserialize

Trait for data structures that can be deserialized from a JSON string.

Map

Trait that can hand out places to write values of a map.

Seq

Trait that can hand out places to write sequence elements.

Visitor

Trait that can write data into an output place.