How to derive serialize/deserialize for Vec of a struct as a CSV field?

Here are 3 structs: MainStruct, InnerStruct and MyEnum, and I want MainStruct to be serialized into a row in CSV, and it has a field which is Vec<InnerStruct>.

Gist on Playground

#[derive(Serialize, Deserialize, Debug)]
pub struct MyMainStruct {
	pub field1: i32,
	pub field2: Vec<InnerStruct>
}

#[derive(Serialize, Deserialize, Debug)]
pub struct InnerStruct {
	pub field3: i32,
	pub field4: MyEnum
}

#[derive(Serialize, Deserialize, Debug)]
pub enum MyEnum {
	#[serde(rename="for")]
	Forward,
	#[serde(rename="back")]
	Backward,
}

By default, Serde can't serialize it into CSV. It compiles correctly, but then outputs a serialization error.

I could use a #[serde(with=...)] macro and write a conversion of InnerStruct -> String. But it will require manual unpacking and will break if InnerStruct changes.

I tried using serialize_seq in my serialization code, but it fails the same way as without #[serde(with...)], when running.

Another option I tried was to run ..iter().map(|inner| inner.serialize(serializer)).collect().join(","), but serialize outputs a "serialization object", not a String.

I looked at making impl<...> Serialize<...> for Vec<InnerStruct> but it looks overly complicated.

Is there any elegant way to write serialization?

Please share some example CSV output you want to get from the serialization.

InnerStruct may be serialized as a small CSV line, like "123,for", and multiple of them may be semicolon-separated: "123,for;456,back;789,for".

So the result will be like:

field1,field2
987,"123,for;456,back;789,for"
654,"888,for"
321,""

I could write this encoding/decoding, but the real example has more fields, and feels like it'll be more tedious. That's why I'm asking if there's an elegant way.

CSV doesn't natively have a way to encode non-atomic nested values; it's for flat tables where every column is a simple value (number, string, missing, etc.)

Why do you expect an arbitrary serializer to output a String? That doesn't make much sense. Serializers are generic, there are many kinds of serializers for many formats (that's the point of Serde), and they can't just give you a string.

You can't impl Serialize for Vec because it's already implemented by Serde itself, so it would fail the coherence rules.

If you want that particular format, you'll have to implement it manually.

1 Like

I know they should output a serialized object, and when I wrote one for Vec<u32> I converted it to String, then used serialize_str.

It's just I have to get just something working.

All right.

Here's an example that produces CSV-in-CSV.

2 Likes

csv supports vec types for Serialize/Deserialize if you ignore the header: Writer in csv - Rust

1 Like

As @H2CO3 said:

CSV doesn't natively have a way to encode non-atomic nested values

Tab Separated Values can do the work. Four years ago I wrote a crate named tsv. It utilize tabular data to represent hierarchical values, and can be viewed/edited in Excel. FYI.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.