Loading page…
Rust walkthroughs
Loading page…
Bitflags provides a macro for defining bitwise flag types. It generates types that can be combined with |, &, ^ operators and provide methods for checking, setting, and clearing flags.
Key concepts:
| (union), & (intersection), ^ (xor), ! (complement)contains, insert, remove, toggleWhen to use Bitflags:
When NOT to use Bitflags:
use bitflags::bitflags;
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Permissions: u32 {
const READ = 0b0001;
const WRITE = 0b0010;
const EXECUTE = 0b0100;
}
}
fn main() {
let perms = Permissions::READ | Permissions::WRITE;
println!("{:?}", perms); // READ | WRITE
println!("Value: {}", perms.bits()); // 3
}use bitflags::bitflags;
bitflags! {
#[derive(Debug)]
struct Flags: u8 {
const A = 0b0000_0001;
const B = 0b0000_0010;
const C = 0b0000_0100;
}
}
fn main() {
let flags = Flags::A | Flags::C;
// Check if specific flag is set
println!("Has A: {}", flags.contains(Flags::A)); // true
println!("Has B: {}", flags.contains(Flags::B)); // false
println!("Has C: {}", flags.contains(Flags::C)); // true
// Check if all specified flags are set
println!("Has A and C: {}", flags.contains(Flags::A | Flags::C)); // true
println!("Has A and B: {}", flags.contains(Flags::A | Flags::B)); // false
// Check if any flag is set
println!("Has any: {}", !flags.is_empty());
}use bitflags::bitflags;
bitflags! {
#[derive(Debug, Clone, Copy)]
struct Config: u16 {
const DEBUG = 1 << 0;
const VERBOSE = 1 << 1;
const LOG_FILE = 1 << 2;
const LOG_STDERR = 1 << 3;
}
}
fn main() {
let mut config = Config::DEBUG;
// Insert flags
config.insert(Config::VERBOSE);
println!("After insert: {:?}", config);
// Remove flags
config.remove(Config::DEBUG);
println!("After remove: {:?}", config);
// Toggle flags
config.toggle(Config::LOG_FILE);
println!("After toggle: {:?}", config);
// Set to exact value
config.set(Config::VERBOSE, false);
println!("After set false: {:?}", config);
}use bitflags::bitflags;
bitflags! {
struct Colors: u8 {
const RED = 1;
const GREEN = 2;
const BLUE = 4;
}
}
fn main() {
let red = Colors::RED;
let green = Colors::GREEN;
// Union (OR)
let yellow = red | green; // RED | GREEN
println!("Yellow: {:?}", yellow);
// Intersection (AND)
let both = yellow & Colors::RED;
println!("Intersection: {:?}", both); // RED
// Difference
let diff = yellow & !Colors::RED;
println!("Difference: {:?}", diff); // GREEN
// XOR
let xor = yellow ^ Colors::RED;
println!("XOR: {:?}", xor); // GREEN
// Complement
let complement = !Colors::RED;
println!("Complement: {:?}", complement);
}use bitflags::bitflags;
bitflags! {
#[derive(Debug, Clone, Copy)]
struct FilePermission: u32 {
const OWNER_READ = 0o400;
const OWNER_WRITE = 0o200;
const OWNER_EXEC = 0o100;
const GROUP_READ = 0o040;
const GROUP_WRITE = 0o020;
const GROUP_EXEC = 0o010;
const OTHER_READ = 0o004;
const OTHER_WRITE = 0o002;
const OTHER_EXEC = 0o001;
// Combined constants
const OWNER_ALL = Self::OWNER_READ.bits() | Self::OWNER_WRITE.bits() | Self::OWNER_EXEC.bits();
const GROUP_ALL = Self::GROUP_READ.bits() | Self::GROUP_WRITE.bits() | Self::GROUP_EXEC.bits();
const OTHER_ALL = Self::OTHER_READ.bits() | Self::OTHER_WRITE.bits() | Self::OTHER_EXEC.bits();
}
}
fn main() {
// rwxr-xr-x
let mode = FilePermission::OWNER_ALL
| FilePermission::GROUP_READ
| FilePermission::GROUP_EXEC
| FilePermission::OTHER_READ
| FilePermission::OTHER_EXEC;
println!("Mode: {:o}", mode.bits()); // 755
println!("Owner can write: {}", mode.contains(FilePermission::OWNER_WRITE));
println!("Group can write: {}", mode.contains(FilePermission::GROUP_WRITE));
}use bitflags::bitflags;
use serde::{Serialize, Deserialize};
bitflags! {
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
struct Features: u8 {
const FEATURE_A = 1;
const FEATURE_B = 2;
const FEATURE_C = 4;
}
}
fn main() {
let features = Features::FEATURE_A | Features::FEATURE_C;
// Serialize to JSON
let json = serde_json::to_string(&features).unwrap();
println!("JSON: {}", json);
// Deserialize from JSON
let parsed: Features = serde_json::from_str(&json).unwrap();
println!("Parsed: {:?}", parsed);
}use bitflags::bitflags;
use std::str::FromStr;
bitflags! {
#[derive(Debug)]
struct Options: u32 {
const OPT_A = 1;
const OPT_B = 2;
const OPT_C = 4;
}
}
fn main() {
// Parse from hex string
let opts = Options::from_bits(0b101).unwrap();
println!("Parsed: {:?}", opts); // OPT_A | OPT_C
// From bits truncates unknown bits
let truncated = Options::from_bits_truncate(0b1111);
println!("Truncated: {:?}", truncated); // OPT_A | OPT_B | OPT_C
}use bitflags::bitflags;
bitflags! {
#[derive(Debug)]
struct Flags: u8 {
const A = 1;
const B = 2;
const C = 4;
const D = 8;
}
}
fn main() {
let flags = Flags::A | Flags::C | Flags::D;
// Iterate over set flags
for flag in flags.iter() {
println!("Flag: {:?}", flag);
}
// Count set flags
let count = flags.iter().count();
println!("Count: {}", count); // 3
}use bitflags::bitflags;
bitflags! {
#[derive(Debug)]
struct Flags: u8 {
const A = 1;
const B = 2;
const C = 4;
}
}
fn main() {
// All flags set
let all = Flags::all();
println!("All: {:?}", all); // A | B | C
// No flags set
let empty = Flags::empty();
println!("Empty: {:?}", empty);
// Check if empty
println!("Is empty: {}", empty.is_empty()); // true
println!("Is empty: {}", all.is_empty()); // false
}use bitflags::bitflags;
bitflags! {
struct Capabilities: u16 {
const CAN_READ = 1;
const CAN_WRITE = 2;
const CAN_DELETE = 4;
const CAN_SHARE = 8;
}
}
fn main() {
let caps = Capabilities::CAN_READ | Capabilities::CAN_WRITE | Capabilities::CAN_SHARE;
// Check if all of these are set
let required = Capabilities::CAN_READ | Capabilities::CAN_WRITE;
if caps.contains(required) {
println!("Has read and write");
}
// Check if any of these are set
let any_of = Capabilities::CAN_DELETE | Capabilities::CAN_SHARE;
if caps.intersects(any_of) {
println!("Has delete or share");
}
// Check exact match
if caps == required | Capabilities::CAN_SHARE {
println!("Exact match!");
}
}use bitflags::bitflags;
bitflags! {
#[derive(Debug)]
struct Settings: u8 {
const ENABLED = 1;
const VERBOSE = 2;
const DEBUG = 4;
}
}
impl Default for Settings {
fn default() -> Self {
Settings::ENABLED | Settings::VERBOSE
}
}
fn main() {
let settings = Settings::default();
println!("Default: {:?}", settings); // ENABLED | VERBOSE
}use bitflags::bitflags;
bitflags! {
struct Status: u32 {
// Lower 8 bits for state
const STATE_MASK = 0xFF;
const STATE_INIT = 0;
const STATE_RUNNING = 1;
const STATE_STOPPED = 2;
// Upper bits for flags
const FLAG_ERROR = 1 << 8;
const FLAG_WARNING = 1 << 9;
const FLAG_MAINTENANCE = 1 << 10;
}
}
fn main() {
let status = Status::STATE_RUNNING | Status::FLAG_WARNING;
// Extract state
let state = status & Status::STATE_MASK;
println!("State: {:?}", state);
// Check flags
if status.contains(Status::FLAG_ERROR) {
println!("Error!");
}
if status.contains(Status::FLAG_WARNING) {
println!("Warning!");
}
}use bitflags::bitflags;
bitflags! {
struct FlagsA: u8 {
const X = 1;
}
}
bitflags! {
struct FlagsB: u8 {
const Y = 1;
}
}
fn main() {
let a = FlagsA::X;
let b = FlagsB::Y;
// This would be a type error:
// let combined = a | b; // Error: mismatched types
// Must use same type
let combined_a = a | FlagsA::from_bits_truncate(0); // OK
}use bitflags::bitflags;
bitflags! {
#[derive(Debug, Clone, Copy)]
struct Mode: u8 {
const READ = 1;
const WRITE = 2;
const APPEND = 4;
const CREATE = 8;
const TRUNCATE = 16;
}
}
fn open_file(filename: &str, mode: Mode) {
println!("Opening {} with mode: {:?}", filename, mode);
if mode.contains(Mode::WRITE) && mode.contains(Mode::READ) {
println!("Read-write mode");
}
if mode.contains(Mode::CREATE) && !mode.contains(Mode::WRITE) {
println!("Warning: CREATE without WRITE");
}
}
fn main() {
open_file("test.txt", Mode::READ | Mode::WRITE | Mode::CREATE);
}use bitflags::bitflags;
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct ColumnFlags: u16 {
const PRIMARY_KEY = 1;
const NOT_NULL = 2;
const UNIQUE = 4;
const INDEXED = 8;
const AUTO_INCREMENT = 16;
const FOREIGN_KEY = 32;
}
}
struct Column {
name: String,
flags: ColumnFlags,
}
impl Column {
fn new(name: &str) -> Self {
Column {
name: name.to_string(),
flags: ColumnFlags::empty(),
}
}
fn primary(mut self) -> Self {
self.flags.insert(ColumnFlags::PRIMARY_KEY | ColumnFlags::NOT_NULL);
self
}
fn unique(mut self) -> Self {
self.flags.insert(ColumnFlags::UNIQUE | ColumnFlags::INDEXED);
self
}
fn nullable(mut self) -> Self {
self.flags.remove(ColumnFlags::NOT_NULL);
self
}
}
fn main() {
let id_column = Column::new("id").primary();
let name_column = Column::new("email").unique();
println!("ID flags: {:?}", id_column.flags);
println!("Email flags: {:?}", name_column.flags);
}use bitflags::bitflags;
bitflags! {
#[derive(Debug)]
struct TcpFlags: u8 {
const FIN = 1;
const SYN = 2;
const RST = 4;
const PSH = 8;
const ACK = 16;
const URG = 32;
}
}
fn analyze_packet(flags: TcpFlags) {
if flags.contains(TcpFlags::SYN | TcpFlags::ACK) {
println!("SYN-ACK packet");
} else if flags.contains(TcpFlags::SYN) {
println!("SYN packet (connection start)");
} else if flags.contains(TcpFlags::FIN) {
println!("FIN packet (connection close)");
} else if flags.contains(TcpFlags::RST) {
println!("RST packet (connection reset)");
}
}
fn main() {
analyze_packet(TcpFlags::SYN);
analyze_packet(TcpFlags::SYN | TcpFlags::ACK);
analyze_packet(TcpFlags::FIN | TcpFlags::ACK);
}use bitflags::bitflags;
bitflags! {
#[derive(Debug)]
struct Flags: u8 {
const A = 1;
const B = 2;
const C = 4;
}
}
fn main() {
// Get raw bits
let flags = Flags::A | Flags::C;
let bits: u8 = flags.bits();
println!("Bits: {}", bits); // 5
// From bits (returns None for invalid)
let from_bits = Flags::from_bits(5);
println!("From bits: {:?}", from_bits); // Some(A | C)
// From bits (truncates invalid)
let truncated = Flags::from_bits_truncate(255);
println!("Truncated: {:?}", truncated); // A | B | C
// Check if bits are valid
let is_valid = Flags::is_valid_bit_pattern(255);
println!("Valid: {}", is_valid); // true for flags-defined bits only
}Bitflags Key Imports:
use bitflags::bitflags;Defining Bitflags:
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Flags: u8 {
const A = 1;
const B = 2;
const C = 4;
}
}Key Methods:
| Method | Description |
|--------|-------------|
| .contains(flag) | Check if flag is set |
| .insert(flag) | Set flag(s) |
| .remove(flag) | Clear flag(s) |
| .toggle(flag) | Flip flag(s) |
| .set(flag, bool) | Set/clear based on bool |
| .intersects(flag) | Check if any flag matches |
| .is_empty() | No flags set |
| .all() | All flags set |
| .iter() | Iterate over set flags |
| .bits() | Get raw value |
Bitwise Operators:
| Operator | Name | Result |
|----------|------|--------|
| \| | Union | Flags in either |
| & | Intersection | Flags in both |
| ^ | XOR | Flags in one but not both |
| ! | Complement | All flags not in operand |
Key Points:
| operatorcontains() for all or intersects() for any.bits() returns raw integer.from_bits() validates, .from_bits_truncate() ignores unknown