From f826921dfa677a730e1dbf8b88c42092532dbf16 Mon Sep 17 00:00:00 2001 From: Thiago Arrais Date: Thu, 1 Oct 2020 13:07:53 -0300 Subject: [PATCH] Allows empty flag definition Fixes #179 --- src/lib.rs | 118 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 89 insertions(+), 29 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 55daa5ea..8b300ef2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -356,7 +356,7 @@ macro_rules! bitflags { $( $(#[$inner:ident $($args:tt)*])* const $Flag:ident = $value:expr; - )+ + )* } ) => { __bitflags! { @@ -365,7 +365,7 @@ macro_rules! bitflags { $( $(#[$inner $($args)*])* $Flag = $value; - )+ + )* } } }; @@ -399,7 +399,7 @@ macro_rules! __bitflags { $( $(#[$inner:ident $($args:tt)*])* $Flag:ident = $value:expr; - )+ + )* } ) => { $(#[$outer])* @@ -413,7 +413,7 @@ macro_rules! __bitflags { $( $(#[$inner $($args)*])* $Flag = $value; - )+ + )* } } }; @@ -475,7 +475,7 @@ macro_rules! __fn_bitflags { #[macro_export(local_inner_macros)] #[doc(hidden)] -macro_rules! __impl_bitflags { +macro_rules! __all_bitflags { ( $BitFlags:ident: $T:ty { $( @@ -483,6 +483,55 @@ macro_rules! __impl_bitflags { $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 { @@ -499,7 +548,7 @@ macro_rules! __impl_bitflags { $( #[inline] fn $Flag(&self) -> bool { false } - )+ + )* } // Conditionally override the check for just those flags that @@ -518,7 +567,7 @@ macro_rules! __impl_bitflags { } } } - )+ + )* } let mut first = true; @@ -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 { @@ -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. @@ -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. @@ -983,6 +1017,11 @@ mod tests { } } + bitflags! { + struct EmptyFlags: u32 { + } + } + #[test] fn test_bits() { assert_eq!(Flags::empty().bits(), 0b00000000); @@ -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] @@ -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] @@ -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] @@ -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] @@ -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] @@ -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] @@ -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] @@ -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]