0

I'm trying to load a Toml file with Serde, it contains multiple booleans, I want to default them all to false if not found in the text file.

My implementation currently is:

#[derive(serde::Deserialize, serde::Serialize)]
#[serde(rename_all="PascalCase")]
pub struct SomeConfigStruct {
     // This one *must* exist, non optional, non defaulted.
    class_name : String, 

    #[serde(default = "default_boolean")]
    parent_in_constructor : bool,

    #[serde(default = "default_boolean")]
    set_user_texts : bool,

    #[serde(default = "default_boolean")]
    singleton : bool, 

    #[serde(default = "default_boolean")]
    use_enum_types : bool,
}

How can I do something in the lines of:

#[derive(serde::Deserialize, serde::Serialize)]
#[serde(rename_all="PascalCase")]
pub struct SomeConfigStruct {
    class_name : String,

    #[serde(type = bool, default = "default_boolean")]
    parent_in_constructor : bool,
    set_user_texts : bool,
    singleton : bool, 
    use_enum_types : bool,
}

[edit, new member on the Struct to better exemplify what I need.]

Tomaz Canabrava
  • 2,320
  • 15
  • 20
  • Just a quick clarification: I strongly believe such a macro would need to be applied to `SomeConfigStruct`, not a specific field. – L. Riemer Mar 14 '20 at 10:07

1 Answers1

1

Updated for new constraints

I don't know of such a macro, to my knowledge that doesn't exist. I can offer an alternative solution though.

#[derive(serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "PascalCase")]
pub struct SomeConfigStruct {
    class_name: String,

    #[serde(default)]
    #[serde(flatten)]
    defaulting_values: SomeConfigStructDefaulting,
}

#[derive(serde::Deserialize, serde::Serialize)]
#[serde(default)]
pub struct SomeConfigStructDefaulting {
    parent_in_constructor: bool,
    set_user_texts: bool,
    singleton: bool,
    use_enum_types: bool,
}

// This will be called to fill in missing spots in defaulting_values.
// Will also be called, if defaulting_values is missing altogether.
impl Default for SomeConfigStructDefaulting {
    fn default() -> Self {
        let default_boolean = true;
        Self {
            parent_in_constructor: default_boolean,
            set_user_texts: default_boolean,
            singleton: default_boolean,
            use_enum_types: default_boolean,
        }
    }
}

This for sure doesn't decrease line count, but it does fix default_boolean to one value, if that was your primary concern.

This way, your serialized representation will still look the same, and you can easily write wrappers to not have to write some_config_struct.defaulting_values in your actual code.

L. Riemer
  • 644
  • 8
  • 13
  • I'v found one RFC from rust that perhaps will allow default values on the structs, let's see if that will help. :) I can't really use the Default in my specific case because *one* of the values should panic if not in the file being read by serde, and if I define a Default, I need to default for *every* value. – Tomaz Canabrava Mar 13 '20 at 22:36
  • Can you link that RFC please? I couldn't find it. One workaround would be to factor all fields that have a default into an inner struct, which could then be [flattened](https://serde.rs/attr-flatten.html) into the outer struct. This could also be systematicallly done with a proc macro. – L. Riemer Mar 14 '20 at 10:05
  • https://github.com/rust-lang/rfcs/pull/1806 and https://github.com/Centril/rfcs/pull/19 – Tomaz Canabrava Mar 14 '20 at 11:01
  • Thank you, the 'flatten' is what I missed. :) – Tomaz Canabrava Mar 14 '20 at 11:40