aboutsummaryrefslogtreecommitdiff
path: root/src/internal.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/internal.rs')
-rw-r--r--src/internal.rs505
1 files changed, 28 insertions, 477 deletions
diff --git a/src/internal.rs b/src/internal.rs
index eca0a30..c4fb653 100644
--- a/src/internal.rs
+++ b/src/internal.rs
@@ -10,29 +10,14 @@
#[doc(hidden)]
macro_rules! __declare_internal_bitflags {
(
- $vis:vis struct $InternalBitFlags:ident: $T:ty;
- $iter_vis:vis struct $Iter:ident;
- $iter_names_vis:vis struct $IterNames:ident;
+ $vis:vis struct $InternalBitFlags:ident: $T:ty
) => {
// NOTE: The ABI of this type is _guaranteed_ to be the same as `T`
// This is relied on by some external libraries like `bytemuck` to make
// its `unsafe` trait impls sound.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
- $vis struct $InternalBitFlags {
- bits: $T,
- }
-
- $iter_vis struct $Iter {
- inner: $IterNames,
- done: bool,
- }
-
- $iter_names_vis struct $IterNames {
- idx: usize,
- source: $InternalBitFlags,
- state: $InternalBitFlags,
- }
+ $vis struct $InternalBitFlags($T);
};
}
@@ -44,14 +29,18 @@ macro_rules! __declare_internal_bitflags {
#[doc(hidden)]
macro_rules! __impl_internal_bitflags {
(
- $InternalBitFlags:ident: $T:ty, $BitFlags:ident, $Iter:ident, $IterNames:ident {
+ $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident {
$(
$(#[$attr:ident $($args:tt)*])*
- $Flag:ident;
+ $Flag:ident = $value:expr;
)*
}
) => {
- impl $crate::__private::PublicFlags for $BitFlags {
+ // NOTE: This impl is also used to prevent using bits types from non-primitive types
+ // in the `bitflags` macro. If this approach is changed, this guard will need to be
+ // retained somehow
+ impl $crate::__private::PublicFlags for $PublicBitFlags {
+ type Primitive = $T;
type Internal = $InternalBitFlags;
}
@@ -73,7 +62,7 @@ macro_rules! __impl_internal_bitflags {
// We can remove this `0x0` and remain compatible with `FromStr`,
// because an empty string will still parse to an empty set of flags,
// just like `0x0` does.
- $crate::__private::core::write!(f, "{:#x}", <$T as $crate::__private::Bits>::EMPTY)
+ $crate::__private::core::write!(f, "{:#x}", <$T as $crate::Bits>::EMPTY)
} else {
$crate::__private::core::fmt::Display::fmt(self, f)
}
@@ -82,278 +71,21 @@ macro_rules! __impl_internal_bitflags {
impl $crate::__private::core::fmt::Display for $InternalBitFlags {
fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter<'_>) -> $crate::__private::core::fmt::Result {
- // A formatter for bitflags that produces text output like:
- //
- // A | B | 0xf6
- //
- // The names of set flags are written in a bar-separated-format,
- // followed by a hex number of any remaining bits that are set
- // but don't correspond to any flags.
-
- // Iterate over the valid flags
- let mut first = true;
- let mut iter = self.iter_names();
- for (name, _) in &mut iter {
- if !first {
- f.write_str(" | ")?;
- }
-
- first = false;
- f.write_str(name)?;
- }
-
- // Append any extra bits that correspond to flags to the end of the format
- let extra_bits = iter.state.bits();
- if extra_bits != <$T as $crate::__private::Bits>::EMPTY {
- if !first {
- f.write_str(" | ")?;
- }
-
- $crate::__private::core::write!(f, "{:#x}", extra_bits)?;
- }
-
- $crate::__private::core::fmt::Result::Ok(())
+ $crate::parser::to_writer(&$PublicBitFlags(*self), f)
}
}
- // The impl for `FromStr` should parse anything produced by `Display`
impl $crate::__private::core::str::FromStr for $InternalBitFlags {
type Err = $crate::parser::ParseError;
fn from_str(s: &str) -> $crate::__private::core::result::Result<Self, Self::Err> {
- let s = s.trim();
-
- let mut parsed_flags = Self::empty();
-
- // If the input is empty then return an empty set of flags
- if s.is_empty() {
- return $crate::__private::core::result::Result::Ok(parsed_flags);
- }
-
- for flag in s.split('|') {
- let flag = flag.trim();
-
- // If the flag is empty then we've got missing input
- if flag.is_empty() {
- return $crate::__private::core::result::Result::Err($crate::parser::ParseError::empty_flag());
- }
-
- // If the flag starts with `0x` then it's a hex number
- // Parse it directly to the underlying bits type
- let parsed_flag = if let $crate::__private::core::option::Option::Some(flag) = flag.strip_prefix("0x") {
- let bits = <$T>::from_str_radix(flag, 16).map_err(|_| $crate::parser::ParseError::invalid_hex_flag(flag))?;
-
- Self::from_bits_retain(bits)
- }
- // Otherwise the flag is a name
- // The generated flags type will determine whether
- // or not it's a valid identifier
- else {
- Self::from_name(flag).ok_or_else(|| $crate::parser::ParseError::invalid_named_flag(flag))?
- };
-
- parsed_flags.insert(parsed_flag);
- }
-
- $crate::__private::core::result::Result::Ok(parsed_flags)
- }
- }
-
- impl $crate::__private::core::fmt::Binary for $InternalBitFlags {
- fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result {
- $crate::__private::core::fmt::Binary::fmt(&self.bits(), f)
- }
- }
-
- impl $crate::__private::core::fmt::Octal for $InternalBitFlags {
- fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result {
- $crate::__private::core::fmt::Octal::fmt(&self.bits(), f)
- }
- }
-
- impl $crate::__private::core::fmt::LowerHex for $InternalBitFlags {
- fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result {
- $crate::__private::core::fmt::LowerHex::fmt(&self.bits(), f)
- }
- }
-
- impl $crate::__private::core::fmt::UpperHex for $InternalBitFlags {
- fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result {
- $crate::__private::core::fmt::UpperHex::fmt(&self.bits(), f)
- }
- }
-
- impl $InternalBitFlags {
- #[inline]
- pub const fn empty() -> Self {
- Self { bits: <$T as $crate::__private::Bits>::EMPTY }
- }
-
- #[inline]
- pub const fn all() -> Self {
- Self::from_bits_truncate(<$T as $crate::__private::Bits>::ALL)
- }
-
- #[inline]
- pub const fn bits(&self) -> $T {
- self.bits
- }
-
- #[inline]
- pub fn bits_mut(&mut self) -> &mut $T {
- &mut self.bits
- }
-
- #[inline]
- pub const fn from_bits(bits: $T) -> $crate::__private::core::option::Option<Self> {
- let truncated = Self::from_bits_truncate(bits).bits;
-
- if truncated == bits {
- $crate::__private::core::option::Option::Some(Self { bits })
- } else {
- $crate::__private::core::option::Option::None
- }
- }
-
- #[inline]
- pub const fn from_bits_truncate(bits: $T) -> Self {
- if bits == <$T as $crate::__private::Bits>::EMPTY {
- return Self { bits }
- }
-
- let mut truncated = <$T as $crate::__private::Bits>::EMPTY;
-
- $(
- __expr_safe_flags!(
- $(#[$attr $($args)*])*
- {
- if bits & $BitFlags::$Flag.bits() == $BitFlags::$Flag.bits() {
- truncated |= $BitFlags::$Flag.bits()
- }
- }
- );
- )*
-
- Self { bits: truncated }
- }
-
- #[inline]
- pub const fn from_bits_retain(bits: $T) -> Self {
- Self { bits }
- }
-
- #[inline]
- pub fn from_name(name: &str) -> $crate::__private::core::option::Option<Self> {
- $(
- __expr_safe_flags!(
- $(#[$attr $($args)*])*
- {
- if name == $crate::__private::core::stringify!($Flag) {
- return $crate::__private::core::option::Option::Some(Self { bits: $BitFlags::$Flag.bits() });
- }
- }
- );
- )*
-
- let _ = name;
- $crate::__private::core::option::Option::None
- }
-
- #[inline]
- pub const fn iter(&self) -> $Iter {
- $Iter {
- inner: self.iter_names(),
- done: false,
- }
- }
-
- #[inline]
- pub const fn iter_names(&self) -> $IterNames {
- $IterNames {
- idx: 0,
- source: *self,
- state: *self,
- }
- }
-
- #[inline]
- pub const fn is_empty(&self) -> bool {
- self.bits == Self::empty().bits
- }
-
- #[inline]
- pub const fn is_all(&self) -> bool {
- Self::all().bits | self.bits == self.bits
- }
-
- #[inline]
- pub const fn intersects(&self, other: Self) -> bool {
- !(Self { bits: self.bits & other.bits}).is_empty()
- }
-
- #[inline]
- pub const fn contains(&self, other: Self) -> bool {
- (self.bits & other.bits) == other.bits
- }
-
- #[inline]
- pub fn insert(&mut self, other: Self) {
- self.bits |= other.bits;
- }
-
- #[inline]
- pub fn remove(&mut self, other: Self) {
- self.bits &= !other.bits;
- }
-
- #[inline]
- pub fn toggle(&mut self, other: Self) {
- self.bits ^= other.bits;
- }
-
- #[inline]
- pub fn set(&mut self, other: Self, value: bool) {
- if value {
- self.insert(other);
- } else {
- self.remove(other);
- }
- }
-
- #[inline]
- #[must_use]
- pub const fn intersection(self, other: Self) -> Self {
- Self { bits: self.bits & other.bits }
- }
-
- #[inline]
- #[must_use]
- pub const fn union(self, other: Self) -> Self {
- Self { bits: self.bits | other.bits }
- }
-
- #[inline]
- #[must_use]
- pub const fn difference(self, other: Self) -> Self {
- Self { bits: self.bits & !other.bits }
- }
-
- #[inline]
- #[must_use]
- pub const fn symmetric_difference(self, other: Self) -> Self {
- Self { bits: self.bits ^ other.bits }
- }
-
- #[inline]
- #[must_use]
- pub const fn complement(self) -> Self {
- Self::from_bits_truncate(!self.bits)
+ $crate::parser::from_str::<$PublicBitFlags>(s).map(|flags| flags.0)
}
}
impl $crate::__private::core::convert::AsRef<$T> for $InternalBitFlags {
fn as_ref(&self) -> &$T {
- &self.bits
+ &self.0
}
}
@@ -363,208 +95,27 @@ macro_rules! __impl_internal_bitflags {
}
}
- impl $crate::__private::core::iter::Iterator for $Iter {
- type Item = $BitFlags;
-
- fn next(&mut self) -> $crate::__private::core::option::Option<Self::Item> {
- match self.inner.next().map(|(_, value)| value) {
- $crate::__private::core::option::Option::Some(value) => $crate::__private::core::option::Option::Some(value),
- $crate::__private::core::option::Option::None if !self.done => {
- self.done = true;
+ // The internal flags type offers a similar API to the public one
- // After iterating through valid names, if there are any bits left over
- // then return one final value that includes them. This makes `into_iter`
- // and `from_iter` roundtrip
- if self.inner.state != $InternalBitFlags::empty() {
- $crate::__private::core::option::Option::Some($BitFlags::from_bits_retain(self.inner.state.bits()))
- } else {
- $crate::__private::core::option::Option::None
- }
- },
- _ => $crate::__private::core::option::Option::None,
- }
+ __impl_public_bitflags! {
+ $InternalBitFlags: $T, $PublicBitFlags {
+ $(
+ $(#[$attr $($args)*])*
+ $Flag;
+ )*
}
}
- impl $crate::__private::core::iter::Iterator for $IterNames {
- type Item = (&'static str, $BitFlags);
-
- fn next(&mut self) -> $crate::__private::core::option::Option<Self::Item> {
- const NUM_FLAGS: usize = {
- let mut num_flags = 0;
-
- $(
- __expr_safe_flags!(
- $(#[$attr $($args)*])*
- {
- { num_flags += 1; }
- }
- );
- )*
-
- num_flags
- };
-
- const OPTIONS: [$T; NUM_FLAGS] = [
- $(
- __expr_safe_flags!(
- $(#[$attr $($args)*])*
- {
- $BitFlags::$Flag.bits()
- }
- ),
- )*
- ];
-
- const OPTIONS_NAMES: [&'static str; NUM_FLAGS] = [
- $(
- __expr_safe_flags!(
- $(#[$attr $($args)*])*
- {
- $crate::__private::core::stringify!($Flag)
- }
- ),
- )*
- ];
-
- if self.state.is_empty() || NUM_FLAGS == 0 {
- $crate::__private::core::option::Option::None
- } else {
- #[allow(clippy::indexing_slicing)]
- for (flag, flag_name) in OPTIONS[self.idx..NUM_FLAGS].iter().copied()
- .zip(OPTIONS_NAMES[self.idx..NUM_FLAGS].iter().copied())
- {
- self.idx += 1;
-
- // NOTE: We check whether the flag exists in self, but remove it from
- // a different value. This ensure that overlapping flags are handled
- // properly. Take the following example:
- //
- // const A: 0b00000001;
- // const B: 0b00000101;
- //
- // Given the bits 0b00000101, both A and B are set. But if we removed A
- // as we encountered it we'd be left with 0b00000100, which doesn't
- // correspond to a valid flag on its own.
- if self.source.contains($InternalBitFlags { bits: flag }) {
- self.state.remove($InternalBitFlags { bits: flag });
-
- return $crate::__private::core::option::Option::Some((flag_name, $BitFlags::from_bits_retain(flag)))
- }
- }
-
- $crate::__private::core::option::Option::None
- }
- }
+ __impl_public_bitflags_iter! {
+ $InternalBitFlags: $T, $PublicBitFlags
}
- };
-}
-/// A macro that processed the input to `bitflags!` and shuffles attributes around
-/// based on whether or not they're "expression-safe".
-///
-/// This macro is a token-tree muncher that works on 2 levels:
-///
-/// For each attribute, we explicitly match on its identifier, like `cfg` to determine
-/// whether or not it should be considered expression-safe.
-///
-/// If you find yourself with an attribute that should be considered expression-safe
-/// and isn't, it can be added here.
-#[macro_export(local_inner_macros)]
-#[doc(hidden)]
-macro_rules! __expr_safe_flags {
- // Entrypoint: Move all flags and all attributes into `unprocessed` lists
- // where they'll be munched one-at-a-time
- (
- $(#[$inner:ident $($args:tt)*])*
- { $e:expr }
- ) => {
- __expr_safe_flags! {
- expr: { $e },
- attrs: {
- // All attributes start here
- unprocessed: [$(#[$inner $($args)*])*],
- processed: {
- // Attributes that are safe on expressions go here
- expr: [],
- },
- },
- }
- };
- // Process the next attribute on the current flag
- // `cfg`: The next flag should be propagated to expressions
- // NOTE: You can copy this rules block and replace `cfg` with
- // your attribute name that should be considered expression-safe
- (
- expr: { $e:expr },
- attrs: {
- unprocessed: [
- // cfg matched here
- #[cfg $($args:tt)*]
- $($attrs_rest:tt)*
- ],
- processed: {
- expr: [$($expr:tt)*],
- },
- },
- ) => {
- __expr_safe_flags! {
- expr: { $e },
- attrs: {
- unprocessed: [
- $($attrs_rest)*
- ],
- processed: {
- expr: [
- $($expr)*
- // cfg added here
- #[cfg $($args)*]
- ],
- },
- },
- }
- };
- // Process the next attribute on the current flag
- // `$other`: The next flag should not be propagated to expressions
- (
- expr: { $e:expr },
- attrs: {
- unprocessed: [
- // $other matched here
- #[$other:ident $($args:tt)*]
- $($attrs_rest:tt)*
- ],
- processed: {
- expr: [$($expr:tt)*],
- },
- },
- ) => {
- __expr_safe_flags! {
- expr: { $e },
- attrs: {
- unprocessed: [
- $($attrs_rest)*
- ],
- processed: {
- expr: [
- // $other not added here
- $($expr)*
- ],
- },
- },
+ impl $InternalBitFlags {
+ /// Returns a mutable reference to the raw value of the flags currently stored.
+ #[inline]
+ pub fn bits_mut(&mut self) -> &mut $T {
+ &mut self.0
+ }
}
};
- // Once all attributes on all flags are processed, generate the actual code
- (
- expr: { $e:expr },
- attrs: {
- unprocessed: [],
- processed: {
- expr: [$(#[$expr:ident $($exprargs:tt)*])*],
- },
- },
- ) => {
- $(#[$expr $($exprargs)*])*
- { $e }
- }
}