bitflags

repository·main·Indexed 22 days ago

https://github.com/bitflags/bitflags

A Rust library that generates flag enums with well-defined semantics and ergonomic APIs. It provides a macro for creating structs that manage sets of flags, supporting standard bitwise operations, string parsing/formatting, and integration with crates like serde, arbitrary, and bytemuck. It is particularly useful for creating user-friendly bindings to C APIs and efficient options types.

Tokens
4.8K
Snippets
13
Records
24
Agent score
77%

What's inside bitflags

  1. Check if a flags value contains, intersects, or is empty

    main

    When working with Flags values, you can perform several logical checks:

    • Contains: Returns true if all set bits in the source flags value are also set in the target flags value.
    • Intersects: Returns true if any set bits in the source flags value are also set in the target flags value.
    • Empty: Returns true if all bits in the flags value are unset (0b0000_0000).
    • All: Returns true if all defined flags in the flags type are contained within the flags value.

    Example logic for a value 0b0000_0011:

    • It contains: 0b0000_0000, 0b0000_0010, 0b0000_0001, 0b0000_0011.
    • It intersects: 0b0000_0010, 0b0000_0001, 0b1111_1111.
    • It does not intersect: 0b0000_0000, 0b1111_0000.
  2. Perform bitwise operations on flags values

    main

    You can combine or compare flags values using standard bitwise operations. Given a flags type with flags A, B, and C:

    • Union (|): Bitwise OR. Combines bits from two values.
    • Intersection (&): Bitwise AND. Returns only bits present in both.
    • Symmetric difference (^): Bitwise XOR. Returns bits present in one value or the other, but not both.
    • Complement (!): Bitwise NOT. Inverts bits and truncates the result to only include known bits.
    • Difference: Bitwise intersection of one value and the negation of another (val1 & !val2). Note that this is distinct from val1 & !val2 if the negation is not truncated.
    • Truncate: Unsets all bits that are not part of any defined flag in the flags type.
  3. Iterate over flags values

    main

    Iteration yields the bits of a source flags value as a set of contained flags values.

    Each yielded value should ideally set exactly the bits of a defined flag. Any known bits that are not part of a defined flag are yielded together as a final flags value.

    Example Behavior: If Flags defines A = 0b0001, B = 0b0010, and AB = 0b0011, iterating over 0b1111 might yield:

    1. A (0b0001)
    2. B (0b0010)
    3. A final value containing the remaining bits (0b1100).
  4. Understand the bitflags terminology and semantics

    main

    To use bitflags effectively, it is important to distinguish between its core abstractions:

    • Bits type: The underlying storage type, typically a fixed-width unsigned integer (e.g., u8, u32).
    • Bits value: An instance of a bits type representing a specific configuration of set (1) and unset (0) bits.
    • Flag: A specific set of bits within a bits type, which may or may not have a unique name. Flags can be single-bit, multi-bit, or even zero-bit.
    • Flags type: A collection of defined flags associated with a specific bits type.
    • Flags value: An instance of a flags type used for storage and manipulation.

    Note on safety: bitflags does not guarantee that only defined flags will be set. Because you have access to the underlying bits type, arbitrary bits can be set, resulting in "unknown bits" that are not part of any defined flag.

  5. Generate flags enums with the bitflags! macro

    main

    Use the bitflags! macro to generate a struct that manages a set of flags. You specify the underlying integer type (e.g., u32) and define constants representing specific bit positions. The macro supports standard bitwise operations like union (|), intersection (&), set difference (-), and complement (!).

    Note that bitflags does not guarantee that only defined bits will be set; the underlying bits type remains accessible, allowing arbitrary bits to be set.

    use bitflags::bitflags;
    
    // The `bitflags!` macro generates `struct`s that manage a set of flags.
    bitflags! {
        #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
        struct Flags: u32 {
            const A = 0b00000001;
            const B = 0b00000010;
            const C = 0b00000100;
    
            /// The combination of `A`, `B`, and `C`.
            const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits();
        }
    }
    
    fn main() {
        let e1 = Flags::A | Flags::C;
        let e2 = Flags::B | Flags::C;
        assert_eq!((e1 | e2), Flags::ABC);   // union
        assert_eq!((e1 & e2), Flags::C);     // intersection
        assert_eq!((e1 - e2), Flags::A);     // set difference
        assert_eq!(!e2, Flags::A);           // set complement
    }
  6. Handle externally defined flags with unnamed flags

    main

    When generating flags for an external source (like a C API), you can define an unnamed flag using the _ identifier. This flag acts as a mask for all bits that the external source might set. This ensures that methods like all() and truncating operators like ! consider these bits, improving compatibility if the external source adds new bits later.

    # use bitflags::bitflags;
    bitflags! {
        pub struct Flags: u32 {
            const A = 0b00000001;
            const B = 0b00000010;
            const C = 0b00000100;
    
            // The source may set any bits
            const _ = !0;
        }
    }
  7. Iterate over all defined flags regardless of value with `IterDefinedNames`

    main
    The IterDefinedNames iterator yields all defined, named flags for a specific Flags type, regardless of whether those flags are actually set in a particular instance. Each item is a pair of (&'static str, B) representing the name and the bit value of the flag.
  8. Understand bitflags terminology

    main

    The library uses specific terminology to describe its components:

    • Bits type: The underlying integer type (e.g., u8, u32) that defines the storage.
    • Flag: A specific set of bits within a bits type, which may have a name.
    • Flags type: The collection of defined flags over a specific bits type.
    • Flags value: An instance of a flags type containing specific bits.

    Known vs Unknown Bits

    • Known bits: Bits explicitly defined in your bitflags! declaration.
    • Unknown bits: Any bits set in a value that were not explicitly defined in the flags type.
  9. Find names for a specific bit pattern with `IterEqualNames`

    main
    The IterEqualNames iterator yields the names (&'static str) of all defined flags that exactly match the bit pattern of a given flags value. This is useful for finding which named flag (or combination of flags) corresponds to a specific set of bits.
  10. Iterate over contained flags with `Iter`

    main

    The Iter iterator yields the values of the flags contained within a specific flags instance. It first yields all defined, named flags that are present in the source, and then yields any remaining bits (bits that do not correspond to a named flag) as a final value. This ensures that into_iter() and from_iter() can roundtrip correctly.

    Note: Iter is typically accessed via the into_iter() method on a Flags type generated by the bitflags! macro.

  11. Iterate over named flags and their values with `IterNames`

    main

    The IterNames iterator yields pairs of (&'static str, B), where the string is the name of a defined, named flag and B is its value. This iterator only yields flags that are actually contained in the source value. Any bits that do not correspond to a named flag are not yielded by this iterator, but can be retrieved using the .remaining() method.

    Use IterNames when you only care about the explicitly named flags present in a bitset and want to know if there are any 'unnamed' bits left over.

    // Example of how the underlying logic works for named flags
    // (Typically used via the bitflags! macro's generated methods)
    for (name, flag_value) in flags_instance.iter_names() {
        println!("Flag {} is set", name);
    }
    
    if !flags_instance.iter_names().remaining().is_empty() {
        println!("Warning: Unnamed bits are set!");
    }