How to deserialize a Vec of structures inside a Yaml with serde

Let says that I have this Yaml:

countries:
  cities:
    paris:
      - street: "ranom_name_1"
        weather: 12
        pollution: 2
      - sreet: "ranom_name_2"
        weather: 15
        pollution: 1
    london:
      - street: "ranom_name_1"
        weather: 5
        pollution: 1
        rank: 1
      - sreet: "ranom_name_2"
        weather: 1
        pollution: 4
        rank: 2

After I made the needed structures :

#[derive(Debug, Deserialize)]
struct Paris {
	street: String,
    weather: u16,
    pollution: u16,
}

#[derive(Debug, Deserialize)]
struct London {
	street: String,
    weather: u16,
    pollution: u16,
	rank: u16,
}

#[derive(Debug, Deserialize)]
struct Cities {
    #[serde(flatten)]
    paris: Vec<Paris>,
    #[serde(flatten)]
    london: Vec<London>,
}

#[derive(Debug, Deserialize)]
struct Country {
    #[serde(flatten)]
    cities: Cities,
}

pub struct Data {
    #[serde(flatten)]
    coutries: Country,
}

The problem is that serde can't flatten Vec, so when I call :

    let data = serde_yaml::from_str::<Data>(data_yaml);

I get this error :

Error : can only flatten structs and maps at line 3 column 7

My question is, how can I deserialize my Yaml ?

Why do you think you need #[serde(flatten)] for this at all? You don't. Your data structures seem to match your YAML exactly, except for some typos, the missing rank field, and the missing #[derive(Debug, Deserialize)] on Data. If you fix those, the result compiles and runs as expected.

1 Like

Thanks, worked!!!

As I'm new to Rust, I thought the #[serde(flatten)] must be used on every structure.

No. Please read the relevant documentation. Flattening is specifically used for merging the contents of a field into its parent type. If you don't want that, #[derive(Serialize, Deserialize)] does the correct thing by default, field-by-field.


In general, Rust libraries won't purposefully make you write boilerplate code. It is in fact the very point of using a procedural macro such as #[derive] to remove boilerplate code.

1 Like