"passthrough enum" for Traits?

#1
  1. I am 100% sure that for enum Animal below, I want an enum, not a Trait. I want to define upfront the set of all possible valid values.
use super::*;


trait SomeT {
    fn func1(&self);
    fn func2(&self, x: isize);
    fn func3(&self, y: u32);
    fn func4(&self);
    fn func5(&self);
}

pub struct Cat {}
pub struct Dog {}
pub struct Bird {}
pub struct Rat {}

impl SomeT for Cat {
    fn func1(&self) { unimplemented!() }
    fn func2(&self, x: isize) { unimplemented!() }
    fn func3(&self, y: u32) { unimplemented!() }
    fn func4(&self) { unimplemented!() }
    fn func5(&self) { unimplemented!() }
}

impl SomeT for Dog {
    fn func1(&self) { unimplemented!() }
    fn func2(&self, x: isize) { unimplemented!() }
    fn func3(&self, y: u32) { unimplemented!() }
    fn func4(&self) { unimplemented!() }
    fn func5(&self) { unimplemented!() }
}

impl SomeT for Bird {
    fn func1(&self) { unimplemented!() }
    fn func2(&self, x: isize) { unimplemented!() }
    fn func3(&self, y: u32) { unimplemented!() }
    fn func4(&self) { unimplemented!() }
    fn func5(&self) { unimplemented!() }
}

impl SomeT for Rat {
    fn func1(&self) { unimplemented!() }
    fn func2(&self, x: isize) { unimplemented!() }
    fn func3(&self, y: u32) { unimplemented!() }
    fn func4(&self) { unimplemented!() }
    fn func5(&self) { unimplemented!() }
}

// == ^^^^^ I have some Trait, and a bunch of structs that implement it. ^^^^^


pub enum Animal { // == Yes, I really do want a enum, instead of a Trait
    Cat(Cat),
    Dog(Dog),
    Bird(Bird),
    Rat(Rat),
}


// === is there someway to simplify these impls, this seems very repetitive
impl SomeT for Animal {

    fn func1(&self) {
        match self {
            Animal::Cat(cat) => cat.func1(),
            Animal::Dog(dog) => dog.func1(),
            Animal::Bird(bird) => bird.func1(),
            Animal::Rat(rat) => rat.func1(),
        }
    }


    fn func2(&self, x: isize) {
        match self {
            Animal::Cat(cat) => cat.func2(x),
            Animal::Dog(dog) => dog.func2(x),
            Animal::Bird(bird) => bird.func2(x),
            Animal::Rat(rat) => rat.func2(x),
        }
    }


    fn func3(&self, y: u32) {
        match self {
            Animal::Cat(cat) => cat.func3(y),
            Animal::Dog(dog) => dog.func3(y),
            Animal::Bird(bird) => bird.func3(y),
            Animal::Rat(rat) => rat.func3(y),
        }
    }


    fn func4(&self) {
        match self {
            Animal::Cat(cat) => cat.func4(),
            Animal::Dog(dog) => dog.func4(),
            Animal::Bird(bird) => bird.func4(),
            Animal::Rat(rat) => rat.func4(),
        }
    }


    fn func5(&self) {
        match self {
            Animal::Cat(cat) => cat.func5(),
            Animal::Dog(dog) => dog.func5(),
            Animal::Bird(bird) => bird.func5(),
            Animal::Rat(rat) => rat.func5(),
        }
    }
}
  1. Is there some way to reduce this repetition? I guarantee that my enum Animal is a list of the form Name(StructName), where StructName implements Foot … and all I want enum Animal to do is to “pass through the function cal”
1 Like
#2

You could use macros to do this, there may also be a crate to handle this.

#3

I had this exact same use case when working with ASTs and compilers. You can use defer!() from the sum_type crate to do the passthrough stuff. The sum_type!() macro also adds a bunch of convenience methods and impls for converting to/from the variant types.

2 Likes
#4

@Michael-F-Bryan : defer! is indeed what I am looking for. Thanks!