Trait gclient::ext::sp_core::serde::de::DeserializeSeed

source ·
pub trait DeserializeSeed<'de>: Sized {
    type Value;

    // Required method
    fn deserialize<D>(
        self,
        deserializer: D,
    ) -> Result<Self::Value, <D as Deserializer<'de>>::Error>
       where D: Deserializer<'de>;
}
Expand description

DeserializeSeed is the stateful form of the Deserialize trait. If you ever find yourself looking for a way to pass data into a Deserialize impl, this trait is the way to do it.

As one example of stateful deserialization consider deserializing a JSON array into an existing buffer. Using the Deserialize trait we could deserialize a JSON array into a Vec<T> but it would be a freshly allocated Vec<T>; there is no way for Deserialize to reuse a previously allocated buffer. Using DeserializeSeed instead makes this possible as in the example code below.

The canonical API for stateless deserialization looks like this:

fn func<'de, T: Deserialize<'de>>() -> Result<T, Error>

Adjusting an API like this to support stateful deserialization is a matter of accepting a seed as input:

fn func_seed<'de, T: DeserializeSeed<'de>>(seed: T) -> Result<T::Value, Error>

In practice the majority of deserialization is stateless. An API expecting a seed can be appeased by passing std::marker::PhantomData as a seed in the case of stateless deserialization.

§Lifetime

The 'de lifetime of this trait is the lifetime of data that may be borrowed by Self::Value when deserialized. See the page Understanding deserializer lifetimes for a more detailed explanation of these lifetimes.

§Example

Suppose we have JSON that looks like [[1, 2], [3, 4, 5], [6]] and we need to deserialize it into a flat representation like vec![1, 2, 3, 4, 5, 6]. Allocating a brand new Vec<T> for each subarray would be slow. Instead we would like to allocate a single Vec<T> and then deserialize each subarray into it. This requires stateful deserialization using the DeserializeSeed trait.

use serde::de::{Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor};
use std::fmt;
use std::marker::PhantomData;

// A DeserializeSeed implementation that uses stateful deserialization to
// append array elements onto the end of an existing vector. The preexisting
// state ("seed") in this case is the Vec<T>. The `deserialize` method of
// `ExtendVec` will be traversing the inner arrays of the JSON input and
// appending each integer into the existing Vec.
struct ExtendVec<'a, T: 'a>(&'a mut Vec<T>);

impl<'de, 'a, T> DeserializeSeed<'de> for ExtendVec<'a, T>
where
    T: Deserialize<'de>,
{
    // The return type of the `deserialize` method. This implementation
    // appends onto an existing vector but does not create any new data
    // structure, so the return type is ().
    type Value = ();

    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: Deserializer<'de>,
    {
        // Visitor implementation that will walk an inner array of the JSON
        // input.
        struct ExtendVecVisitor<'a, T: 'a>(&'a mut Vec<T>);

        impl<'de, 'a, T> Visitor<'de> for ExtendVecVisitor<'a, T>
        where
            T: Deserialize<'de>,
        {
            type Value = ();

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                write!(formatter, "an array of integers")
            }

            fn visit_seq<A>(self, mut seq: A) -> Result<(), A::Error>
            where
                A: SeqAccess<'de>,
            {
                // Decrease the number of reallocations if there are many elements
                if let Some(size_hint) = seq.size_hint() {
                    self.0.reserve(size_hint);
                }

                // Visit each element in the inner array and push it onto
                // the existing vector.
                while let Some(elem) = seq.next_element()? {
                    self.0.push(elem);
                }
                Ok(())
            }
        }

        deserializer.deserialize_seq(ExtendVecVisitor(self.0))
    }
}

// Visitor implementation that will walk the outer array of the JSON input.
struct FlattenedVecVisitor<T>(PhantomData<T>);

impl<'de, T> Visitor<'de> for FlattenedVecVisitor<T>
where
    T: Deserialize<'de>,
{
    // This Visitor constructs a single Vec<T> to hold the flattened
    // contents of the inner arrays.
    type Value = Vec<T>;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "an array of arrays")
    }

    fn visit_seq<A>(self, mut seq: A) -> Result<Vec<T>, A::Error>
    where
        A: SeqAccess<'de>,
    {
        // Create a single Vec to hold the flattened contents.
        let mut vec = Vec::new();

        // Each iteration through this loop is one inner array.
        while let Some(()) = seq.next_element_seed(ExtendVec(&mut vec))? {
            // Nothing to do; inner array has been appended into `vec`.
        }

        // Return the finished vec.
        Ok(vec)
    }
}

let visitor = FlattenedVecVisitor(PhantomData);
let flattened: Vec<u64> = deserializer.deserialize_seq(visitor)?;

Required Associated Types§

source

type Value

The type produced by using this seed.

Required Methods§

source

fn deserialize<D>( self, deserializer: D, ) -> Result<Self::Value, <D as Deserializer<'de>>::Error>
where D: Deserializer<'de>,

Equivalent to the more common Deserialize::deserialize method, except with some initial piece of data (the seed) passed in.

Object Safety§

This trait is not object safe.

Implementors§

source§

impl<'de, T> DeserializeSeed<'de> for PhantomData<T>
where T: Deserialize<'de>,

§

type Value = T