我可以使用 Bincode 反序列化具有可变长度前缀的向量吗?
Can I deserialize vectors with variable length prefix with Bincode?
我在使用 Rust bincode 库时遇到问题。当它序列化一个向量时,它总是假设前缀长度是 8 个字节。当您总是使用 bincode 对数据进行编码时,这是一个很好的假设,因为 bincode 可以读取它自己的序列化数据。
我处于无法影响序列化程序的情况,因为我没有编写它,并且由于遗留原因它必须保持不变。它将其向量编码为长度前缀数组,其中前缀始终为 2 个字节(或者在某些情况下为 4 个字节,但我很了解这些情况。一旦我知道如何用 2 个字节来做,4 个字节不应该是问题)。
如何使用 bincode(和 serde)来反序列化这些字段?我可以绕过 bincode 中硬编码的默认 8 字节长度吗?
Bincode 不应该与任何现有的序列化程序或标准兼容。根据评论,您尝试阅读的格式也不是。
我建议你获取 bincode 源——它们是 MIT-licensed,这样你基本上可以随心所欲地使用它们——并修改它们以适合你的格式(并赋予它你的命名并将其包含在您的项目中)。
serde::Deserializer
is quite well documented, as is the underlying data model,bincode 中的实现很容易找到(在 de/mod.rs
中),因此将其作为您的起点并根据需要进行调整。
我想出了一个(可能非常丑陋的)方法来实现它而不用实现我自己的反序列化器——毕竟 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)?);
}
}
简而言之,我让系统认为我反序列化了一个元组,我将长度设置为我需要的最大值。我已经测试过了,它实际上并没有分配那么多内存。然后我就好像长度是这个元组的一部分一样,先阅读它,然后继续阅读这个长度告诉我的范围。它不漂亮,但确实有效。
我在使用 Rust bincode 库时遇到问题。当它序列化一个向量时,它总是假设前缀长度是 8 个字节。当您总是使用 bincode 对数据进行编码时,这是一个很好的假设,因为 bincode 可以读取它自己的序列化数据。
我处于无法影响序列化程序的情况,因为我没有编写它,并且由于遗留原因它必须保持不变。它将其向量编码为长度前缀数组,其中前缀始终为 2 个字节(或者在某些情况下为 4 个字节,但我很了解这些情况。一旦我知道如何用 2 个字节来做,4 个字节不应该是问题)。
如何使用 bincode(和 serde)来反序列化这些字段?我可以绕过 bincode 中硬编码的默认 8 字节长度吗?
Bincode 不应该与任何现有的序列化程序或标准兼容。根据评论,您尝试阅读的格式也不是。
我建议你获取 bincode 源——它们是 MIT-licensed,这样你基本上可以随心所欲地使用它们——并修改它们以适合你的格式(并赋予它你的命名并将其包含在您的项目中)。
serde::Deserializer
is quite well documented, as is the underlying data model,bincode 中的实现很容易找到(在 de/mod.rs
中),因此将其作为您的起点并根据需要进行调整。
我想出了一个(可能非常丑陋的)方法来实现它而不用实现我自己的反序列化器——毕竟 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)?);
}
}
简而言之,我让系统认为我反序列化了一个元组,我将长度设置为我需要的最大值。我已经测试过了,它实际上并没有分配那么多内存。然后我就好像长度是这个元组的一部分一样,先阅读它,然后继续阅读这个长度告诉我的范围。它不漂亮,但确实有效。