I need to update specific fields of an arbitrary input file without touching any keys or values that my program does not know about.
Here is an example input file:
{
"alpha": {
"a": 1,
"z": 2
},
"beta": "b"
}
I'd like to update alpha.a
by 100:
{
"alpha": {
"a": 101,
"z": 2
},
"beta": "b"
}
It is possible to do this with types like serde_json::Value
and toml::value::Value
, but this code is very cumbersome:
extern crate serde; // 1.0.66
extern crate serde_json; // 1.0.21
use serde_json::Value;
fn main() {
let input = r#"{
"alpha": {
"a": 1,
"z": 2
},
"beta": "b"
}"#;
let mut to_change: Value = serde_json::from_str(input).unwrap();
{
let obj = to_change.as_object_mut().unwrap();
let alpha = obj.get_mut("alpha").unwrap();
let obj = alpha.as_object_mut().unwrap();
let num = {
let a = obj.get("a").unwrap();
let mut num = a.as_i64().unwrap();
num += 100;
num
};
obj.insert("a".into(), Value::Number(num.into()));
}
println!("{}", serde_json::to_string_pretty(&to_change).unwrap());
}
I'd much rather use the clean derived syntax:
extern crate serde; // 1.0.66
#[macro_use]
extern crate serde_derive; // 1.0.66
extern crate serde_json; // 1.0.21
#[derive(Debug, Deserialize, Serialize)]
struct WhatICareAbout {
alpha: Alpha,
}
#[derive(Debug, Deserialize, Serialize)]
struct Alpha {
a: i32,
}
fn main() {
let input = r#"{
"alpha": {
"a": 1,
"z": 2
},
"beta": "b"
}"#;
let mut subobject: WhatICareAbout = serde_json::from_str(input).unwrap();
subobject.alpha.a += 1;
println!("{}", serde_json::to_string_pretty(&subobject).unwrap());
}
This runs, but it strips out any unknown keys:
{
"alpha": {
"a": 2
}
}
Is there a way I can use the pretty Deserialize
and Serialize
implementations while still preserving keys and values I don't know about?
An ideal answer would:
- Work for most Serde formats — I'm showing JSON here but my real code is TOML.
- Allow adding, updating, and removing fields.