aboutsummaryrefslogtreecommitdiff
path: root/src/traits.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/traits.rs')
-rw-r--r--src/traits.rs269
1 files changed, 175 insertions, 94 deletions
diff --git a/src/traits.rs b/src/traits.rs
index f8fc757..2823514 100644
--- a/src/traits.rs
+++ b/src/traits.rs
@@ -1,60 +1,164 @@
-use core::{fmt, ops::{BitAnd, BitOr, BitXor, Not}};
-
-use crate::{parser::{ParseError, ParseHex, WriteHex}, iter};
-
-/// Metadata for an individual flag.
+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.
+*/
pub struct Flag<B> {
name: &'static str,
value: B,
}
impl<B> Flag<B> {
- /// Create a new flag with the given name and value.
+ /**
+ 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.
+ /**
+ 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 value of this flag.
+ /**
+ 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 flags.
-///
-/// This trait is automatically implemented for flags types defined using the `bitflags!` macro.
-/// It can also be implemented manually for custom flags types.
+/**
+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<Self>] = &[
+ 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<F: 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::<MyFlags>());
+```
+*/
pub trait Flags: Sized + 'static {
- /// The set of available flags and their names.
+ /// The set of defined flags.
const FLAGS: &'static [Flag<Self>];
- /// The underlying storage type.
+ /// The underlying bits type.
type Bits: Bits;
- /// Returns an empty set of flags.
+ /// Get a flags value with all bits unset.
fn empty() -> Self {
Self::from_bits_retain(Self::Bits::EMPTY)
}
- /// Returns the set containing all flags.
+ /// Get a flags value with all known bits set.
fn all() -> Self {
- Self::from_bits_truncate(Self::Bits::ALL)
+ let mut truncated = Self::Bits::EMPTY;
+
+ for flag in Self::FLAGS.iter() {
+ truncated = truncated | flag.value().bits();
+ }
+
+ Self::from_bits_retain(truncated)
}
- /// Returns the raw value of the flags currently stored.
+ /// Get the underlying bits value.
+ ///
+ /// The returned value is exactly the bits set in this flags value.
fn bits(&self) -> Self::Bits;
- /// Convert from underlying bit representation, unless that
- /// representation contains bits that do not correspond to a flag.
- ///
- /// Note that each [multi-bit flag] is treated as a unit for this comparison.
+ /// Convert from a bits value.
///
- /// [multi-bit flag]: index.html#multi-bit-flags
+ /// This method will return `None` if any unknown bits are set.
fn from_bits(bits: Self::Bits) -> Option<Self> {
let truncated = Self::from_bits_truncate(bits);
@@ -65,68 +169,62 @@ pub trait Flags: Sized + 'static {
}
}
- /// Convert from underlying bit representation, dropping any bits
- /// that do not correspond to flags.
- ///
- /// Note that each [multi-bit flag] is treated as a unit for this comparison.
- ///
- /// [multi-bit flag]: index.html#multi-bit-flags
+ /// Convert from a bits value, unsetting any unknown bits.
fn from_bits_truncate(bits: Self::Bits) -> Self {
- if bits == Self::Bits::EMPTY {
- return Self::empty();
- }
-
- let mut truncated = Self::Bits::EMPTY;
-
- for flag in Self::FLAGS.iter() {
- let flag = flag.value();
-
- if bits & flag.bits() == flag.bits() {
- truncated = truncated | flag.bits();
- }
- }
-
- Self::from_bits_retain(truncated)
+ Self::from_bits_retain(bits & Self::all().bits())
}
- /// Convert from underlying bit representation, preserving all
- /// bits (even those not corresponding to a defined flag).
+ /// Convert from a bits value exactly.
fn from_bits_retain(bits: Self::Bits) -> Self;
- /// Get the flag for a particular name.
+ /// 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<Self> {
+ // 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()))
+ return Some(Self::from_bits_retain(flag.value().bits()));
}
}
None
}
- /// Iterate over enabled flag values.
+ /// 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<Self> {
iter::Iter::new(self)
}
- /// Iterate over the raw names and bits for enabled flag values.
+ /// 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<Self> {
iter::IterNames::new(self)
}
- /// Returns `true` if no flags are currently stored.
+ /// Whether all bits in this flags value are unset.
fn is_empty(&self) -> bool {
self.bits() == Self::Bits::EMPTY
}
- /// Returns `true` if all flags are currently set.
+ /// 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()
}
- /// Returns `true` if there are flags common to both `self` and `other`.
+ /// 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,
@@ -134,7 +232,7 @@ pub trait Flags: Sized + 'static {
self.bits() & other.bits() != Self::Bits::EMPTY
}
- /// Returns `true` if all of the flags in `other` are contained within `self`.
+ /// 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,
@@ -142,31 +240,34 @@ pub trait Flags: Sized + 'static {
self.bits() & other.bits() == other.bits()
}
- /// Inserts the specified flags in-place.
+ /// 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() | other.bits());
+ *self = Self::from_bits_retain(self.bits()).union(other);
}
- /// Removes the specified flags in-place.
+ /// 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() & !other.bits());
+ *self = Self::from_bits_retain(self.bits()).difference(other);
}
- /// Toggles the specified flags in-place.
+ /// 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() ^ other.bits());
+ *self = Self::from_bits_retain(self.bits()).symmetric_difference(other);
}
- /// Inserts or removes the specified flags depending on the passed value.
+ /// 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,
@@ -178,64 +279,43 @@ pub trait Flags: Sized + 'static {
}
}
- /// Returns the intersection between the flags in `self` and
- /// `other`.
- ///
- /// Specifically, the returned set contains only the flags which are
- /// present in *both* `self` *and* `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())
}
- /// Returns the union of between the flags in `self` and `other`.
- ///
- /// Specifically, the returned set contains all flags which are
- /// present in *either* `self` *or* `other`, including any which are
- /// present in both (see [`Self::symmetric_difference`] if that
- /// is undesirable).
+ /// 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())
}
- /// Returns the difference between the flags in `self` and `other`.
- ///
- /// Specifically, the returned set contains all flags present in
- /// `self`, except for the ones present in `other`.
+ /// The intersection of a source flags value with the complement of a target flags value (`&!`).
///
- /// It is also conceptually equivalent to the "bit-clear" operation:
- /// `flags & !other` (and this syntax is also supported).
+ /// 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())
}
- /// Returns the [symmetric difference][sym-diff] between the flags
- /// in `self` and `other`.
- ///
- /// Specifically, the returned set contains the flags present which
- /// are present in `self` or `other`, but that are not present in
- /// both. Equivalently, it contains the flags present in *exactly
- /// one* of the sets `self` and `other`.
- ///
- /// [sym-diff]: https://en.wikipedia.org/wiki/Symmetric_difference
+ /// 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())
}
- /// Returns the complement of this set of flags.
- ///
- /// Specifically, the returned set contains all the flags which are
- /// not set in `self`, but which are allowed for this type.
+ /// 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())
}
}
-/// Underlying storage for a flags type.
+/**
+A bits type that can be used as storage for a flags type.
+*/
pub trait Bits:
Clone
+ Copy
@@ -247,10 +327,10 @@ pub trait Bits:
+ Sized
+ 'static
{
- /// The value of `Self` where no bits are set.
+ /// A value with all bits unset.
const EMPTY: Self;
- /// The value of `Self` where all bits are set.
+ /// A value with all bits set.
const ALL: Self;
}
@@ -320,6 +400,7 @@ pub trait PublicFlags {
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.