Bitwise or in match?

Viewed 1186

I have a variable that consists of several flags ORed together, and I'd like to test which combination of them my value is and act on that. Unfortunately, the | operator has a different meaning in a match statement, so I can't write

match x {
    (FLAG1 | FLAG2) => return 5;
    (FLAG1 | FLAG3) => return 6;
    (FLAG2 | FLAG3) => return y;
    _ => return 0;
}

and instead I need to precompute (FLAG1 | FLAG2) and so on, making my code ugly and unreadable. Is there a better way to do this?

3 Answers

The left part of each arm of a match expression is a pattern not an expression. That means you can only do pattern matching there. You can't use operators, accessors and function calls.

Unfortunately, I think you might be stuck with doing an if..else:

if x == FLAG1 | FLAG2 { return 5 }
else if x == FLAG1 | FLAG2 { return 6 }
else if x == FLAG1 | FLAG2 { return y }
else { return 0 };

But, since if..else (and match) are expressions, you can at least eliminate the repeated return:

return if x == FLAG1 | FLAG2 { 5 }
else if x == FLAG1 | FLAG2 { 6 }
else if x == FLAG1 | FLAG2 { y }
else { 0 };

You could work around this limitation by using an array of possible options:

const FLAG1: usize = 1;
const FLAG2: usize = 2;
const FLAG3: usize = 3;

fn main() {
    let x = 1;
    let y = 10;

    let options = [
        (FLAG1 | FLAG2, 5), 
        (FLAG1 | FLAG3, 6), 
        (FLAG2 | FLAG3, y)
    ];

    let result = options.iter()
                        .find(|(calc, _)| *calc == x)
                        .map(|(_, ret)| *ret)
                        .unwrap_or(0);
}

Depending on the number of variants you want to cover this might be a viable solution.

I wrote a little macro to transform your code into a match with if guards. I named it switch! since it works a little more like switch from other languages.

https://github.com/camsteffen/switch-statement-rust

switch! { x;
    FLAG1 | FLAG2 => return 5,
    FLAG1 | FLAG3 => return 6,
    FLAG2 | FLAG3 => return y,
    _ => return 0,
}
Related