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

Improve #[serde(default, skip_serializing_if = "xxx")] behavior on Enum variant value. #2508

Open
xjasonli opened this issue Jul 13, 2023 · 2 comments · May be fixed by #2509
Open

Improve #[serde(default, skip_serializing_if = "xxx")] behavior on Enum variant value. #2508

xjasonli opened this issue Jul 13, 2023 · 2 comments · May be fixed by #2509

Comments

@xjasonli
Copy link

Currently, #[serde(default, skip_serializing_if = "is_default"] below has no effects.

use anyhow::Result;
use serde_derive::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug)]
#[serde(tag = "type", content = "settings", rename_all = "lowercase")]
pub enum TypeWithSettings {
    Foo(
        #[serde(default, skip_serializing_if = "is_default")]
        FooSettings
    ),
    Bar(
        #[serde(default, skip_serializing_if = "is_default")]
        BarSettings
    ),
}

#[derive(Serialize, Deserialize, Debug, Default, PartialEq)]
pub struct FooSettings {
    value: String,
}

#[derive(Serialize, Deserialize, Debug, Default, PartialEq)]
pub struct BarSettings {
    value: u32,
}

fn main() {
    println!("calling de():");
    if let Err(e) = de() {
        println!("Error: {:?}", e);
    }

    println!("calling ser():");
    if let Err(e) = ser() {
        println!("Error: {:?}", e);
    }
}

fn de() -> Result<()> {
    let json = r#"
    {
        "type": "foo"
    }"#;
    let settings: TypeWithSettings = serde_json::from_str(json)?;
    println!("{:?}", settings);
    Ok(())
}

fn ser() -> Result<()> {
    let settings = TypeWithSettings::Foo(FooSettings::default());
    println!("{}", serde_json::to_string_pretty(&settings)?);
    Ok(())
}

pub fn is_default<T: Default + PartialEq>(t: &T) -> bool {
    t == &T::default()
}

What i expect the code is to deserialize the json string with a default FooSettings instance as the Foo varant value, and serialize the enum without "settings" field.

But currelty the output is:

calling de():
Error: missing field `settings` at line 4 column 5
calling ser():
{
  "type": "foo",
  "settings": {
    "value": ""
  }
}
@dtolnay
Copy link
Member

dtolnay commented Jul 13, 2023

Makes sense; I would accept a PR to fix this.

@Baptistemontan
Copy link
Contributor

Looking at the derive macro code the skip_serializing_if and default attributes are not taken into account for newtype variants in adjacently tagged enums

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
3 participants