derive_more icon indicating copy to clipboard operation
derive_more copied to clipboard

#[derive(From)]: allow specifying default values for struct/enum variant fields

Open balsoft opened this issue 4 months ago • 0 comments

Resolves https://github.com/JelteF/derive_more/issues/149

Synopsis

When deriving From, it is often useful to let some fields be a certain "constant" default value instead of being part of the source tuple type.

The most obvious such value is Default::default(), but specifying other values is very useful as well.

This is my first time touching proc-macros, please handle with care :)

The tests pass though (except for one that was broken before my changes), and this change shouldn't break anything.

I'm also open to alternative designs (e.g. #[from(default = <...>)] instead of #[from(...)])

Solution

Add handling of #[from] and #[from(<default value>)] attrs on struct (and enum struct) fields. For more information about the handling details, please consult the included documentation changes and/or tests.

Excerpt from documentation

If you add a #[from(<default value>)] attribute to any fields of the struct, then those fields will be omitted from the tuple and be set to the default value in the implementation:

# use std::collections::HashMap;
#
# use derive_more::From;
#
#[derive(Debug, From, PartialEq)]
struct MyWrapper {
    inner: u8,
    #[from(1)]
    not_important: u32,
    #[from(HashMap::new())]
    extra_properties: HashMap<String, String>,
}

assert_eq!(MyWrapper { inner: 123, not_important: 1, extra_properties: HashMap::new(), }, 123.into());

If you add a #[from] value to any fields of the struct, then only those fields will be present in the tuple and the rest will be either set to Default::default() or taken from their default values specified in #[from(<default value>)]:


# use std::collections::HashMap;
#
# use derive_more::From;
#
#[derive(Debug, From, PartialEq)]
struct Location {
    #[from]
    lat: f32,
    #[from]
    lon: f32,
    #[from(String::from("Check out my location!"))]
    description: String,
    extra_properties: HashMap<String, String>,
}

// This is equivalent to:

// #[derive(Debug, From, PartialEq)]
// struct Location {
//     lat: f32,
//     lon: f32,
//     #[from(String::from("Check out my location!"))]
//     description: String,
//     #[from(Default::default())]
//     extra_properties: HashMap<String, String>,
// }


assert_eq!(
    Location {
        lat: 41.7310,
        lon: 44.8067,
        description: String::from("Check out my location!"),
        extra_properties: Default::default(),
    },
    (41.7310, 44.8067).into()
);

Checklist

  • [x] Documentation is updated (if required)
  • [x] Tests are added/updated (if required)
  • [x] CHANGELOG entry is added (if required)

balsoft avatar Aug 26 '25 09:08 balsoft