#map #sequence #deserializer #adapter #access #traits #move-oriented

serde-mobile

为 serde 反序列化器提供的面向移动的序列和映射访问类型

4 个稳定版本

3.0.0 2022年4月20日
2.0.0 2022年4月19日
1.0.2 2022年4月13日

#2241 in 解析器实现


用于 kaydle

MPL-2.0 许可证

23KB
223

serde-mobile

该软件包提供创建面向移动的序列和映射访问器的特性和适配器,作为剩余 serde 反序列化器特性的补充,这些特性完全是面向移动的。有关详细信息,请参阅docs.rs


lib.rs:

该软件包提供创建面向移动的序列和映射访问器的特性和适配器,作为剩余 serde 反序列化器特性的补充,这些特性完全是面向移动的。

它提供了SeqAccess,它替代了serde::de::SeqAccess,以及MapKeyAccess / MapValueAccess,它们共同替代了serde::de::MapAccess。当您专注于使用移动构造时,这些特性在实现 Deserializer 时通常更容易使用,并有助于确保调用者的正确性。

为了与serde进行交互,它还提供了AccessAdapter。这个结构体接受任何SeqAccessMapKeyAccess类型,并将其转换为serde::de::SeqAccessserde::de::MapAccess

示例

在这个示例中,我们感兴趣的是创建一个反序列化器,它从一对`(key, value)`的迭代器中读取并将它们作为映射输出。我们创建了一个`KeyAccess`类型,该类型实现了MapKeyAccess。我们使用`serde-mobile`的内置SubordinateValue类型作为我们的MapValueAccess,因为我们将在键和值访问器中存储迭代器。这最终使得实现更加简单(如果更冗长):一个serde::de::MapAccess是一个需要单独反序列化键和值的单一类型,因此需要一些不灵活的设计来捕捉键已产生但值未产生的情况。《serde-mobile》,另一方面,将其拆分为一对类型,这样就可以表达正确的状态。

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")
}
}

依赖

~110–340KB