Match on pair of enum when both are of the same kind

Solution 1:

I'm not sure how many of these operations you want to implement, and how many enum variants you actually have. Depending on that, the best answer changes quite a bit, I think. If you really only have one operation (interpolate), and three variants: type it out, anything else will be a lot less simple and maintainable.

That being said, I might use

let geometry = binop!(match (&self.geometry, &other.geometry) {
    (a, b) => *a.interpolate(b, t)
});

based on

macro_rules! binop {
    (match ($av:expr, $bv:expr) { ($a:ident, $b:ident) => $op:expr }) => {{
        use Geometry::*;
        binop!($av, $bv, $a, $b, $op, Point, Curve, EPBox)
    }};
    ($av:expr, $bv:expr, $a:ident, $b:ident, $op:expr, $($var:path),*) => {
        match ($av, $bv) {
            $(($var($a), $var($b)) => $var($op),)*
            _ => unimplemented!("Kinds not matching")
        }
    };
}

Playground

You'll have to list up the enum variants once. If you don't want that, you'll have to go for a proc macro. I think that would be overkill.

Solution 2:

With your current code, you can't really do this. Checking if the enum variants are the same variant is fairly simple with the use of core::mem::discriminant, but you can't access the contained value without match or if let statements. What you can do is use type parameters for the variables and type IDs. This is a really tacky way to do things, and should be avoided really, but it works. I've given an example to show you how you could implement it

use std::any::Any;

trait SomeTrait {
    fn some_function(&self, other: Self) -> &Self;
}

#[derive(Clone)]
struct Var0 {
    eg: i64
}

#[derive(Clone)]
struct Var1 {
    other_eg: f64
}

fn check<T: 'static, B: 'static>(lhs: T, rhs: B) -> Option<T> {
    if lhs.type_id() == rhs.type_id() {
        Some(lhs.some_function(rhs))
    } else {
        None
    }
}

fn main() {
    let a = Var0{ eg: 2 };
    let b = Var0{ eg: 9 };
    let c = Var1 { other_eg: -3f64 };
    assert!(check(a.clone(), b).is_some());
    assert!(check(a, c).is_none());
}

impl SomeTrait for Var0 { /* ... */ }
impl SomeTrait for Var1 { /* ... */ }

Please note though: as I said before this is messy and pretty hacky and not very nice to read. If I were writing this I would use the match statement over this, but it's up to you what you do since this does require some reworking to implement. I'm also not sure if you can use different lifetimes for the check function other than `static which might be a problem.