rust-csv icon indicating copy to clipboard operation
rust-csv copied to clipboard

[lowpri] serialization of containers-in-structs errors differently depending on the circumstances

Open guswynn opened this issue 4 years ago • 1 comments

Thank you for taking the time to file a bug report. The following describes some guidelines to creating a minimally useful ticket.

Above all else: do not describe your problem, SHOW your problem.

What version of the csv crate are you using?

1.1.5

Briefly describe the question, bug or feature request.

I was looking into how the csv crate implemented serde serialization/deserialization, and noticed a discrepancy.

In this case: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=0093262a4a6e3a775a70df76c8e9a91f

use std::error::Error;
use std::io;
use std::process;
use csv; // 1.1.5
use serde;

use serde::Serialize;

#[derive(Debug, Serialize)]
struct Record {
    city: String,
    region: String,
    country: String,
    population: Option<u64>,
    v: Vec<i64>,
}

fn example() -> Result<(), Box<dyn Error>> {
    let mut wtr = csv::Writer::from_writer(io::stdout());

    // When writing records with Serde using structs, the header row is written
    // automatically.
    wtr.serialize(Record {
        city: "Southborough".to_string(),
        region: "MA".to_string(),
        country: "United States".to_string(),
        population: Some(9686),
        v: vec![1, 2, 3, 4],
    })?;
    wtr.serialize(Record {
        city: "Northbridge".to_string(),
        region: "MA".to_string(),
        country: "United States".to_string(),
        population: Some(14061),
        v: vec![1, 2, 3, 4],
    })?;
    wtr.flush()?;
    Ok(())
}

fn main() {
    if let Err(err) = example() {
        println!("error running example: {}", err);
        process::exit(1);
    }
}

outputs

city,region,country,population,verror running example: CSV write error: cannot serialize sequence container inside struct when writing headers from structs

It very clearly states that the problem is, serializing containers in a struct is impossible.

However https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d9fe9283bd43cfce5fc9bebbde843ef3

    wtr.serialize(Record {
        city: "Southborough".to_string(),
        region: "MA".to_string(),
        country: "United States".to_string(),
        population: Some(9686),
        v: Some(vec![1, 2, 3, 4]),
    })?;
    wtr.serialize(Record {
        city: "Northbridge".to_string(),
        region: "MA".to_string(),
        country: "United States".to_string(),
        population: Some(14061),
        v: Some(vec![1, 2, 3, 4]),
    })?;

outputs

city,region,country,population,v
Southborough,MA,United States,9686,1,2,3,4error running example: CSV error: found record with 8 fields, but the previous record has 5 fields

showing that only the Writer notices the problem of "containers-in-structs" when it notices there are too many fields.

Similarly https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=275fdb4cf35a29bb47786590c699bcfc shows that things like tuple structs fail late as well, and https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=275fdb4cf35a29bb47786590c699bcfc shows that top-level sequences only work if they are the exact same size.

Looking into the code of the serializer, and thinking about how csv works, it makes sense why this behavior is the way it is, however, I am wondering, do you think it would be worth it to restructure the serializer so it could give better error messages? I would be willing to look into this, unless you think its not possible/very difficult

guswynn avatar Jan 07 '21 00:01 guswynn