Suppose I have the following structs "Wheel" and "Car" where a "Car" can contain a list of Cars (a recursive definition).
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Wheel {
#[serde(default, rename(deserialize = "Car"))]
pub car: Car,
#[serde(default, rename(deserialize = "Wheel Diameter"))]
pub wheel_diameter: f64,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Car {
#[serde(default, rename(deserialize = "Dealer Price"))]
pub dealer_price: f64,
#[serde(default, rename(deserialize = "Cars"))]
pub cars: Vec<Car>,
}
impl Default for Wheel {
fn default() -> Wheel {
Wheel {
car: Car {
..Default::default()
},
wheel_diameter: 5.0,
}
}
}
impl Default for Car {
fn default() -> Car {
Car {
dealer_price: 1.0,
cars: Vec::new(),
}
}
}
fn main() {
let str_input = r#"[
{
"Wheel Diameter": 5.2,
"Car": {
"Dealer Price": 500,
"Cars": [
{
"Car": {
"Dealer Price": 1500
}
}
]
}
}
]"#;
let cars: Vec<Wheel> = serde_json::from_str(str_input).unwrap();
println!("cars {:#?}", cars);
}
1) When I run the above with str_input
(basically an escape free JSON formatted string), I get the following output:
cars [
Wheel {
car: Car {
dealer_price: 500.0,
cars: [
Car {
dealer_price: 0.0,
cars: [],
},
],
},
wheel_diameter: 5.2,
},
]
The top level initializes the defaults correctly, but the "nested cars" do not get initialized properly in the Vec. How to get this working in serde? I tried adding a with = "serde_with::json::nested"
in various places but that didn't seem to work. I would get errors complaining about Error("invalid type: sequence, expected valid json object", line: 1, column: 61
Does this mean I have to write a custom deserialization somehow?
2) What's a good way to ensure the recursive deserialization doesn't "blow up" the memory? Fairly new to Rust. In Golang, you can pretty much "magically" deserialize this type of structure by adding some string labeled attributes onto the struct responsible for housing the deserialized json.
Note: I realize having a vector of "cars" in the Car struct may not "make sense" from a domain modeling perspective, but I had to do some field renaming to ensure I didn't share code in the wild that wasn't supposed to be shared. So the structure of the code reflects the problem that needs solving even though the names may not make sense conceptually.