How to pass in flags parameters in rust?

Viewed 72

Like in C, you can set a int parameter as flags, so you can know if some flag is set by doing & operation. Of course, I know in Rust I can do the same thing. But is there a safer and more elegant way to do that? Cause there're multiple groups of flags, I'm worrying I may mix them up and set wrong flags.

1 Answers

You could use enums, optionally implementing BitAnd and BitOr traits for convenience:

#[repr(u8)]
enum Flags {
    Flag1 = 1,
    Flag2 = 2,
    Flag3 = 4,
}

impl Flags {
    pub fn is_set(self, flags: u8) -> bool {
        flags & self as u8 != 0
    }
}

impl std::ops::BitAnd for Flags {
    type Output = u8;
    fn bitand(self, rhs: Self) -> Self::Output {
        self as u8 & rhs as u8
    }
}

impl std::ops::BitOr for Flags {
    type Output = u8;
    fn bitor(self, rhs: Self) -> Self::Output {
        self as u8 | rhs as u8
    }
}

fn main() {
    let flags = 0b11111111u8 & (Flags::Flag1 | Flags::Flag3);
    println!("{}", Flags::Flag1.is_set(flags));
    println!("{}", Flags::Flag2.is_set(flags));
    println!("{}", Flags::Flag3.is_set(flags));
}

Playground

Alternatively you could use Bitflags crate which implements it all for you:

use bitflags::bitflags;

bitflags! {
    struct Flags: u32 {
        const FLAG1 = 0b00000001;
        const FLAG2 = 0b00000010;
        const FLAG3 = 0b00000100;
        const FLAGS_ALL = Self::FLAG1.bits | Self::FLAG2.bits | Self::FLAG3.bits;
    }
}

impl Flags {
    fn is_set(self, flag: Self) -> bool {
        self & flag == flag
    }
}

fn main() {
    let flags = Flags::FLAG1 | Flags::FLAG3;
    println!("{}", flags.is_set(Flags::FLAG1));
    println!("{}", flags.is_set(Flags::FLAG2));
    println!("{}", flags.is_set(Flags::FLAG3));
}

Playground link

Related