CSV with nested structs

55 views Asked by At

I'm trying to serialize an object made of nested structs to CSV. The reason for nesting is purely code organization and I don't expect it to remain after serialization. This code example represents what I have (playground)

use serde::Serialize;
use std::io;

#[derive(Serialize)]
struct UserInfo {
    id: String,
    username: String,
}

#[derive(Serialize)]
struct User {
    user_info: UserInfo,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut wtr = csv::Writer::from_writer(io::stdout());
    wtr.serialize(User {
        user_info: UserInfo {
            id: "1".to_string(),
            username: "Jon".to_string(),
        },
    })?;
    wtr.flush()?;
    Ok(())
}

Running this gives me this error

Error(Serialize("cannot serialize UserInfo container inside struct when writing headers from structs"))

I tried adding #[serde(flatten)] to user_info, but that's also not supported according to this issue.

What would be a workaround for this? I don't mind adding the headers manually if that would help. I just want to keep the nesting.

1

There are 1 answers

0
cafce25 On BEST ANSWER

There is a workaround in the comment thread under the issue you linked:

use serde::Serialize;
fn main() {
  let mut w = csv::Writer::from_writer(std::io::stdout());
  w.serialize(Data::<CustomColumns>::default()).unwrap();
}

#[derive(Debug, Serialize, Default)]
struct Data<Extra: Serialize + Default>(DataInner, Extra);

#[derive(Debug, Serialize, Default)]
struct DataInner {
  a: usize,
  b: String,
}

#[derive(Debug, Serialize, Default)]
struct CustomColumns {
  custom: String,
}

That is, make the top most struct a tuple struct, and put all previously nested structs thereby removing the unsupported nesting side by side in it for example:

#[derive(Serialize)]
struct UserInfo {
    id: String,
    username: String,
}

#[derive(Serialize)]
struct UserRow(User, UserInfo);

#[derive(Serialize)]
struct User {
    other_user_field: &'static str,
}