use core::{ fmt, ops::{BitAnd, BitOr, BitXor, Not}, }; use crate::{ iter, parser::{ParseError, ParseHex, WriteHex}, }; /** A defined flags value that may be named or unnamed. */ #[derive(Debug)] pub struct Flag { name: &'static str, value: B, } impl Flag { /** Define a flag. If `name` is non-empty then the flag is named, otherwise it's unnamed. */ pub const fn new(name: &'static str, value: B) -> Self { Flag { name, value } } /** Get the name of this flag. If the flag is unnamed then the returned string will be empty. */ pub const fn name(&self) -> &'static str { self.name } /** Get the flags value of this flag. */ pub const fn value(&self) -> &B { &self.value } /** Whether the flag is named. If [`Flag::name`] returns a non-empty string then this method will return `true`. */ pub const fn is_named(&self) -> bool { !self.name.is_empty() } /** Whether the flag is unnamed. If [`Flag::name`] returns a non-empty string then this method will return `false`. */ pub const fn is_unnamed(&self) -> bool { self.name.is_empty() } } /** A set of defined flags using a bits type as storage. ## Implementing `Flags` This trait is implemented by the [`bitflags`](macro.bitflags.html) macro: ``` use bitflags::bitflags; bitflags! { struct MyFlags: u8 { const A = 1; const B = 1 << 1; } } ``` It can also be implemented manually: ``` use bitflags::{Flag, Flags}; struct MyFlags(u8); impl Flags for MyFlags { const FLAGS: &'static [Flag] = &[ Flag::new("A", MyFlags(1)), Flag::new("B", MyFlags(1 << 1)), ]; type Bits = u8; fn from_bits_retain(bits: Self::Bits) -> Self { MyFlags(bits) } fn bits(&self) -> Self::Bits { self.0 } } ``` ## Using `Flags` The `Flags` trait can be used generically to work with any flags types. In this example, we can count the number of defined named flags: ``` # use bitflags::{bitflags, Flags}; fn defined_flags() -> usize { F::FLAGS.iter().filter(|f| f.is_named()).count() } bitflags! { struct MyFlags: u8 { const A = 1; const B = 1 << 1; const C = 1 << 2; const _ = !0; } } assert_eq!(3, defined_flags::()); ``` */ pub trait Flags: Sized + 'static { /// The set of defined flags. const FLAGS: &'static [Flag]; /// The underlying bits type. type Bits: Bits; /// Get a flags value with all bits unset. fn empty() -> Self { Self::from_bits_retain(Self::Bits::EMPTY) } /// Get a flags value with all known bits set. fn all() -> Self { let mut truncated = Self::Bits::EMPTY; for flag in Self::FLAGS.iter() { truncated = truncated | flag.value().bits(); } Self::from_bits_retain(truncated) } /// Get the underlying bits value. /// /// The returned value is exactly the bits set in this flags value. fn bits(&self) -> Self::Bits; /// Convert from a bits value. /// /// This method will return `None` if any unknown bits are set. fn from_bits(bits: Self::Bits) -> Option { let truncated = Self::from_bits_truncate(bits); if truncated.bits() == bits { Some(truncated) } else { None } } /// Convert from a bits value, unsetting any unknown bits. fn from_bits_truncate(bits: Self::Bits) -> Self { Self::from_bits_retain(bits & Self::all().bits()) } /// Convert from a bits value exactly. fn from_bits_retain(bits: Self::Bits) -> Self; /// Get a flags value with the bits of a flag with the given name set. /// /// This method will return `None` if `name` is empty or doesn't /// correspond to any named flag. fn from_name(name: &str) -> Option { // Don't parse empty names as empty flags if name.is_empty() { return None; } for flag in Self::FLAGS { if flag.name() == name { return Some(Self::from_bits_retain(flag.value().bits())); } } None } /// Yield a set of contained flags values. /// /// Each yielded flags value will correspond to a defined named flag. Any unknown bits /// will be yielded together as a final flags value. fn iter(&self) -> iter::Iter { iter::Iter::new(self) } /// Yield a set of contained named flags values. /// /// This method is like [`Flags::iter`], except only yields bits in contained named flags. /// Any unknown bits, or bits not corresponding to a contained flag will not be yielded. fn iter_names(&self) -> iter::IterNames { iter::IterNames::new(self) } /// Whether all bits in this flags value are unset. fn is_empty(&self) -> bool { self.bits() == Self::Bits::EMPTY } /// Whether all known bits in this flags value are set. fn is_all(&self) -> bool { // NOTE: We check against `Self::all` here, not `Self::Bits::ALL` // because the set of all flags may not use all bits Self::all().bits() | self.bits() == self.bits() } /// Whether any set bits in a source flags value are also set in a target flags value. fn intersects(&self, other: Self) -> bool where Self: Sized, { self.bits() & other.bits() != Self::Bits::EMPTY } /// Whether all set bits in a source flags value are also set in a target flags value. fn contains(&self, other: Self) -> bool where Self: Sized, { self.bits() & other.bits() == other.bits() } /// The bitwise or (`|`) of the bits in two flags values. fn insert(&mut self, other: Self) where Self: Sized, { *self = Self::from_bits_retain(self.bits()).union(other); } /// The intersection of a source flags value with the complement of a target flags value (`&!`). /// /// This method is not equivalent to `self & !other` when `other` has unknown bits set. /// `remove` won't truncate `other`, but the `!` operator will. fn remove(&mut self, other: Self) where Self: Sized, { *self = Self::from_bits_retain(self.bits()).difference(other); } /// The bitwise exclusive-or (`^`) of the bits in two flags values. fn toggle(&mut self, other: Self) where Self: Sized, { *self = Self::from_bits_retain(self.bits()).symmetric_difference(other); } /// Call [`Flags::insert`] when `value` is `true` or [`Flags::remove`] when `value` is `false`. fn set(&mut self, other: Self, value: bool) where Self: Sized, { if value { self.insert(other); } else { self.remove(other); } } /// The bitwise and (`&`) of the bits in two flags values. #[must_use] fn intersection(self, other: Self) -> Self { Self::from_bits_retain(self.bits() & other.bits()) } /// The bitwise or (`|`) of the bits in two flags values. #[must_use] fn union(self, other: Self) -> Self { Self::from_bits_retain(self.bits() | other.bits()) } /// The intersection of a source flags value with the complement of a target flags value (`&!`). /// /// This method is not equivalent to `self & !other` when `other` has unknown bits set. /// `difference` won't truncate `other`, but the `!` operator will. #[must_use] fn difference(self, other: Self) -> Self { Self::from_bits_retain(self.bits() & !other.bits()) } /// The bitwise exclusive-or (`^`) of the bits in two flags values. #[must_use] fn symmetric_difference(self, other: Self) -> Self { Self::from_bits_retain(self.bits() ^ other.bits()) } /// The bitwise negation (`!`) of the bits in a flags value, truncating the result. #[must_use] fn complement(self) -> Self { Self::from_bits_truncate(!self.bits()) } } /** A bits type that can be used as storage for a flags type. */ pub trait Bits: Clone + Copy + PartialEq + BitAnd + BitOr + BitXor + Not + Sized + 'static { /// A value with all bits unset. const EMPTY: Self; /// A value with all bits set. const ALL: Self; } // Not re-exported: prevent custom `Bits` impls being used in the `bitflags!` macro, // or they may fail to compile based on crate features pub trait Primitive {} macro_rules! impl_bits { ($($u:ty, $i:ty,)*) => { $( impl Bits for $u { const EMPTY: $u = 0; const ALL: $u = <$u>::MAX; } impl Bits for $i { const EMPTY: $i = 0; const ALL: $i = <$u>::MAX as $i; } impl ParseHex for $u { fn parse_hex(input: &str) -> Result { <$u>::from_str_radix(input, 16).map_err(|_| ParseError::invalid_hex_flag(input)) } } impl ParseHex for $i { fn parse_hex(input: &str) -> Result { <$i>::from_str_radix(input, 16).map_err(|_| ParseError::invalid_hex_flag(input)) } } impl WriteHex for $u { fn write_hex(&self, mut writer: W) -> fmt::Result { write!(writer, "{:x}", self) } } impl WriteHex for $i { fn write_hex(&self, mut writer: W) -> fmt::Result { write!(writer, "{:x}", self) } } impl Primitive for $i {} impl Primitive for $u {} )* } } impl_bits! { u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize, } /// A trait for referencing the `bitflags`-owned internal type /// without exposing it publicly. pub trait PublicFlags { /// The type of the underlying storage. type Primitive: Primitive; /// The type of the internal field on the generated flags type. type Internal; } #[doc(hidden)] #[deprecated(note = "use the `Flags` trait instead")] pub trait BitFlags: ImplementedByBitFlagsMacro + Flags { /// An iterator over enabled flags in an instance of the type. type Iter: Iterator; /// An iterator over the raw names and bits for enabled flags in an instance of the type. type IterNames: Iterator; } #[allow(deprecated)] impl BitFlags for B { type Iter = iter::Iter; type IterNames = iter::IterNames; } impl ImplementedByBitFlagsMacro for B {} /// A marker trait that signals that an implementation of `BitFlags` came from the `bitflags!` macro. /// /// There's nothing stopping an end-user from implementing this trait, but we don't guarantee their /// manual implementations won't break between non-breaking releases. #[doc(hidden)] pub trait ImplementedByBitFlagsMacro {} pub(crate) mod __private { pub use super::{ImplementedByBitFlagsMacro, PublicFlags}; }