I have a setup like this
#[derive(Deserialize)]
struct GameData {
game: String,
player_data: Vec<MarioPartyData>,
<more common data>
}
#[derive(Deserialize)]
#[serde(untagged)]
enum MarioPartyData {
MarioParty(MarioParty),
MarioParty2(MarioParty2),
MarioParty3(MarioParty3),
<many more variants>
}
#[derive(Deserialize)]
struct MarioParty {
stars: i32,
coins: i32,
spaces_walked: i32
}
#[derive(Deserialize)]
struct MarioParty2 {
stars: i32,
coins: i32
}
#[derive(Deserialize)]
struct MarioParty3 {
stars: i32,
coins: i32
}
This almost works. The problem is that some games have the exact same structure so when I deserialize MarioParty3
, in this instance, it becomes a MarioParty2
variant, because that's the first one it matches. The game
field should be able to uniquely identify which game to deserialize into, but I can't figure out how to use the different tagging macros in serde
to accomplish that, or if it's even possible. I'm hoping to avoid implementing the deserializer myself. There's also a slight wrinkle in that the game
field won't be "MarioParty3"
, but rather "Mario Party 3"
, I think this might be handled with something like #[serde(rename = "Mario Party 3")]
though?
A valid JSON
input for a MarioParty3
instance might look like this
{
"game": "Mario Party 3",
"player_data": [
{
"stars": 3,
"coins" 45
}
]
}
I'm not against changing any of the structures I have in rust
, but the JSON
coming in is pretty firm. Any advice is appreciated!
The most straightforward way to represent this JSON using Serde is with an adjacently tagged enum.
#[derive(Deserialize)]
struct GameData {
#[serde(flatten)]
player_data: MarioPartyData,
// <more common data>
}
#[derive(Deserialize)]
#[serde(tag = "game", content = "player_data")]
enum MarioPartyData {
#[serde(rename = "Mario Party")]
MarioParty(Vec<MarioParty>),
#[serde(rename = "Mario Party 2")]
MarioParty2(Vec<MarioParty2>),
#[serde(rename = "Mario Party 3")]
MarioParty3(Vec<MarioParty3>),
// <many more variants>
}
This does change the structure so that the Vec
occurs inside the enum, forcing each Vec
to only contain one type. This sounds like it reflects your JSON alright, but might change how you deal with it in Rust.