1
votes

Given an enum like

struct Earth { water: usize }
struct Mars { redness: usize }

enum World {
    Mars(Mars),
    Earth(Earth),
}

A common pattern I write is

fn something_expecting_mars(planet: World) {
    let mars = match planet {
        World::Mars(data) => data,
        _ => panic!("Shouldn't be here now"),
    }
}

Is there a macro I can use to expect a variant of an enum and subsequently extract its data?

// rewriting to this
let mars = expect_v!(planet, World::Mars);
2

2 Answers

3
votes

The standard library provides a macro for testing a match, but not one for extracting a value. However, it's fairly easy to write one:

macro_rules! expect_v {
    ($e:expr, $p:path) => {
        match $e {
            $p(value) => value,
            _ => panic!("expected {}", stringify!($p)),
        }
    };
}

Playground

As suggested in answers to the related question brought up in the comments, you might want to decouple value extraction from the panic. In that case, return an Option instead and let the callers panic if they wish by calling unwrap():

macro_rules! extract {
    ($e:expr, $p:path) => {
        match $e {
            $p(value) => Some(value),
            _ => None,
        }
    };
}

// ...
fn something_expecting_mars(planet: World) {
    let mars = extract!(planet, World::Mars).unwrap();
}
-1
votes

Anything wrong with just using if let instead of match?

mars = if let World::Mars(data) = planet { data } else { panic!("Woot woot")}