Skip to content

Deserializing enums fails at run-time #211

@hniksic

Description

@hniksic

What version of the csv crate are you using?

1.1.3

Briefly describe the question, bug or feature request.

I can't get csv/serde to deserialize an enum.

I am processing a CSV file whose records store several different variants of data. It has a discriminator field and columns specific to each variant (which are empty when the discriminator shows the other variant), as well as some common columns, for example:

EventType,C,A1,B1
A,1,2,
B,3,,4

EventType is the discriminator that discriminates between two variants, A and B. C is the field common to both variants, and A1 and B1 are fields belonging to variants A and B respectively.

I would like to deserialize those rows Rust enums, something like:

enum Event {
    A(AEvent),
    B(BEvent),
}

struct AEvent {
    C: u32,
    A1: u32,
}

struct BEvent {
    C: u32,
    B1: u32,
}

...but I can't get that to successfully run with serde/csv using the code below (or variants thereof that I tested).

Include a complete program demonstrating a problem.

use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(tag = "EventType")]
enum Event {
    A(AEvent),
    B(BEvent),
}

#[allow(non_snake_case)]
#[derive(Debug, Deserialize)]
struct AEvent {
    C: u32,
    A1: u32,
}

#[allow(non_snake_case)]
#[derive(Debug, Deserialize)]
struct BEvent {
    C: u32,
    B1: u32,
}

fn main() {
    let src = std::io::Cursor::new(
        r#"EventType,C,A1,B1
A,1,2,
B,3,,4
"#,
    );
    let mut reciter = csv::ReaderBuilder::new()
        .from_reader(src)
        .into_deserialize::<Event>();
    dbg!(reciter.next());
    dbg!(reciter.next());
}

What is the observed behavior of the code above?

The program outputs errors for both fields, the error message being "invalid type: string \"A\", expected internally tagged enum". Full output:

[src/main.rs:34] reciter.next() = Some(
    Err(
        Error(
            Deserialize {
                pos: Some(
                    Position {
                        byte: 18,
                        line: 2,
                        record: 1,
                    },
                ),
                err: DeserializeError {
                    field: None,
                    kind: Message(
                        "invalid type: string \"A\", expected internally tagged enum",
                    ),
                },
            },
        ),
    ),
)
[src/main.rs:35] reciter.next() = Some(
    Err(
        Error(
            Deserialize {
                pos: Some(
                    Position {
                        byte: 25,
                        line: 3,
                        record: 2,
                    },
                ),
                err: DeserializeError {
                    field: None,
                    kind: Message(
                        "invalid type: string \"B\", expected internally tagged enum",
                    ),
                },
            },
        ),
    ),
)

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

It should output the deserialized records, something like:

reciter.next() = A(
    AEvent {
        C: 1,
        A1: 2,
    },
)
reciter.next() = B(
    BEvent {
        C: 3,
        B1: 4,
    },
)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions