简体   繁体   中英

Rust deserialize json based on an enum in the json

Is it possible to use a value in JSON to determine how to deserialize the rest of the JSON using serde? For example, consider the following code:

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
}

What I'm trying to achieve is deserialization of the data, even if in multiple steps, where the type field in the AllMyStuff determines which type of struct data is present in data . For example, given the following pseudocode, I'd like to ultimately have a Bar struct with the proper data in it:

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

If steps (1) and (2) are somehow able to be done in a single step, that would be awesome but not needed. I'm not sure what type of type to declare data in the AllMyStuff struct to enable this as well.

I may be missing something, but AllMyStuff looks as if you are trying to manually distinguish between Foo and Bar .

However, Rust, has a built-in way of doing this:

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

Click here to see it in action.

You can use serde_json::Value as the type for AllMyStuff::data . It will deserialize any valid json object and also implements Deserialize itself, so it can be further deserialized once the type to deserialize to is known (via AllMyStuff::type ). While this requires more intermittent steps and (mostly temporary) types, it saves you from manually implementing Deserialize on an enum AllMyStuff { Foo(Foo), Bar(Bar) } .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM