我可以使用Bincode反序列化具有可变长度前缀的向量吗?

时间:2019-05-20 11:10:10

标签: rust deserialization serde

我的Rust二进制代码库有问题。序列化向量时,始终假设前缀长度为8个字节。当您始终使用Bincode编码数据时,这是一个很好的假设,因为Bincode可以读取它自己的序列化数据。

我处于无法影响串行器的情况,因为我没有编写串行器,并且由于遗留原因,它必须保持不变。它将其矢量编码为一个长度为前缀的数组,其中的前缀始终为2个字节(或者在某些情况下为4个字节,但是我知道这些情况。一旦我知道如何使用2个字节来做,则4个字节不应为问题)。

如何使用Bincode(和Serde)对这些字段进行反序列化?我可以解决以二进制编码硬编码的默认8个字节的长度吗?

2 个答案:

答案 0 :(得分:4)

Bincode不应该与任何现有的序列化程序或标准兼容。根据评论,您尝试读取的格式也不是。

我建议您获得bincode来源(它们是MIT许可的,因此您基本上可以随心所欲地对它们进行任何操作),并对其进行修改以适合您的格式(并为其命名并包含它在您的项目中。)

serde::Deserializer和基础的data model都有很好的文档说明,在bincode中的实现很难找到(在de/mod.rs中),因此以它为起点并进行调整根据需要。

答案 1 :(得分:0)

我已经找到了一种(可能非常丑陋的)方式来实现它,而无需实现自己的反序列化器— Bincode毕竟可以做到。看起来像这样:

impl<'de> Deserialize<'de> for VarLen16 {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct VarLen16Visitor;
        impl<'de> Visitor<'de> for VarLen16Visitor {
            type Value = VarLen16;
            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("VarLen16")
            }

            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
            where
                A: SeqAccess<'de>,
            {
                let mut res: Vec<u8> = vec![];

                let length: u16 = seq
                    .next_element()?
                    .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?;

                for i in 0..length {
                    res.push(
                        seq.next_element()?
                            .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?,
                    );
                }

                return Ok(VarLen16(res));
            }
        }

        return Ok(deserializer.deserialize_tuple(1 << 16, VarLen16Visitor)?);
    }
}
简而言之,我使系统认为我反序列化了一个元组,在该元组中,我将长度设置为所需的最大长度。我已经测试过了,它实际上并没有分配那么多的内存。然后,我将长度表示为该元组的一部分,先阅读该长度,然后继续阅读直到该长度指示我为止。它虽然不漂亮,但肯定可以。