Peternator7 / strum

A small rust library for adding custom derives to enums
https://crates.io/crates/strum
MIT License
1.8k stars 151 forks source link

Proposal to add a trait for EnumDiscriminants #376

Closed vpochapuis closed 1 month ago

vpochapuis commented 2 months ago

Hello! First of all thank you very much for this amazing crate which is very useful for lots of application.

What

I would like to make a proposal to add a Trait implementation to the structs that got derived with EnumDiscriminants in order to use them into generics and get access to the generated enum.

Currently, if my understanding is correct, a new enum is generated from the original name and appended the Discriminants suffix, however i didn't find a convenient way to reference that Type from generics.

Hence this proposal would add a new Trait, EnumDiscriminants:

/// A trait for retrieving the enum generated by [`EnumDiscriminants`] from an associated
/// Type on the original enumeration. This trait can be autoderived by `strum_macros`.
pub trait EnumDiscriminants {
    /// Enum listing the same variants as this enum but without any data fields
    /// Note: maybe we could add some trait bounds based on defaults
    type Discriminants;
}

and related implementation in the macro:

...

        impl #impl_generics #strum_module_path::EnumDiscriminants for #name #ty_generics #where_clause {
            type Discriminants = #discriminants_name;
        }
...

Why

When building applications with Generics, it can be interesting to have access to this generated enum without having to explicitly pass the type. For example, in my case, I was building a select element for enums in the web using Yew, and wanted to pass to a child that Discriminants Enum through generics, hence we could have trait bounds like so:

impl<T> yew::Component for FormSelect<T>
where
    T: FromStr + strum::EnumDiscriminants + 'static,
    <<T as strum::EnumDiscriminants>::Discriminants: FromStr
        + strum::VariantNames
        + AsRef<str>,
    <<<T as strum::EnumDiscriminants>::Discriminants as FromStr>::Err: Debug,

Etc...

This let me save the state of the enum as a lightweight enum without having the potential issue to store additional unused data of enum variants inner types.


If you think this proposal is on par with this crate development, please take a look at this commit from my fork, and if you would like to have a PR , I will do so. If you think this doesn't fit in this project, please let me know too!

Have a nice day

mohe2015 commented 2 months ago

I also want this, please open a PR. Also https://github.com/Peternator7/strum/pull/176 seems to be related.

Peternator7 commented 2 months ago

@vpochapuis thanks for the proposal. Not sure why #176 died (probably lost on my end 😟). Seems reasonable to me, let's do it. One small request, can we implement this trait instead:

/// A trait for retrieving the enum generated by [`EnumDiscriminants`] from an associated
/// Type on the original enumeration. This trait can be autoderived by `strum_macros`.
pub trait IntoDiscriminant {
    /// Enum listing the same variants as this enum but without any data fields
    /// Note: maybe we could add some trait bounds based on defaults
    type Discriminant;

    fn discriminant(&self) -> Self::Discriminant;
}
vpochapuis commented 2 months ago

@vpochapuis thanks for the proposal. Not sure why #176 died (probably lost on my end 😟). Seems reasonable to me, let's do it. One small request, can we implement this trait instead:

/// A trait for retrieving the enum generated by [`EnumDiscriminants`] from an associated
/// Type on the original enumeration. This trait can be autoderived by `strum_macros`.
pub trait IntoDiscriminant {
    /// Enum listing the same variants as this enum but without any data fields
    /// Note: maybe we could add some trait bounds based on defaults
    type Discriminant;

    fn discriminant(&self) -> Self::Discriminant;
}

Sure~ Updated at : https://github.com/Peternator7/strum/pull/377

thanks for taking a look at my proposal~