У меня проблема с библиотекой bincode Rust. Когда он сериализует вектор, он всегда предполагает, что длина префикса составляет 8 байтов. Это хорошее предположение, когда вы всегда кодируете данные с помощью bincode, потому что bincode может считывать свои собственные сериализованные данные.
Я нахожусь в ситуации, когда я не могу повлиять на сериализатор, поскольку я его не писал, и он должен оставаться прежним по устаревшим причинам. Он кодирует свои векторы в виде массива с префиксом длины, где префикс всегда равен 2 байтам (или, в некоторых случаях, 4 байтам, но я хорошо знаю такие случаи. Как только я знаю, как это сделать с 2 байтами, 4 байта не должны быть проблема).
Как я могу использовать bincode (и serde в этом отношении) для десериализации этих полей? Могу ли я обойти 8 байтов длины по умолчанию, жестко закодированных в bincode?
Эти данные сериализуются программой Python и отправляются через сокет udp.
Но является ли сериализация в программе python общедоступным форматом? Или это просто специальный набор struct.pack
, созданный для проекта?
Последнее, и я не создавал эту программу. Это часть проекта Tribler ipv8 github.com/Tribler/py-ipv8/blob/master/ipv8/messaging/…. Мне просто нужно интерпретировать данные, которые они посылают. Bincode показался мне лучшим способом, и я реализовал 90% их стандарта. В основном это касается вещей переменной длины, которые они отправляют, поскольку их префикс длины несовместим с бинкодом.
Бинкод не должен быть совместим с любым существующим сериализатором или стандартом. Согласно комментарию, это не тот формат, который вы пытаетесь прочитать.
Я предлагаю вам получить исходники бинкод — они лицензированы MIT, так что вы можете делать с ними практически все, что пожелаете, — и модифицировать их в соответствии с вашим форматом (и дать им свое имя, и включить их в свой проект).
serde::Deserializer
довольно хорошо задокументирован, как и базовый модель данных, а реализацию в бинкоде найти несложно (в 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)?);
}
}
Короче говоря, я заставляю систему думать, что я десериализую кортеж, где я устанавливаю максимальную длину, которая мне нужна. Я проверял это, на самом деле он не выделяет столько памяти. Затем я действую так, как будто длина является частью этого кортежа, сначала читаю его, а затем продолжаю читать до тех пор, пока эта длина говорит мне. Это не красиво, но это, безусловно, работает.
Что это за сериализатор, из которого вы пытаетесь декодировать данные? Bincode не должен быть совместим ни с какими существующими сериализаторами.