Implement trait automatically for enum

Is there a way to automatically implement a trait for all variants of an enum?

Example:

struct Alpha {}
struct Beta {}

trait Foo {
    fn foo(self);
}

impl Foo for Alpha {
    fn foo(self) {
        println!("foo_alpha");
    }
}

impl Foo for Beta {
    fn foo(self) {
        println!("foo_beta");
    }
}

// implement `Foo` here without writing the match manually
enum Options {
    A(Alpha),
    B(Beta),
}

fn main() {
    let alpha = Alpha{};
    alpha.foo();
    let beta = Beta{};
    beta.foo();
    let options = Options::A(Alpha{});
    options.foo(); // not implemented
}

Are you looking for 'derive' ?

1 Like

just deriving Foo does not work…:

#[derive(Foo)]
enum Options {
    A(Alpha),
    B(Beta),
}

What do you mean by that? Writing my own proc macro?

Yes, probably that.

The crate enumx provides some macros to serve this purpose -- implementing trait for enums all the variants of which have already implemented the trait.

Using the def_impls!{}, _Variants!(), _variants!() macros seems less concise than proc-macro-derive, but it works and you can see and control the underlying logic.

use enumx::export::*;
use enumx::predefined::*;

struct Alpha {}
struct Beta {}

trait Foo {
    fn foo(self);
}

impl Foo for Alpha {
    fn foo(self) {
        println!("foo_alpha");
    }
}

impl Foo for Beta {
    fn foo(self) {
        println!("foo_beta");
    }
}

// implement `Foo` here without writing the match manually
enum Options {
    A(Alpha),
    B(Beta),
}

def_impls! {                          
    impl Foo for _def!(
        enum Options {
            A(Alpha),
            B(Beta),
        } 
    ) {
        fn foo(self) {
            _match!( _variant!().foo() )
        }
    }
}

// You don't need to define Options
// You can use `Enum![1..=6]` to implement Foo for "anonymous enums" composed of 1,2,3,4,5,6 variants.
def_impls! {
    impl Foo for Enum![2..=2]
        where _Variants!(): Foo
    {
        fn foo(self) {
            _match!( _variant!().foo() )
        }
    }
}

fn main() {
    let alpha = Alpha{};
    alpha.foo();
    let beta = Beta{};
    beta.foo();
    let options = Options::A(Alpha{});
    options.foo(); // implemented

    let enum2 = Enum2::<Alpha,Beta>::_0(Alpha{});
    enum2.foo();
}

If the actual trait Foo you are using is complex and you don't want to repeat its method again and again, you can save its definition in one place( in some macro_rules! ) and implement it using the following syntax:

impl_trait! {
    _impl!( Foo _for!( Options ))
}

See the enumx book for more.

2 Likes

more complicated than I hoped but thank you

there is https://crates.io/crates/enum_dispatch

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.