Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Duplicated values when flattening an enum. #2234

Closed
morr0ne opened this issue Jun 25, 2022 · 3 comments
Closed

Duplicated values when flattening an enum. #2234

morr0ne opened this issue Jun 25, 2022 · 3 comments

Comments

@morr0ne
Copy link

morr0ne commented Jun 25, 2022

When flattening an enum the values aren't discared and they get deserialized twice.
Here is a reproducible example:

use serde::Deserialize;
use serde_json::Value;

#[derive(Debug, Deserialize)]
struct Parsed {
    name: String,
    #[serde(flatten)]
    status: Status,
    #[serde(flatten)]
    unknown: Value,
}

#[derive(Debug, Deserialize)]
#[serde(untagged)]
pub enum Status {
    Dead { hour: u32 },
    Alive { age: u32, residence: String },
}

fn main() {
    let json = r#"{
        "name": "Ben",
        "age": 10,
        "residence": "Planet Earth"
    }"#;

    let parsed: Parsed = serde_json::from_str(json).unwrap();

    println!("{parsed:#?}")
}

link to playground

This outputs the following:

Parsed {
    name: "Ben",
    status: Alive {
        age: 10,
        residence: "Planet Earth",
    },
    unknown: Object({
        "age": Number(
            10,
        ),
        "residence": String(
            "Planet Earth",
        ),
    }),
}

The enum values get parsed both in the status field and the unknown field.
The same thing doesn't happen when using a struct:

use serde::Deserialize;
use serde_json::Value;

#[derive(Debug, Deserialize)]
struct Parsed {
    name: String,
    #[serde(flatten)]
    status: Status,
    #[serde(flatten)]
    unknown: Value,
}

#[derive(Debug, Deserialize)]
pub struct Status {
    age: u32,
    residence: String,
}

fn main() {
    let json = r#"{
        "name": "Ben",
        "age": 10,
        "residence": "Planet Earth"
    }"#;

    let parsed: Parsed = serde_json::from_str(json).unwrap();

    println!("{parsed:#?}")
}

link to playground
Which outputs the following:

Parsed {
    name: "Ben",
    status: Status {
        age: 10,
        residence: "Planet Earth",
    },
    unknown: Object({}),
}

I'd expect the unknown field to be an empty object in both cases.
This is clearly a bug as extra data is being parsed which clearly should not have been.

This bug is clearly caused by the way the derive attributes generate deserializing logic.
It also happens on other formats (I actually encoutered this problem while implementing my own format), I chose serde_json to make the examples more readable.

@morr0ne
Copy link
Author

morr0ne commented Jun 25, 2022

I think this is the same issue highlighted in #2200, I didn't notice at first because of the weird wording in the title.

@kangalio
Copy link

Yes, this seems to be a duplicate of #2200

@Mingun
Copy link
Contributor

Mingun commented May 9, 2023

Even more: this is duplicate of #1909

@oli-obk oli-obk closed this as completed May 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

4 participants