Ржавчина десериализуется json на основе перечисления в json - PullRequest
0 голосов
/ 28 февраля 2020

Можно ли использовать значение в JSON, чтобы определить, как десериализовать остальную часть JSON с использованием serde? Например, рассмотрим следующий код:

use serde::{Serialize, Deserialize};
use serde_repr::*;

#[derive(Serialize_repr, Deserialize_repr, Debug)]
#[repr(u8)]
enum StructType {
    Foo = 1,
    Bar = 2
}

#[derive(Serialize, Deserialize, Debug)]
struct Foo {
    a: String,
    b: u8
}

#[derive(Serialize, Deserialize, Debug)]
struct Bar {
    x: String,
    y: u32,
    z: u16
}

#[derive(Serialize, Deserialize, Debug)]
struct AllMyStuff {
    type: StructType,
    data: //HELP: Not sure what to put here
}

Я пытаюсь добиться десериализации данных, даже если в несколько этапов поле type в AllMyStuff определяет, какой тип данные структуры присутствуют в data. Например, учитывая следующий псевдокод, я хотел бы в конечном итоге иметь структуру Bar с надлежащими данными в ней:

data = {"type": "2", "data": { "x": "Hello world", "y": "18", "z": "5" } }
// 1) use serde_json to deserialize a AllMyStuff struct, not erroring on the "data" blob
// 2) Now that we know data is of type "2" (or Bar), parse the remaining "data" into a AllMyStuff struct

Если шаги (1) и (2) каким-то образом можно сделано за один шаг, это было бы здорово, но не нужно. Я не уверен, какой тип объявить data в структуре AllMyStuff, чтобы включить это.

Ответы [ 2 ]

1 голос
/ 28 февраля 2020

Вы можете использовать serde_json::Value в качестве типа для AllMyStuff::data. Он десериализует любой действительный json объект, а также реализует сам Deserialize, поэтому его можно дополнительно десериализовать, когда известен тип для десериализации (через AllMyStuff::type). Хотя для этого требуются более прерывистые шаги и (в основном временные) типы, это избавляет вас от ручной реализации Deserialize на enum AllMyStuff { Foo(Foo), Bar(Bar) }.

1 голос
/ 28 февраля 2020

Я могу что-то упустить, но AllMyStuff выглядит так, как будто вы пытаетесь вручную различить guish между Foo и Bar.

Однако у Rust есть встроенный способ сделать это:

#[derive(Serialize, Deserialize, Debug)]
enum AllMyStuff {
    Foo(Foo),
    Bar(Bar),
}

Нажмите здесь , чтобы увидеть его в действии.

...