Deserialise dynamic externally tagged values with serde?

Viewed 243

I've come across some data I'm trying to translate into a struct to use with serde. It's a nested dictionary where each subsequent entry's key is the version number of the piece of data. I can't wrap my head around how to translate this into a serde struct that will read a dynamic number of these versions. I attached a terrible example of what I came up with but this is definitely is wrong.

I'm not sure exactly what key terms I can use to search for information on this. The one thing I did find in the documentation were externally tagged enums however I'm not quite sure this will help me.

{
    "v0001": {
        "id": "a"
        // ...
    },
    "v0002": {
        "id": "b"
        // ...
    }
    "v0003": {
        "id": "c"
        // ...
    }
    // ...
}
use serde::{Deserialize, Serialize};

#[derive(Debug, Default, Serialize, Deserialize)]
pub struct Data {
    pub v0001: Version,
    pub v0002: Version,
    pub v0003: Version,
    // ??!
}

#[derive(Debug, Default, Serialize, Deserialize)]
pub struct Version {
    id: String,
}

What I'm ultimately trying to do is, load the json, append a new version and rewrite it back to json.

Any help/thoughts/feedback would be amazing! :)

1 Answers

After @cdknight's suggestion to use a HashMap I realized that the root data type didn't have to be a struct. Here's a working solution I came up with. I used a BTreeMap instead so the keys would be in order.

type Data = BTreeMap<String, Version>;

#[derive(Debug, Serialize, Deserialize)]
struct Version {
    pub id: String,
}

fn main() {
    let input = r#"
    {
        "v0001": {
            "id": "a"
        },
        "v0002": {
            "id": "b"
        },
        "v0003": {
            "id": "c"
        }
    }"#;

    let data: Data = serde_json::from_str(input).unwrap();
    dbg!(&data);

    let vec: Vec<Version> = data.into_values().collect();
    dbg!(&vec);
}

Ouputs:

[src/main.rs:106] &data = {
    "v0001": Version {
        id: "a",
    },
    "v0002": Version {
        id: "b",
    },
    "v0003": Version {
        id: "c",
    },
}
[src/main.rs:109] &vec = [
    Version {
        id: "a",
    },
    Version {
        id: "b",
    },
    Version {
        id: "c",
    },
]
Related