BurntSushi / rust-csv

A CSV parser for Rust, with Serde support.
The Unlicense
1.72k stars 219 forks source link

Cannot Deserialize Serialize output when outer type is an untagged enum. #360

Open cafce25 opened 7 months ago

cafce25 commented 7 months ago

What version of the csv crate are you using?

1.3.0

Briefly describe the question, bug or feature request.

I want to deserialize different rows of a CSV file differently depending on wether a field can be serialized into an enum or is empty, I tried using a #[serde(untagged)] enum for that, but although that produces the expected output when serializing, it does fail to deserialize it (and it's own output).

Include a complete program demonstrating a problem.

use serde::{Serialize, Deserialize};

#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(untagged)]
enum MaybeRecord {
    Record(Record),
    Partial(Partial),
}
#[derive(Debug, Serialize, Deserialize, Clone)]
struct Partial {
    name: String,
    ty: (),
}
#[derive(Debug, Serialize, Deserialize, Clone)]
enum Ty {
    One,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Record{
    name: String,
    ty: Ty,
}

fn serialize() -> Result<String, Box<dyn std::error::Error>> {
    let mut wrtr = csv::Writer::from_writer(Vec::new());
    wrtr.serialize(&MaybeRecord::Partial(Partial {
        name: String::from("baz"),
        ty: (),
    }))?;
    wrtr.serialize(&MaybeRecord::Record(Record {
        name: String::from("foo"),
        ty: Ty::One,
    }))?;
    Ok(String::from_utf8(wrtr.into_inner()?)?)
}
fn deserialize(data: &str) -> Result<(), Box<dyn std::error::Error>> {
    let mut rdr = csv::Reader::from_reader(data.as_bytes());
    for record in rdr.deserialize::<MaybeRecord>() {
        dbg!(record)?;
    }
    Ok(())
}
fn main() {
    let serialized = serialize().unwrap();
    println!("----\n{serialized}\n----");
    deserialize(&serialized).unwrap();

}

Playground

What is the observed behavior of the code above?

Standard Error

   Compiling playground v0.0.1 (/playground)
    Finished dev [unoptimized + debuginfo] target(s) in 1.01s
     Running `target/debug/playground`
[src/main.rs:40:9] record = Err(
    Error(
        Deserialize {
            pos: Some(
                Position {
                    byte: 8,
                    line: 2,
                    record: 1,
                },
            ),
            err: DeserializeError {
                field: None,
                kind: Message(
                    "data did not match any variant of untagged enum MaybeRecord",
                ),
            },
        },
    ),
)
thread 'main' panicked at src/main.rs:47:30:
called `Result::unwrap()` on an `Err` value: Error(Deserialize { pos: Some(Position { byte: 8, line: 2, record: 1 }), err: DeserializeError { field: None, kind: Message("data did not match any variant of untagged enum MaybeRecord") } })
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Standard Output

----
name,ty
baz,
foo,One

----

What is the expected or desired behavior of the code above?

While stdout shows that serialization was successfull, deserializing that very output fails.