user82395214
user82395214

Reputation: 929

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

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);

Upvotes: 1

Views: 1490

Answers (2)

user4815162342
user4815162342

Reputation: 154916

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();
}

Upvotes: 3

cadolphs
cadolphs

Reputation: 9617

Anything wrong with just using if let instead of match?

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

Upvotes: -1

Related Questions