Loading pageā¦
Rust walkthroughs
Loading pageā¦
bitflags::Flags::contains enable checking multiple flags at once?The bitflags::Flags::contains method tests whether a flags value includes all specified flags, enabling efficient multi-flag checks through a single bitwise operation. Unlike checking each flag individually with multiple method calls, contains performs a bitwise AND between the value and the flags being tested, returning true only if all specified bits are set. This pattern is fundamental to bitflags designāflags are combined through bitwise OR and tested through bitwise AND, making multi-flag operations both expressive and performant.
use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy, Debug)]
struct Permissions: u32 {
const READ = 0b001;
const WRITE = 0b010;
const EXECUTE = 0b100;
}
}
fn basic_contains() {
let perms = Permissions::READ | Permissions::WRITE;
// Check for single flag
assert!(perms.contains(Permissions::READ));
// Check for multiple flags at once
assert!(perms.contains(Permissions::READ | Permissions::WRITE));
// Fails if any flag is missing
assert!(!perms.contains(Permissions::EXECUTE));
assert!(!perms.contains(Permissions::READ | Permissions::EXECUTE));
}contains returns true only if all specified flags are present in the value.
use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy)]
struct Flags: u8 {
const A = 0b0001;
const B = 0b0010;
const C = 0b0100;
const D = 0b1000;
}
}
fn bitwise_explanation() {
let value = Flags::A | Flags::B | Flags::C; // 0b0111
let test = Flags::A | Flags::B; // 0b0011
// contains performs: (value & test) == test
// value & test = 0b0111 & 0b0011 = 0b0011
// 0b0011 == 0b0011 -> true
assert!(value.contains(test));
let test2 = Flags::A | Flags::D; // 0b1001
// value & test2 = 0b0111 & 0b1001 = 0b0001
// 0b0001 != 0b1001 -> false
assert!(!value.contains(test2));
}The implementation uses (self.bits & other.bits) == other.bits for efficiency.
use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy)]
struct FilePerms: u32 {
const READ = 0b001;
const WRITE = 0b010;
const EXECUTE = 0b100;
const RW = Self::READ.bits | Self::WRITE.bits;
const RWX = Self::READ.bits | Self::WRITE.bits | Self::EXECUTE.bits;
}
}
fn composite_flags() {
let file = FilePerms::RW;
// Can check against composite flags
assert!(file.contains(FilePerms::RW));
assert!(file.contains(FilePerms::READ | FilePerms::WRITE));
// Both are equivalent
assert!(file.contains(FilePerms::READ));
assert!(file.contains(FilePerms::WRITE));
assert!(!file.contains(FilePerms::EXECUTE));
}Composite flags combine multiple flags for convenient checking.
use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy)]
struct Capabilities: u32 {
const CAN_READ = 0b0001;
const CAN_WRITE = 0b0010;
const CAN_DELETE = 0b0100;
const CAN_ADMIN = 0b1000;
}
}
fn check_multiple() {
let user_caps = Capabilities::CAN_READ | Capabilities::CAN_WRITE;
// Single operation to check multiple flags
if user_caps.contains(Capabilities::CAN_READ | Capabilities::CAN_WRITE) {
println!("User can read and write");
}
// Compare with individual checks
if user_caps.contains(Capabilities::CAN_READ)
&& user_caps.contains(Capabilities::CAN_WRITE)
{
println!("User can read and write (verbose)");
}
}contains with multiple flags is more concise than multiple individual calls.
use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy, Debug)]
struct Permission: u32 {
const VIEW = 0b0001;
const EDIT = 0b0010;
const DELETE = 0b0100;
const SHARE = 0b1000;
const ADMIN = Self::VIEW.bits | Self::EDIT.bits
| Self::DELETE.bits | Self::SHARE.bits;
}
}
struct User {
name: String,
permissions: Permission,
}
fn check_permission(user: &User, required: Permission) -> bool {
user.permissions.contains(required)
}
fn access_document(user: &User) -> Result<String, &'static str> {
// Require both VIEW and EDIT
if !check_permission(user, Permission::VIEW | Permission::EDIT) {
return Err("Insufficient permissions: need VIEW and EDIT");
}
Ok("Access granted".to_string())
}
fn delete_document(user: &User) -> Result<String, &'static str> {
// Require DELETE permission
if !check_permission(user, Permission::DELETE) {
return Err("Insufficient permissions: need DELETE");
}
Ok("Document deleted".to_string())
}Permission checks using contains are readable and efficient.
use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy)]
struct Status: u32 {
const ACTIVE = 0b0001;
const PENDING = 0b0010;
const VERIFIED = 0b0100;
const SUSPENDED = 0b1000;
}
}
fn contains_vs_intersects() {
let status = Status::ACTIVE | Status::VERIFIED;
// contains: ALL flags must be present
assert!(status.contains(Status::ACTIVE));
assert!(status.contains(Status::ACTIVE | Status::VERIFIED));
assert!(!status.contains(Status::ACTIVE | Status::PENDING));
// intersects: ANY flag can be present
assert!(status.intersects(Status::ACTIVE));
assert!(status.intersects(Status::ACTIVE | Status::VERIFIED));
assert!(status.intersects(Status::ACTIVE | Status::PENDING)); // true because ACTIVE matches
assert!(!status.intersects(Status::PENDING | Status::SUSPENDED)); // neither present
}contains requires all flags; intersects requires any flag.
use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy)]
struct Feature: u32 {
const FEATURE_A = 0b0001;
const FEATURE_B = 0b0010;
const FEATURE_C = 0b0100;
}
}
fn empty_and_all() {
// Empty flags
let empty = Feature::empty();
assert!(!empty.contains(Feature::FEATURE_A));
assert!(empty.contains(Feature::empty())); // Empty contains empty
// All flags
let all = Feature::all();
assert!(all.contains(Feature::FEATURE_A));
assert!(all.contains(Feature::FEATURE_A | Feature::FEATURE_B));
assert!(all.contains(Feature::all())); // All contains all
}empty() contains nothing; all() contains all defined flags.
use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy, Debug)]
struct Mode: u32 {
const READ = 0b001;
const WRITE = 0b010;
const EXECUTE = 0b100;
}
}
fn modify_flags() {
let mut mode = Mode::READ;
// Insert adds flags
mode.insert(Mode::WRITE);
assert!(mode.contains(Mode::READ | Mode::WRITE));
// Remove clears flags
mode.remove(Mode::READ);
assert!(!mode.contains(Mode::READ));
assert!(mode.contains(Mode::WRITE));
// Toggle flips flags
mode.toggle(Mode::READ | Mode::EXECUTE);
assert!(mode.contains(Mode::READ));
assert!(mode.contains(Mode::WRITE));
assert!(mode.contains(Mode::EXECUTE));
}Flag modifications can affect multiple flags at once.
use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy)]
struct Options: u32 {
const A = 0b0001;
const B = 0b0010;
const C = 0b0100;
}
}
fn set_operations() {
let set1 = Options::A | Options::B;
let set2 = Options::B | Options::C;
// Union (OR): contains either set
let union = set1 | set2;
assert!(union.contains(Options::A));
assert!(union.contains(Options::B));
assert!(union.contains(Options::C));
// Intersection (AND): contains both sets
let intersection = set1 & set2;
assert!(intersection.contains(Options::B));
assert!(!intersection.contains(Options::A));
// Difference: contains set1 but not set2
let difference = set1 - set2;
assert!(difference.contains(Options::A));
assert!(!difference.contains(Options::B));
// Symmetric difference (XOR): contains exclusive flags
let sym_diff = set1 ^ set2;
assert!(sym_diff.contains(Options::A));
assert!(sym_diff.contains(Options::C));
assert!(!sym_diff.contains(Options::B));
}Set operations manipulate flag combinations efficiently.
use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy)]
struct Config: u32 {
const ENABLED = 0b0001;
const DEBUG = 0b0010;
const VERBOSE = 0b0100;
const SECURE = 0b1000;
}
}
fn validate_config(config: Config) -> Result<(), String> {
// If ENABLED, must have SECURE or not have DEBUG
if config.contains(Config::ENABLED) {
if config.contains(Config::DEBUG) && !config.contains(Config::SECURE) {
return Err("DEBUG requires SECURE when ENABLED".to_string());
}
}
// VERBOSE requires DEBUG
if config.contains(Config::VERBOSE) && !config.contains(Config::DEBUG) {
return Err("VERBOSE requires DEBUG".to_string());
}
Ok(())
}
fn test_validation() {
let valid = Config::ENABLED | Config::SECURE | Config::DEBUG;
assert!(validate_config(valid).is_ok());
let invalid = Config::ENABLED | Config::DEBUG; // Missing SECURE
assert!(validate_config(invalid).is_err());
}contains enables complex validation logic with readable code.
use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy)]
struct Flags: u64 {
const FLAG_1 = 1;
const FLAG_2 = 2;
const FLAG_3 = 4;
const FLAG_4 = 8;
const FLAG_5 = 16;
}
}
fn performance_comparison() {
let flags = Flags::FLAG_1 | Flags::FLAG_2 | Flags::FLAG_3;
let test = Flags::FLAG_1 | Flags::FLAG_2;
// Single contains call - one bitwise AND + comparison
let result = flags.contains(test);
// Multiple individual checks - multiple AND operations + branches
let result2 = flags.contains(Flags::FLAG_1)
&& flags.contains(Flags::FLAG_2);
// Both produce same result, but contains(test) is more efficient
assert_eq!(result, result2);
}A single contains with combined flags is more efficient than multiple calls.
use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy)]
struct State: u32 {
const INITIALIZED = 0b001;
const CONNECTED = 0b010;
const AUTHENTICATED = 0b100;
}
}
fn check_not_set() {
let state = State::INITIALIZED | State::CONNECTED;
// Check what's NOT set using complement
let not_authenticated = !State::AUTHENTICATED;
let missing = state & not_authenticated;
// missing.contains(AUTHENTICATED) is false - AUTHENTICATED not set
assert!(!missing.contains(State::AUTHENTICATED));
// Or simply check absence:
assert!(!state.contains(State::AUTHENTICATED));
// Check if exactly these flags are set
if state == State::INITIALIZED | State::CONNECTED {
println!("Exactly initialized and connected");
}
}Negation and equality checks complement contains for set operations.
use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy, Debug)]
struct FileMode: u32 {
const USER_READ = 0o400;
const USER_WRITE = 0o200;
const USER_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;
const USER_RW = Self::USER_READ.bits | Self::USER_WRITE.bits;
const USER_RWX = Self::USER_RW.bits | Self::USER_EXEC.bits;
}
}
fn check_file_mode() {
// Typical file: rw-r--r--
let file_mode = FileMode::USER_RW | FileMode::GROUP_READ | FileMode::OTHER_READ;
// Check user has read and write
assert!(file_mode.contains(FileMode::USER_READ | FileMode::USER_WRITE));
// Check user does not have execute
assert!(!file_mode.contains(FileMode::USER_EXEC));
// Check group has read
assert!(file_mode.contains(FileMode::GROUP_READ));
// Check group does not have write
assert!(!file_mode.contains(FileMode::GROUP_WRITE));
}File permissions map naturally to bitflags with contains for checks.
use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy, Debug)]
struct TcpFlags: u16 {
const FIN = 0x01;
const SYN = 0x02;
const RST = 0x04;
const PSH = 0x08;
const ACK = 0x10;
const URG = 0x20;
}
}
fn analyze_tcp_packet(flags: TcpFlags) -> &'static str {
// Check for connection establishment (SYN + ACK)
if flags.contains(TcpFlags::SYN | TcpFlags::ACK) {
return "Connection established (SYN-ACK)";
}
// Check for connection initiation (SYN only, no ACK)
if flags.contains(TcpFlags::SYN) && !flags.contains(TcpFlags::ACK) {
return "Connection initiation (SYN)";
}
// Check for connection termination (FIN)
if flags.contains(TcpFlags::FIN) {
return "Connection closing (FIN)";
}
// Check for reset
if flags.contains(TcpFlags::RST) {
return "Connection reset";
}
// Check for data push with acknowledgment
if flags.contains(TcpFlags::PSH | TcpFlags::ACK) {
return "Data transmission";
}
"Unknown flag combination"
}Protocol flags with multiple bits set are checked efficiently with contains.
use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy, Debug)]
struct FeatureFlags: u64 {
const DARK_MODE = 1 << 0;
const NOTIFICATIONS = 1 << 1;
const ANALYTICS = 1 << 2;
const EXPERIMENTAL_UI = 1 << 3;
const BETA_FEATURES = 1 << 4;
const UI_EXPERIMENTS = Self::DARK_MODE.bits | Self::EXPERIMENTAL_UI.bits;
const PRIVACY_SENSITIVE = Self::ANALYTICS.bits | Self::NOTIFICATIONS.bits;
}
}
struct User {
id: u64,
enabled_features: FeatureFlags,
}
impl User {
fn can_access(&self, required: FeatureFlags) -> bool {
self.enabled_features.contains(required)
}
}
fn feature_checks() {
let user = User {
id: 1,
enabled_features: FeatureFlags::DARK_MODE | FeatureFlags::NOTIFICATIONS,
};
// Check single feature
if user.can_access(FeatureFlags::DARK_MODE) {
println!("Dark mode available");
}
// Check multiple features at once
if user.can_access(FeatureFlags::UI_EXPERIMENTS) {
println!("UI experiments available");
} else {
println!("Missing some UI features");
}
// Check privacy-sensitive features
if user.can_access(FeatureFlags::PRIVACY_SENSITIVE) {
println!("All privacy features enabled");
}
}Feature flag combinations are checked with single contains calls.
Key behaviors:
| Method | Condition | Use Case |
|--------|-----------|----------|
| contains(FLAG) | All bits set | Check for specific flags |
| contains(A \| B) | Both A and B set | Check multiple flags |
| intersects(FLAG) | Any bit set | Check for any match |
| == FLAG | Exactly this value | Check exact match |
Implementation details:
| Operation | Bitwise equivalent |
|-----------|-------------------|
| contains(other) | (self & other) == other |
| intersects(other) | (self & other) != 0 |
| insert(other) | self \| other |
| remove(other) | self & !other |
Common patterns:
| Pattern | Code | Meaning |
|---------|------|---------|
| Has all | flags.contains(A \| B) | Both A and B present |
| Has any | flags.intersects(A \| B) | At least one present |
| Has none | !flags.intersects(A \| B) | Neither present |
| Has exactly | flags == A \| B | Only A and B, nothing else |
Key insight: bitflags::Flags::contains enables checking multiple flags through a single efficient bitwise operationā(value & test) == test returns true only if all tested bits are set in the value. This is more efficient and readable than multiple individual checks because it performs one AND and one comparison instead of multiple operations. Combined with bitwise OR (|), contains expresses "has all of these flags" naturally, while intersects expresses "has any of these flags." The pattern extends to flag modification: insert, remove, and toggle all accept combined flags for batch operations. This makes bitflags ideal for permission systems, protocol headers, feature flags, and state machines where multiple boolean states combine efficiently into a single integer.