Expand description

This crate provides traits and an adapter for creating move-oriented sequence and map accessors, as a complement to the remaining serde deserializer traits, which are entirely move-oriented.

It provides SeqAccess, which replaces serde::de::SeqAccess, and MapKeyAccess / MapValueAccess, which collectively replace serde::de::MapAccess. These traits are often easier to use when implementing a Deserializer if you’re focused on using by-move constructs, and help ensure correctness for callers.

In order to interoperate with serde, it also provides AccessAdapter. This struct takes any SeqAccess or MapKeyAccess type and converts it into a serde::de::SeqAccess or serde::de::MapAccess.

Example

In this example, we’re interested in creating a deserializer that reads from an iterator of (key, value) pairs and emits them as a map. We create a a KeyAccess type, which implements MapKeyAccess. We use serde-mobile’s built-in SubordinateValue type as our MapValueAccess, because we’ll be using the common pattern where the iterator is stored by both the key and value accessor. This ends up being easier (if more verbose) to implement: a serde::de::MapAccess is a single type that needs to deserialize keys and values separately, and therefore needs some awkward design to capture the state where a key has been yielded but not a value. serde-mobile, on the other hand, splits this into a pair of types, so that only correct states can be expressed.

use std::collections::hash_map::{HashMap, IntoIter};
use std::marker::PhantomData;
use serde::de::{
    IntoDeserializer,
    Error,
    DeserializeSeed,
    value::{MapAccessDeserializer, Error as SimpleError},
};
use serde::Deserialize;
use serde_mobile::{
    MapKeyAccess,
    MapValueAccess,
    AccessAdapter,
    SubordinateValue
};

struct KeyAccess<I, E>{
    entries: I,
    error: PhantomData<E>,
}

impl<I, K, V, E> KeyAccess<I, E>
where
    I: Iterator<Item=(K, V)>
{
    fn new<C>(collection: C) -> Self
        where C: IntoIterator<IntoIter=I>
    {
        Self {
            entries: collection.into_iter(),
            error: PhantomData,
        }
    }
}

// MapKeyAccess is the key-getting equivalent of serde::de::MapAccess
impl<'de, I, K, V, E> MapKeyAccess<'de> for KeyAccess<I, E>
where
    I: Iterator<Item=(K, V)>,
    K: IntoDeserializer<'de, E>,
    V: IntoDeserializer<'de, E>,
    E: Error,
{
    type Error = E;
    type Value = SubordinateValue<V::Deserializer, Self>;

    // notice that next_key_seed takes self by move and returns Self::Value,
    // which is a MapKeyAccess. This forces the caller to get a value before
    // they can get another key.
    fn next_key_seed<S>(mut self, seed: S) -> Result<Option<(S::Value, Self::Value)>, Self::Error>
    where
        S: DeserializeSeed<'de>
    {
        self.entries
            .next()
            .map(|(key, value)| {
                seed
                    .deserialize(key.into_deserializer())
                    .map(|key| (
                        key,
                        SubordinateValue {
                            value: value.into_deserializer(),
                            parent: self
                        }
                    ))
            })
            .transpose()
    }

    fn size_hint(&self) -> Option<usize> {
        match self.entries.size_hint() {
            (min, Some(max)) if min == max => Some(min),
            _ => None,
        }
    }
}

// Normally we'd have to create a separate struct to implement `MapValueAccess`,
// but this pattern is common enough that serde-mobile provides a type called
// `SubordinateValue` that handles this pattern for us.

let serialized = HashMap::from([
    ("a", 10),
    ("b", 20),
]);

#[derive(Deserialize, Debug, PartialEq, Eq)]
struct Data {
    a: i32,
    b: i32,
}

let seq_access = KeyAccess::new(serialized);

// use an AccessAdapter to turn a serde-mobile access type
// into a serde access type
let deserializer = MapAccessDeserializer::new(AccessAdapter::new(seq_access));

match Data::deserialize(deserializer) {
    Ok(data) => assert_eq!(data, Data { a: 10, b: 20 }),
    Err(err) => {
        let err: SimpleError = err;
        panic!("failed to deserialize")
    }
}

Structs

Utility type implementing MapValueAccess for the common case where a value-access type consists only of a deserializable value, along with the original MapKeyAccess type that produced it, which will be returned after the value is consumed.

Enums

Adapter type for converting the serde-mobile traits into serde’s &mut self oriented traits. It uses an enum to track the state of the accessors.

Traits

Move-oriented version of serde::de::MapAccess, for getting keys.

Move-oriented version of serde::de::MapAccess for getting values associated with keys.

Move-oriented version of serde::de::SeqAccess.

Type Definitions

A SeqAccessAdapter is an AccessAdapter used as a de::SeqAccess. It can never be in the Value state.