How to match against a flags/bitmasks in Rust?
Asked Answered
O

2

8

Take a typical check for bit-flags:

if      (v & (1 << 0)) != 0 { foo(); }
else if (v & (1 << 1)) != 0 { bar(); }
else if (v & (1 << 2)) != 0 { baz(); }

How would this be written as a match statement?

Oenomel answered 27/8, 2016 at 7:33 Comment(3)
Did you mean if v & (1 << 0) > 0 etc.?Astarte
@Dogbert, yes, updatedOenomel
I don't think it makes sense to use match when you are testing single bits.Pindus
I
13
if      (v & (1 << 0)) != 0 { foo(); }
else if (v & (1 << 1)) != 0 { bar(); }
else if (v & (1 << 2)) != 0 { baz(); }

Such concrete code can be rewritten like this:

match v.trailing_zeros() {
    0 => foo(),
    1 => bar(),
    2 => baz(),
    _ => {},
}
Imitate answered 27/8, 2016 at 9:38 Comment(2)
That's really clever! I wrote some tests to check that this is indeed correct (and they pass): play.rust-lang.org/…Astarte
Is the generated code as efficient as a bitmask check?Oenomel
G
2

As fghj answered, it is possible to do this:

match v.trailing_zeros() {
    0 => foo(),
    1 => bar(),
    2 => baz(),
    _ => {},
}

This would be preferable to using if/else, not only for readability, as rustc generates less assembly for the match statement than for the if/else clause: 23 lines of logic vs 9 (see Compiler explorer). It's possible that this could differ depending on architecture, however, particularly for RISC processors

Benchmarking both methods with 8 bits, they have exactly the same performance:

running 2 tests
test bench_if_else ... bench:          62 ns/iter (+/- 0)
test bench_match   ... bench:          61 ns/iter (+/- 2)
Grapple answered 26/12, 2023 at 23:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.