Size: a a a

Rust — русскоговорящее сообщество

2021 June 28

PI

Pavel Ivanov in Rust — русскоговорящее сообщество
Всем привет!
Кто-нибудь может подсказать как с помощью serde_json сделать десериализацию структуры со следующимм требованиями:
1. Десериализация из буфера &[u8]
2. Zero allocations до тех пор, пока не превышен лимит на кол-во элементов в одной структуре (реализуется через heapless)
3. Zero copy, т.е. используется &str для десериализации строк
4. Использование произвольного runtime контекста (конфигурации), влияющего на логику процесса десериализации
5. Возмжоность после десериализации одной или нескольких таких структур узнать сколько байт из буфера было десериализовано или сколько в нем осталось

Если убрать пункт 5 или пункт 4, то задача решена.
А вот совместить их никак не удается.
Единственный механизм, который позволил бы удовлетворить требование 5 из тех, что я нашел - это serde_json::de::StreamDeserializer, который возвращается из serde_json::de::Deserializer::into_iter(), у него есть byte_offset(), и он сам по себе работает, но вот как его совместить с пунктом 4, я так и не смог понять.
Пытался применить сюда DeserializeSeed, но он не вяжется со StreamDeserializer и не дает никакого способа притащить контекст снаружи.

Единственный понятный вариант - это двухэтапная десериализация через промежуточную стуктуру, в которую надо будет все поля из json объекта сначала сложить, а потом уже отдельным вызовом какой-то функции, в которую будет передан контекст, сконвертировать ее в конечную структуру.
Вот только этого хотелось бы избежать из соображений эффективности.
источник

D

Denis in Rust — русскоговорящее сообщество
5. Возмжоность после десериализации одной или нескольких таких структур узнать сколько байт из буфера было десериализовано или сколько в нем осталось
дык надо просто буфер инструментировать, чтобы он запоминал, сколько из него прочитано. если там массив, то можно просто в std::io::Cursor завернуть
источник

PI

Pavel Ivanov in Rust — русскоговорящее сообщество
Тогда прощай zero copy и zero allocations
источник

D

Denis in Rust — русскоговорящее сообщество
чего это?
источник

D

Denis in Rust — русскоговорящее сообщество
а ну хотя да
источник

D

Denis in Rust — русскоговорящее сообщество
ща, проверю одну идею
источник

D

Denis in Rust — русскоговорящее сообщество
ну да, наверное тогда только StreamDeserializer
источник

D

Denis in Rust — русскоговорящее сообщество
4. Использование произвольного runtime контекста (конфигурации), влияющего на логику процесса десериализации

тут несколько непонятно, что это вообще значит, то есть какого рода влияние, как оно вообще реализуется?
источник

PI

Pavel Ivanov in Rust — русскоговорящее сообщество
Ну, например, конфигурацией определяется какие имена предопределенных полей, какие-то правила маппинга одних полей в другие, фильтр полей, которые надо игнорировать, и т.д.
источник

D

Denis in Rust — русскоговорящее сообщество
мм, нельзя ли это решить кастомной имплементацией трейта DeserializeSeed?
источник

PI

Pavel Ivanov in Rust — русскоговорящее сообщество
Ну вот я не понял как это сделать.
1. Как ему снаружи притащить эту конфигурацию?
2. Как его совместить со StreamDeserializer? Судя по имплементации последнего - никак.
источник

D

Denis in Rust — русскоговорящее сообщество
>  Как ему снаружи притащить эту конфигурацию?

ну вот как раз через сид,

> Как его совместить со StreamDeserializer

StreamDeserializer
имплементит трейт Deserializer, то есть ты на своём типе, который имплементит DeserializeSeed, можешь вызывать .deserialize(stream_deserializer)
источник

D

Denis in Rust — русскоговорящее сообщество
struct Configuration { .. }
impl DeserializeSeed<'de> for Configuration {
 type Value = YourType<'de>;
 fn deserialize<D>(self, deserializer: D) ....
}
источник

D

Denis in Rust — русскоговорящее сообщество
наверное нужно даже для &Configuration реализовывать (с отдельным лайфтаймом, не 'de)
источник

D

Denis in Rust — русскоговорящее сообщество
а, стоп, StreamDeserializer не имелементит Deserialize..
источник

PI

Pavel Ivanov in Rust — русскоговорящее сообщество
> StreamDeserializer имплементит трейт Deserializer

Что-то я не вижу тут такого
https://docs.serde.rs/serde_json/struct.StreamDeserializer.html
источник

D

Denis in Rust — русскоговорящее сообщество
да, промахнулся
источник

PI

Pavel Ivanov in Rust — русскоговорящее сообщество
Насчет &Configuration с отдельным лайфтаймом - это да, так и надо.
источник

D

Denis in Rust — русскоговорящее сообщество
ну тут вариант скопипастить StreamDeserializer, и заменить в нём .next(&mut self) -> Option<Item> на что-то типа .next(&mut self) -> Option<Deserializer<'de>>
источник

PI

Pavel Ivanov in Rust — русскоговорящее сообщество
Его нельзя скопипастить, он весь на приватном API serde_json реализован
источник