Skip to content

Commit

Permalink
Allows empty flag definition
Browse files Browse the repository at this point in the history
Fixes #179
  • Loading branch information
thiagoarrais committed Jan 12, 2021
1 parent c2ba431 commit 3e4d475
Showing 1 changed file with 89 additions and 29 deletions.
118 changes: 89 additions & 29 deletions src/lib.rs
Expand Up @@ -356,7 +356,7 @@ macro_rules! bitflags {
$(
$(#[$inner:ident $($args:tt)*])*
const $Flag:ident = $value:expr;
)+
)*
}
) => {
__bitflags! {
Expand All @@ -365,7 +365,7 @@ macro_rules! bitflags {
$(
$(#[$inner $($args)*])*
$Flag = $value;
)+
)*
}
}
};
Expand Down Expand Up @@ -399,7 +399,7 @@ macro_rules! __bitflags {
$(
$(#[$inner:ident $($args:tt)*])*
$Flag:ident = $value:expr;
)+
)*
}
) => {
$(#[$outer])*
Expand All @@ -413,7 +413,7 @@ macro_rules! __bitflags {
$(
$(#[$inner $($args)*])*
$Flag = $value;
)+
)*
}
}
};
Expand Down Expand Up @@ -475,14 +475,63 @@ macro_rules! __fn_bitflags {

#[macro_export(local_inner_macros)]
#[doc(hidden)]
macro_rules! __impl_bitflags {
macro_rules! __all_bitflags {
(
$BitFlags:ident: $T:ty {
$(
$(#[$attr:ident $($args:tt)*])*
$Flag:ident = $value:expr;
)+
}
) => {
__fn_bitflags! {
/// Returns the set containing all flags.
#[inline]
pub const fn all() -> $BitFlags {
// See `Debug::fmt` for why this approach is taken.
#[allow(non_snake_case)]
trait __BitFlags {
$(
const $Flag: $T = 0;
)+
}
impl __BitFlags for $BitFlags {
$(
__impl_bitflags! {
#[allow(deprecated)]
$(? #[$attr $($args)*])*
const $Flag: $T = Self::$Flag.bits;
}
)+
}
$BitFlags { bits: $(<$BitFlags as __BitFlags>::$Flag)|+ }
}
}
};
(
$BitFlags:ident: $T:ty {
}
) => {
__fn_bitflags! {
/// Returns the set containing all flags.
#[inline]
pub const fn all() -> $BitFlags {
$BitFlags { bits: 0 }
}
}
};
}

#[macro_export(local_inner_macros)]
#[doc(hidden)]
macro_rules! __impl_bitflags {
(
$BitFlags:ident: $T:ty {
$(
$(#[$attr:ident $($args:tt)*])*
$Flag:ident = $value:expr;
)*
}
) => {
impl $crate::_core::fmt::Debug for $BitFlags {
fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result {
Expand All @@ -499,7 +548,7 @@ macro_rules! __impl_bitflags {
$(
#[inline]
fn $Flag(&self) -> bool { false }
)+
)*
}

// Conditionally override the check for just those flags that
Expand All @@ -518,7 +567,7 @@ macro_rules! __impl_bitflags {
}
}
}
)+
)*
}

let mut first = true;
Expand All @@ -530,7 +579,7 @@ macro_rules! __impl_bitflags {
first = false;
f.write_str(__bitflags_stringify!($Flag))?;
}
)+
)*
let extra_bits = self.bits & !$BitFlags::all().bits();
if extra_bits != 0 {
if !first {
Expand Down Expand Up @@ -572,7 +621,7 @@ macro_rules! __impl_bitflags {
$(
$(#[$attr $($args)*])*
pub const $Flag: $BitFlags = $BitFlags { bits: $value };
)+
)*

__fn_bitflags! {
/// Returns an empty set of flags.
Expand All @@ -582,29 +631,14 @@ macro_rules! __impl_bitflags {
}
}

__fn_bitflags! {
/// Returns the set containing all flags.
#[inline]
pub const fn all() -> $BitFlags {
// See `Debug::fmt` for why this approach is taken.
#[allow(non_snake_case)]
trait __BitFlags {
__all_bitflags! {
$BitFlags: $T {
$(
const $Flag: $T = 0;
)+
$(#[$attr $($args)*])*
$Flag = $value;
)*
}
impl __BitFlags for $BitFlags {
$(
__impl_bitflags! {
#[allow(deprecated)]
$(? #[$attr $($args)*])*
const $Flag: $T = Self::$Flag.bits;
}
)+
}
$BitFlags { bits: $(<$BitFlags as __BitFlags>::$Flag)|+ }
}
}

__fn_bitflags! {
/// Returns the raw value of the flags currently stored.
Expand Down Expand Up @@ -983,6 +1017,11 @@ mod tests {
}
}

bitflags! {
struct EmptyFlags: u32 {
}
}

#[test]
fn test_bits() {
assert_eq!(Flags::empty().bits(), 0b00000000);
Expand All @@ -991,6 +1030,8 @@ mod tests {

assert_eq!(AnotherSetOfFlags::empty().bits(), 0b00);
assert_eq!(AnotherSetOfFlags::ANOTHER_FLAG.bits(), !0_i8);

assert_eq!(EmptyFlags::empty().bits(), 0b00000000);
}

#[test]
Expand All @@ -1005,6 +1046,9 @@ mod tests {
AnotherSetOfFlags::from_bits(!0_i8),
Some(AnotherSetOfFlags::ANOTHER_FLAG)
);

assert_eq!(EmptyFlags::from_bits(0), Some(EmptyFlags::empty()));
assert_eq!(EmptyFlags::from_bits(0b1), None);
}

#[test]
Expand All @@ -1020,6 +1064,9 @@ mod tests {
AnotherSetOfFlags::from_bits_truncate(0_i8),
AnotherSetOfFlags::empty()
);

assert_eq!(EmptyFlags::from_bits_truncate(0), EmptyFlags::empty());
assert_eq!(EmptyFlags::from_bits_truncate(0b1), EmptyFlags::empty());
}

#[test]
Expand All @@ -1031,6 +1078,9 @@ mod tests {
assert_eq!(unsafe { Flags::from_bits_unchecked(0b11) }, (Flags::A | Flags::B));
assert_eq!(unsafe { Flags::from_bits_unchecked(0b1000) }, (extra | Flags::empty()));
assert_eq!(unsafe { Flags::from_bits_unchecked(0b1001) }, (extra | Flags::A));

let extra = unsafe { EmptyFlags::from_bits_unchecked(0b1000) };
assert_eq!(unsafe { EmptyFlags::from_bits_unchecked(0b1000) }, (extra | EmptyFlags::empty()));
}

#[test]
Expand All @@ -1040,6 +1090,9 @@ mod tests {
assert!(!Flags::ABC.is_empty());

assert!(!AnotherSetOfFlags::ANOTHER_FLAG.is_empty());

assert!(EmptyFlags::empty().is_empty());
assert!(EmptyFlags::all().is_empty());
}

#[test]
Expand All @@ -1049,6 +1102,9 @@ mod tests {
assert!(Flags::ABC.is_all());

assert!(AnotherSetOfFlags::ANOTHER_FLAG.is_all());

assert!(EmptyFlags::all().is_all());
assert!(EmptyFlags::empty().is_all());
}

#[test]
Expand Down Expand Up @@ -1090,6 +1146,8 @@ mod tests {
assert!(Flags::ABC.contains(e2));

assert!(AnotherSetOfFlags::ANOTHER_FLAG.contains(AnotherSetOfFlags::ANOTHER_FLAG));

assert!(EmptyFlags::empty().contains(EmptyFlags::empty()));
}

#[test]
Expand Down Expand Up @@ -1277,6 +1335,8 @@ mod tests {
assert_eq!(format!("{:?}", extra), "0xb8");
assert_eq!(format!("{:?}", Flags::A | extra), "A | 0xb8");
assert_eq!(format!("{:?}", Flags::ABC | extra), "A | B | C | ABC | 0xb8");

assert_eq!(format!("{:?}", EmptyFlags::empty()), "(empty)");
}

#[test]
Expand Down

0 comments on commit 3e4d475

Please sign in to comment.