How can I dynamically define the struct for serde_json when the JSON structure is changed without recompiling?

2.9k views Asked by At

For example, we add a structure that is used inside a *.rs script

#[derive(Serialize, Deserialize, Debug)]
struct Foo {
    Output: OUTPUT,
    input: INPUT,
    logs: LOGS,
}

#[derive(Serialize, Deserialize, Debug)]
struct OUTPUT {
    width: u32,
    samplerate: u32,
}

#[derive(Serialize, Deserialize, Debug)]
struct INPUT {
    fileinputuri: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct LOGS {
    statuslog: String,
}

This is referenced by

let var: Foo = serde_json::from_str(&contents).expect("error while reading json");

When I change the field width: u32, to n_width: u32, in the JSON we would change the struct to

#[derive(Serialize, Deserialize, Debug)]
struct OUTPUT {
    n_width: u32,
    samplerate: u32,
}

Rather than add this to the *.rs file and update it each time, could the struct be extracted to a configuration file and updated and loaded at function call time?

Are there any safety or performance implications for separating the struct from the *.rs file?

Is there a better anonymous/unnamed way that changes to the JSON could be made without needing to update the struct?

Per a comment below, using serde_json::Value is an option, but is this a safe method that can be used in place of a strongly typed structure? I'm worried about memory safety and security against manipulation by a malicious user that gains access to the JSON file.

pub enum Value {
    Null,
    Bool(bool),
    Number(Number),
    String(String),
    Array(Vec<Value>),
    Object(Map<String, Value>),
}

Assume that there is no further reference needed to the n_width field in this program, so no need to open the code by the Rust development team, only the JSON team would make the changes to the JSON file and the struct file.

2

There are 2 answers

0
Shepmaster On BEST ANSWER

Assume that there is no further reference needed to the n_width field in this program, so no need to open the code by the Rust development team, only the JSON team would make the changes to the JSON file and the struct file.

If the Rust code doesn't care about the fields, then don't add them to the structs in the first place. Additional fields in the data that aren't included in the structure will be silently ignored by default.

If you need to bundle along extra data but never need to operate on it within the Rust code (such as in a proxy application), then review How can I use Serde's custom (de)serialization to update a subset of arbitrary input?

0
kmdreko On

If you want dynamically defined data validation, you should look into using something like JSON Schema.

If you need a mix of dynamic and static fields, this can be used along with serde(flatten) (as pointed out in Shepmaster's answer).