bdk_chain::bitcoin::hashes::serde::de

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

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementations on Foreign Types§

Source§

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

Source§

type Value = T

Source§

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

Implementors§