Могу ли я десериализовать векторы с префиксом переменной длины с помощью Bincode?

У меня проблема с библиотекой bincode Rust. Когда он сериализует вектор, он всегда предполагает, что длина префикса составляет 8 байтов. Это хорошее предположение, когда вы всегда кодируете данные с помощью bincode, потому что bincode может считывать свои собственные сериализованные данные.

Я нахожусь в ситуации, когда я не могу повлиять на сериализатор, поскольку я его не писал, и он должен оставаться прежним по устаревшим причинам. Он кодирует свои векторы в виде массива с префиксом длины, где префикс всегда равен 2 байтам (или, в некоторых случаях, 4 байтам, но я хорошо знаю такие случаи. Как только я знаю, как это сделать с 2 байтами, 4 байта не должны быть проблема).

Как я могу использовать bincode (и serde в этом отношении) для десериализации этих полей? Могу ли я обойти 8 байтов длины по умолчанию, жестко закодированных в bincode?

Что это за сериализатор, из которого вы пытаетесь декодировать данные? Bincode не должен быть совместим ни с какими существующими сериализаторами.

Jan Hudec 20.05.2019 13:21

Эти данные сериализуются программой Python и отправляются через сокет udp.

jonathan 20.05.2019 13:25

Но является ли сериализация в программе python общедоступным форматом? Или это просто специальный набор struct.pack, созданный для проекта?

Jan Hudec 20.05.2019 13:38

Последнее, и я не создавал эту программу. Это часть проекта Tribler ipv8 github.com/Tribler/py-ipv8/blob/master/ipv8/messaging/…. Мне просто нужно интерпретировать данные, которые они посылают. Bincode показался мне лучшим способом, и я реализовал 90% их стандарта. В основном это касается вещей переменной длины, которые они отправляют, поскольку их префикс длины несовместим с бинкодом.

jonathan 20.05.2019 13:39
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
2
4
1 230
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Бинкод не должен быть совместим с любым существующим сериализатором или стандартом. Согласно комментарию, это не тот формат, который вы пытаетесь прочитать.

Я предлагаю вам получить исходники бинкод — они лицензированы MIT, так что вы можете делать с ними практически все, что пожелаете, — и модифицировать их в соответствии с вашим форматом (и дать им свое имя, и включить их в свой проект).

serde::Deserializer довольно хорошо задокументирован, как и базовый модель данных, а реализацию в бинкоде найти несложно (в de/mod.rs), поэтому возьмите его за отправную точку и при необходимости настройте.

Хорошо. Я уже боялся, что это будет ответ. Спасибо за вашу помощь.

jonathan 20.05.2019 13:53

Я придумал (возможно, очень уродливый) способ сделать это без реализации собственного десериализатора — в конце концов 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)?);
    }
}

Короче говоря, я заставляю систему думать, что я десериализую кортеж, где я устанавливаю максимальную длину, которая мне нужна. Я проверял это, на самом деле он не выделяет столько памяти. Затем я действую так, как будто длина является частью этого кортежа, сначала читаю его, а затем продолжаю читать до тех пор, пока эта длина говорит мне. Это не красиво, но это, безусловно, работает.

Другие вопросы по теме