Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

rust

I want to get rid of the repeated code here, and not have to list each enum kind:

use Geometry::*;
let geometry = match (&self.geometry, &other.geometry) {
    (Point(a), Point(b)) => Point(*a.interpolate(b, t)),
    (Curve(a), Curve(b)) => Curve(*a.interpolate(b, t)),
    (EPBox(a), EPBox(b)) => EPBox(*a.interpolate(b, t)),
    (_, _) => unimplemented!("Kinds not matching")
};

The types inside the kinds all implement the Interpolate trait which has the interpolate method:

enum Geometry {
    Point(Point),
    Curve(Curve),
    EPBox(EPBox)
}

trait Interpolate {
    fn interpolate(&self, other: &Self, t: f64) -> Box<Self> {
        // ...
    }
}

impl Interpolate for Point {}
impl Interpolate for Curve {}
impl Interpolate for EPBox {}

What I want to do is something like this:

let geometry = match (&self.geometry, &other.geometry) {
    (x(a), x(b)) => x(*a.interpolate(b, t)), // and check that a and b impls Interpolate
    (_, _) => unimplemented!("Kinds not matching")
};
like image 583
Jonatan Kallus Avatar asked Feb 01 '26 15:02

Jonatan Kallus


1 Answers

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.

like image 143
Caesar Avatar answered Feb 04 '26 03:02

Caesar



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!