Expand description
Deserialization traits.
Deserialization in miniserde 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 miniserde::{make_place, Result};
use miniserde::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 miniserde::{make_place, Result};
use miniserde::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 miniserde::{make_place, Result};
use miniserde::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(<dyn 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(miniserde::Error)?;
let message = self.message.take().ok_or(miniserde::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
Trait for data structures that can be deserialized from a JSON string.
Trait that can hand out places to write values of a map.
Trait that can hand out places to write sequence elements.
Trait that can write data into an output place.