我可以将 RMPV `Value` 发送回 rmp_serde 以进行反序列化吗?

Can I send an RMPV `Value` back to rmp_serde for deserialization?

我有一个大的、有点复杂的数据结构,我可以使用 serdermp-serde 对其进行序列化和反序列化,但我发现反序列化速度很慢。我认为这是因为我的数据结构包括两个相当大的 HashMap。我不知道 rmp_serde::from_slice 创建 HashMap 的效率如何——它会使用 .with_capacity 初始化还是只创建一个 HashMap 并逐一插入?此外,我发现 AHashMap 在其他地方给了我相当大的性能改进,所以我尽量避免使用默认的 HashMap。

我想尝试使用 rmpv::decode::value::read_value, but I'd like to leave most of the deserialization to rmp_serde and only implement some deserialization myself given some Value 进行反序列化。有没有办法选择我手动反序列化哪些片段?

从概念上讲,我想做的是:

let v = rmp::decode::read_value(&mut reader).unwrap();   // get some Value
let arr : &Vec<Value> = v.as_array().unwrap();           // v is known to be an array
let first_value : MyType = deserialize_manually(arr[0]); // I'll convert the Value myself
let second_value : AnotherType = arr[1].into();          // allow rmpv to convert Value for me

我目前使用的是 rmp-serde 0.14 和 rmpv 0.4.7。 The rmp_serde changelog and rmp_serde release page 没有提供有关更改内容的详细信息,因此我还没有理由相信升级到当前版本(撰写此问题时为 v0.15.4)会提供任何新功能。

我知道serde提供了一个deserialize_with attribute。也许这是合适的路线,所以或者,我的问题是:如何使用 deserialize_with 反序列化特定的 MsgPack 字段?

我能够使用 deserialize-with 让它工作。首先,我必须注释我的结构:

struct MyStruct {
    some_number: i32,
    #[serde(deserialize_with="de_first_value")]
    first_value : HashMap<i32, String>, // T1 & T2 don't matter
    second_value : AnotherType,
}

然后我创建这个函数来驱动反序列化。因为我正在反序列化 HashMap,所以我遵循 serde 的 Implement Deserialize for a custom map type:

fn de_first_value<'de, D>(deserializer: D) -> Result<HashMap<i32, String>, D::Error>
where
    D: serde::de::Deserializer<'de>,
{
    deserializer.deserialize_byte_buf(MyHmVisitor)
}

然后我定义 MyHmVisitor 并实现 the Visitor trait. For deserializing a HashMap, I have to implement the visit_map function; I assume that I could do a similar deserialization for other types in this way by implementing the default provided methods(除非被覆盖,否则它们都会因类型错误而失败):

struct MyHmVisitor;

impl<'de> serde::de::Visitor<'de> for MyHmVisitor {
    type Value = HashMap<i32, String>;

    /// "This is used in error messages. The message should complete the sentence
    /// 'This Visitor expects to receive ...'"
    /// https://docs.serde.rs/src/serde/de/mod.rs.html#1270
    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(formatter, "a HashMap<i32, String>")
    }

    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
    where
        A: serde::de::MapAccess<'de>,
    {
        // extract the size hint from the serialized map. If it doesn't exist, default to 0
        let capacity = map.size_hint().unwrap_or(0);

        let mut hm = HashMap::with_capacity(capacity);

        while let Some((k, v)) = map.next_entry()? {
            hm.insert(k,v);
        }

        hm
    }
}