serde-rs / serde

Serialization framework for Rust
https://serde.rs/
Apache License 2.0
9.08k stars 767 forks source link

#[serde(default = "...")] does not work on `flatten`-ed fields. #1879

Open BertalanD opened 4 years ago

BertalanD commented 4 years ago

I have a struct A that – along with other fields – contains a flattened B struct and a collection of B structs. I would like B's missing fields to take up a different default value if they are in the flattened field.

The problem

No matter what default attribute I set on the flatten-ed field, it will fall back to its type's default implementation.

For flattened structs, it would mean more sense that default applies to each field separately, as it's a way more common use case than wanting to fall back to the struct's Default implementation unless all of its fields are missing. But I am not even sure if that's how it's currently behaving.

Minimal example

These are my data structures:

#[derive(Serialize, Deserialize)]
#[serde(default)]
struct A {
    zero: usize,
    #[serde(flatten, default = "B::default_if_flattened")]
    b: B,
    c: Vec<B>,
}

impl Default for A {
    fn default() -> Self {
        A {
            zero: 0,
            b: B::default_if_flattened(),
            three: Vec::new(),
        }
    }
}

#[derive(Serialize, Deserialize)]
#[serde(default)]
struct B {
    one: Option<usize>,
    two: Option<String>
}

impl Default for B {
    fn default() -> Self {
        B {
            one: None,
            two: None
        }
    }
}

impl B {
    fn default_if_flattened() -> Self {
        B {
            one: Some(1),
            two: Some(String::from("two"))
        }
    }
}

And I want to deserialize the following TOML file:

zero = 0
two = "two"

three = [ { } ]

Expected results when deserialized into a value: A:

value.b.one == Some(1)
value.three[0].one == None

Here is the same thing in the Rust Playground (currently panics.)

maxcountryman commented 3 years ago

I seem to be running into the same issue with #[serde(default, flatten)] where my field type impls Default.

Any workarounds for this?

ByteNacked commented 1 year ago

Same thing, flatten doesn't work with default, nor with manual default trait impl nor with derive(default).

use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct User {
    #[serde(flatten, default)]
    contact: Contact,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Default)]
struct Contact {
    email: String,
    phone: String,
}

fn main() {
    let json = r#"{
        "email": "john@example.com"
    }"#;

    let user: User = serde_json::from_str(json).unwrap();
    let expected_user = User { contact: Contact { email: "john@example.com".to_string(), phone: "".to_string() } };
    assert_eq!(user, expected_user);
}

panics with:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error("missing field `phone`", line: 3, column: 5)', src/main.rs:20:49

playground link

Mingun commented 1 year ago

This is duplicate of #1626