4 stable releases
3.0.0 | Apr 20, 2022 |
---|---|
2.0.0 | Apr 19, 2022 |
1.0.2 | Apr 13, 2022 |
#2196 in Parser implementations
Used in kaydle
23KB
223 lines
serde-mobile
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. See docs.rs for details.
lib.rs
:
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")
}
}
Dependencies
~100–335KB