bitflag-attr 0.13.0

A macro to generate bitflags structures from C-like enums
Documentation
//! An example on creating a bitflag manually using `bitflag-attr` infrastructure without using the
//! `bitflag` macro.
//!
//! A caveat of doing this, is that your type won't have the const-compatible API generated by the
//! macro.
use core::{fmt, str};

use bitflag_attr::Flags;

// First: Define your flags type. It just needs to be `Sized + Copy + 'static`.
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct ManualFlags(u32);

// Not required: Define some constants for valid flags
impl ManualFlags {
    const FLAG1: Self = Self(1 << 9);
    const FLAG2: Self = Self(1 << 12);
    const FLAG3: Self = Self(1);
    const FLAG4: Self = Self(Self::FLAG1.0 | Self::FLAG2.0);
}

// Next: Implement the `Flags` trait, specifying your set of valid flags and iterators
impl Flags for ManualFlags {
    // Definition all of your named known flags.
    const NAMED_FLAGS: &'static [(&'static str, Self)] = &[
        ("FLAG1", Self::FLAG1),
        ("FLAG2", Self::FLAG2),
        ("FLAG3", Self::FLAG3),
        ("FLAG4", Self::FLAG4),
    ];

    // Here you can define a value of the reserved bits that can be used used but are not
    // necessarily named. This affect what bits the methods consider to do truncating operations.
    //
    // If all named flags are all flags that should be considered, the value can be zero (`0`). Or,
    // if you prefer, the same as the union of your named flags.
    //
    // But if your flag type represents an external flag (C FFI for example), you can define a value
    // that matches the bits that could be set. For most cases, it is `!0` (i.e. all bits could be
    // set externally)
    const RESERVED_BITS: Self::Bits = 0;

    type Bits = u32;

    fn bits(&self) -> Self::Bits {
        self.0
    }

    fn from_bits_retain(bits: Self::Bits) -> Self {
        Self(bits)
    }
}

// Not required: Add parsing support
impl str::FromStr for ManualFlags {
    type Err = bitflag_attr::parser::ParseError;

    fn from_str(input: &str) -> Result<Self, Self::Err> {
        bitflag_attr::parser::from_text(input)
    }
}

// Not required: Add formatting support
impl fmt::Display for ManualFlags {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        bitflag_attr::parser::to_writer(self, f)
    }
}

// Not required: Add debug formatting support with human-readable, binary, octal and hexadecimal
// representations.
impl fmt::Debug for ManualFlags {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        struct HumanReadable<'a>(&'a ManualFlags);

        impl fmt::Debug for HumanReadable<'_> {
            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                if self.0.is_empty() {
                    write!(f, "{:#X}", self.0 .0)
                } else {
                    bitflag_attr::parser::to_writer(self.0, f)
                }
            }
        }

        #[inline]
        pub const fn octal_width() -> usize {
            match u32::BITS as usize {
                8 => 3,
                16 => 6,
                32 => 11,
                64 => 22,
                128 => 43,
                // Not probable to happens, but if it does, do an approximation
                x => x / 3 + x % 3,
            }
        }

        f.debug_struct("ManualFlags")
            .field("flags", &HumanReadable(self))
            // The width `2 +` is to account for the 0b|0o|0x printed before the binary number
            .field(
                "bits",
                &::core::format_args!("{:#0width$b}", self.0, width = 2 + u32::BITS as usize),
            )
            .field(
                "octal",
                &::core::format_args!("{:#0width$o}", self.0, width = 2 + const { octal_width() }),
            )
            .field(
                "hex",
                &::core::format_args!(
                    "{:#0width$X}",
                    self.0,
                    width = 2 + const { u32::BITS as usize / 4 }
                ),
            )
            .finish()
    }
}

fn main() {
    let mut flag = ManualFlags::FLAG1
        .union(ManualFlags::FLAG2)
        .union(ManualFlags::FLAG3);

    flag.set(ManualFlags::from_bits_retain(1 << 5));

    println!("Display: {}", flag);
    println!("Debug: {:#?}", flag);
}