Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement bitwise operations on a bitflags enum?

Tags:

rust

I have an enum that looks like this:

#[repr(u8)]
pub enum PublicFlags {
    PublicFlagVersion = 0x01,
    PublicFlagReset = 0x02,
    NoncePresent = 0x04,
    IdPresent = 0x08,
    PktNumLen4 = 0x30,
    PktNumLen2 = 0x20,
    PktNumLen1 = 0x10,
    Multipath = 0x40,
}

I want to do a bitwise operation on several of the enum values. However, the Rust compiler complains:

an implementation of `std::ops::BitAnd` might be missing for `PublicFlags`.
like image 829
Brett Jackson Avatar asked Apr 20 '17 03:04

Brett Jackson


People also ask

What are the first 4 numeric values of an enum used to store flags?

We use the values 0, 1, 2, 4 to indicate the underlying bits for each value—we should double each value to avoid conflicts. Operators We use bitwise operators, like OR and AND, with enum flags. We use "NOT" to remove a flag from an enum.

Is Bitwise an operator?

A bitwise operator is an operator used to perform bitwise operations on bit patterns or binary numerals that involve the manipulation of individual bits. Bitwise operators are used in: Communication stacks where the individual bits in the header attached to the data signify important information.

How to use Anan enum as a bit flag in rust?

An enum in Rust is not intended to be used as bit flags. PublicFlags can only take the values given in the enum (and not a combination). So for instance, the following match statement is exhaustive: let flags: PublicFlags; ... match flags { PublicFlagVersion => {...}

What is HasFlag in Enum?

.NET's built-in flag enum operations are unfortunately quite limited. Most of the time users are left with figuring out the bitwise operation logic. In .NET 4, the method HasFlag was added to Enum which helps simplify user's code but unfortunately there are many problems with it.

What is bit place in enumerate type?

As the enumerate type is making use of the position of binary digits (i.e. units, 2, 4, 8, 16 etc) and the operation does a logic and. If that bit place is set the value will not be zero (true) otherwise it will be false.

How can I create a struct using bitflags?

The solution is to actually store the value as a u8, then use constants to store the value of each flag. This can be cumbersome, but thankfully the bitflags crate wraps all the boilerplate up in a macro for you. Here is an example how you would create your struct using bitflags: Show activity on this post.


2 Answers

An enum in Rust is not intended to be used as bit flags. PublicFlags can only take the values given in the enum (and not a combination). So for instance, the following match statement is exhaustive:

let flags: PublicFlags;
...
match flags {
    PublicFlagVersion => {...}
    PublicFlagReset => {...}
    NoncePresent => {...}
    IdPresent => {...}
    PktNumLen4 => {...}
    PktNumLen2 => {...}
    PktNumLen1 => {...}
    Multipath => {...}
}

There is no way to have a PublicFlags variable with a combination of the flags.

The solution is to actually store the value as a u8, then use constants to store the value of each flag. This can be cumbersome, but thankfully the bitflags crate wraps all the boilerplate up in a macro for you. Here is an example how you would create your struct using bitflags:

#[macro_use]
extern crate bitflags;

bitflags! {
    flags PublicFlags: u8 {
        const PUBLIC_FLAG_VERSION = 0x01,
        const PUBLIC_FLAG_RESET = 0x02,
        const NONCE_PRESENT = 0x04,
        const ID_PRESENT = 0x08,
        const PKT_NUM_LEN_4 = 0x30,
        const PKT_NUM_LEN_2 = 0x20,
        const PKT_NUM_LEN_1 = 0x10,
        const MULTIPATH = 0x40,
    }
}

fn main() {
    let flag = PUBLIC_FLAG_VERSION | ID_PRESENT;
    assert!((flag & MULTIPATH).is_empty()); 
    assert!(flag.contains(ID_PRESENT));
} 
like image 98
Djzin Avatar answered Sep 22 '22 03:09

Djzin


This could work as an alternative answer without new dependencies.

pub mod PublicFlags {
    pub const PublicFlagVersion: u8 = 0x01;
    pub const PublicFlagReset: u8 = 0x02;
    pub const NoncePresent: u8 = 0x04;
    pub const IdPresent: u8 = 0x08;
    pub const PktNumLen4: u8 = 0x30;
    pub const PktNumLen2: u8 = 0x20;
    pub const PktNumLen1: u8 = 0x10;
    pub const Multipath: u8 = 0x40;
}

You can refer to the values just like with an enum with PublicFlags::PublicFlagVersion, or add use PublicFlags::*; if it is cleaner to reference the values without specifying the namespace.

like image 31
Sasha Kondrashov Avatar answered Sep 19 '22 03:09

Sasha Kondrashov