【问题标题】:Can I deserialize vectors with variable length prefix with Bincode?我可以使用 Bincode 反序列化具有可变长度前缀的向量吗?
【发布时间】:2019-05-20 11:10:09
【问题描述】:

我遇到了 Rust bincode 库的问题。当它序列化一个向量时,它总是假设前缀长度是 8 个字节。当您总是使用 bincode 对数据进行编码时,这是一个很好的假设,因为 bincode 可以读取它自己的序列化数据。

我处于无法影响序列化程序的情况,因为我没有编写它,并且由于遗留原因它必须保持不变。它将向量编码为一个以长度为前缀的数组,其中前缀始终为 2 个字节(或者在某些情况下为 4 个字节,但我非常了解这些情况。一旦我知道如何使用 2 个字节进行操作,4 个字节就不应该是问题)。

如何使用 bincode(以及 serde)来反序列化这些字段?我可以解决在 bincode 中硬编码的默认 8 字节长度吗?

【问题讨论】:

  • 您试图从中解码数据的序列化程序是什么? Bincode 不应该与任何现有的序列化程序兼容。
  • 此数据由 python 程序序列化并通过 udp 套接字发送。
  • 但是python程序中的序列化是某种公开命名的格式吗?还是只是为项目创建的一组特别的struct.packs?
  • 后者,我没有创建这个程序。它是 tribler 的 ipv8 项目github.com/Tribler/py-ipv8/blob/master/ipv8/messaging/… 的一部分。我只需要解释他们发送的数据。 Bincode 似乎是最好的方法,我实现了他们标准的 90%。它主要是关于他们发送的可变长度的东西,因为它们的长度前缀与 bincode 不兼容。

标签: rust deserialization serde


【解决方案1】:

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

我建议您获取 bincode 来源 — 它们是 MIT 许可的,因此您基本上可以随意使用它们 - 并修改它们以适合您的格式(并给出您的名字并将其包含在您的项目)。

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

【讨论】:

  • 好的。我已经害怕这会是答案。不过感谢您的帮助。
【解决方案2】:

我已经找到了一种(可能非常难看)的方法来实现它,而无需实现我自己的反序列化器——毕竟 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)?);
    }
}

简而言之,我让系统认为我反序列化了一个元组,我将长度设置为我需要的最大值。我已经对此进行了测试,它实际上并没有分配那么多内存。然后我表现得好像长度是这个元组的一部分,先阅读它,然后继续阅读这个长度告诉我的内容。它不漂亮,但它确实有效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-21
    • 1970-01-01
    相关资源
    最近更新 更多