From 0bc00187c28ce521d978ccaf36f389818e7ef153 Mon Sep 17 00:00:00 2001 From: KodrAus Date: Thu, 6 Oct 2022 06:59:05 +0200 Subject: [PATCH 1/6] expose bitflags iters using nameable types --- src/bitflags_trait.rs | 19 +- src/lib.rs | 274 ++++++++++++++--------- src/serde_support.rs | 21 +- tests/compile-pass/trait/wrapped_iter.rs | 22 ++ 4 files changed, 220 insertions(+), 116 deletions(-) create mode 100644 tests/compile-pass/trait/wrapped_iter.rs diff --git a/src/bitflags_trait.rs b/src/bitflags_trait.rs index fd0a913a..010b8e38 100644 --- a/src/bitflags_trait.rs +++ b/src/bitflags_trait.rs @@ -4,7 +4,12 @@ use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, /// /// It should not be implemented manually. pub trait BitFlags: ImplementedByBitFlagsMacro { + /// The underlying integer type. type Bits: Bits; + /// 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 IterRaw: Iterator; /// Returns an empty set of flags. fn empty() -> Self; @@ -23,6 +28,8 @@ pub trait BitFlags: ImplementedByBitFlagsMacro { /// Convert from underlying bit representation, preserving all /// bits (even those not corresponding to a defined flag). fn from_bits_retain(bits: Self::Bits) -> Self; + fn iter(&self) -> Self::Iter; + fn iter_raw(&self) -> Self::IterRaw; /// Returns `true` if no flags are currently stored. fn is_empty(&self) -> bool; /// Returns `true` if all flags are currently set. @@ -109,10 +116,20 @@ impl_bits! { u128, i128, } +/// A marker trait for referencing the `bitflags`-owned internal type +/// without exposing it publicly. pub trait PublicFlags { type InternalFlags; } -pub trait InternalFlags { +/// A marker trait for referencing the end-user-owned type generically. +pub trait InternalFlags: InternalIter { type PublicFlags; } + +/// A marker trait for referencing the `bitflags`-owned internal iterator +/// types without exposing them publicly. +pub trait InternalIter { + type Iter; + type IterRaw; +} diff --git a/src/lib.rs b/src/lib.rs index fefac414..08f96cbe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -279,7 +279,9 @@ mod bitflags_trait; #[doc(hidden)] pub mod __private { - pub use crate::bitflags_trait::{Bits, ImplementedByBitFlagsMacro, InternalFlags, PublicFlags}; + pub use crate::bitflags_trait::{ + Bits, ImplementedByBitFlagsMacro, InternalFlags, InternalIter, PublicFlags, + }; pub use core; #[cfg(feature = "serde")] @@ -410,22 +412,39 @@ macro_rules! bitflags { $(#[$outer])* $vis struct $BitFlags(<$BitFlags as $crate::__private::PublicFlags>::InternalFlags); - __impl_public_bitflags! { - $BitFlags: $T { - $( - $(#[$inner $($args)*])* - $Flag = $value; - )* + #[allow( + dead_code, + deprecated, + unused_doc_comments, + unused_attributes, + unused_mut, + unused_imports, + non_upper_case_globals + )] + const _: () = { + __impl_public_bitflags! { + $BitFlags: $T { + $( + $(#[$inner $($args)*])* + $Flag = $value; + )* + } } - } - const _: () = { #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] $vis struct InternalFlags { bits: $T, } + $vis struct Iter(IterRaw); + + $vis struct IterRaw { + idx: usize, + source: InternalFlags, + state: InternalFlags, + } + __impl_internal_bitflags! { InternalFlags: $T { $( @@ -439,6 +458,11 @@ macro_rules! bitflags { type PublicFlags = $BitFlags; } + impl $crate::__private::InternalIter for InternalFlags { + type Iter = Iter; + type IterRaw = IterRaw; + } + impl $crate::__private::PublicFlags for $BitFlags { type InternalFlags = InternalFlags; } @@ -490,14 +514,6 @@ macro_rules! __impl_public_bitflags { } } - #[allow( - dead_code, - deprecated, - unused_doc_comments, - unused_attributes, - unused_mut, - non_upper_case_globals - )] impl $PublicBitFlags { $( $(#[$attr $($args)*])* @@ -507,13 +523,13 @@ macro_rules! __impl_public_bitflags { /// Returns an empty set of flags. #[inline] pub const fn empty() -> Self { - Self(<$PublicBitFlags as $crate::__private::PublicFlags>::InternalFlags::empty()) + Self(::InternalFlags::empty()) } /// Returns the set containing all flags. #[inline] pub const fn all() -> Self { - Self(<$PublicBitFlags as $crate::__private::PublicFlags>::InternalFlags::all()) + Self(::InternalFlags::all()) } /// Returns the raw value of the flags currently stored. @@ -526,7 +542,7 @@ macro_rules! __impl_public_bitflags { /// representation contains bits that do not correspond to a flag. #[inline] pub const fn from_bits(bits: $T) -> $crate::__private::core::option::Option { - match <$PublicBitFlags as $crate::__private::PublicFlags>::InternalFlags::from_bits(bits) { + match ::InternalFlags::from_bits(bits) { $crate::__private::core::option::Option::Some(bits) => $crate::__private::core::option::Option::Some(Self(bits)), $crate::__private::core::option::Option::None => $crate::__private::core::option::Option::None, } @@ -536,7 +552,7 @@ macro_rules! __impl_public_bitflags { /// that do not correspond to flags. #[inline] pub const fn from_bits_truncate(bits: $T) -> Self { - Self(<$PublicBitFlags as $crate::__private::PublicFlags>::InternalFlags::from_bits_truncate(bits)) + Self(::InternalFlags::from_bits_truncate(bits)) } /// Convert from underlying bit representation, preserving all @@ -552,7 +568,19 @@ macro_rules! __impl_public_bitflags { /// are valid for this bitflags type. #[inline] pub const fn from_bits_retain(bits: $T) -> Self { - Self(<$PublicBitFlags as $crate::__private::PublicFlags>::InternalFlags::from_bits_retain(bits)) + Self(::InternalFlags::from_bits_retain(bits)) + } + + /// Iterate over enabled flag values. + #[inline] + pub const fn iter(&self) -> <::InternalFlags as $crate::__private::InternalIter>::Iter { + self.0.iter() + } + + /// Iterate over the raw names and bits for enabled flag values. + #[inline] + pub const fn iter_raw(&self) -> <::InternalFlags as $crate::__private::InternalIter>::IterRaw { + self.0.iter_raw() } /// Returns `true` if no flags are currently stored. @@ -691,14 +719,6 @@ macro_rules! __impl_public_bitflags { pub const fn complement(self) -> Self { Self(self.0.complement()) } - - /// Returns an iterator over set flags and their names. - pub fn iter(self) -> impl $crate::__private::core::iter::Iterator { - use $crate::__private::core::iter::Iterator as _; - - self.0.iter().map(|(name, bits)| (name, Self::from_bits_retain(bits))) - } - } impl $crate::__private::core::ops::BitOr for $PublicBitFlags { @@ -801,9 +821,21 @@ macro_rules! __impl_public_bitflags { } } + impl $crate::__private::core::iter::IntoIterator for $PublicBitFlags { + type Item = Self; + type IntoIter = <::InternalFlags as $crate::__private::InternalIter>::Iter; + + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } + } + impl $crate::BitFlags for $PublicBitFlags { type Bits = $T; + type Iter = <::InternalFlags as $crate::__private::InternalIter>::Iter; + type IterRaw = <::InternalFlags as $crate::__private::InternalIter>::IterRaw; + fn empty() -> Self { $PublicBitFlags::empty() } @@ -828,6 +860,14 @@ macro_rules! __impl_public_bitflags { $PublicBitFlags::from_bits_retain(bits) } + fn iter(&self) -> Self::Iter { + $PublicBitFlags::iter(self) + } + + fn iter_raw(&self) -> Self::IterRaw { + $PublicBitFlags::iter_raw(self) + } + fn is_empty(&self) -> bool { $PublicBitFlags::is_empty(self) } @@ -901,7 +941,7 @@ macro_rules! __impl_internal_bitflags { fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result { // Iterate over the valid flags let mut first = true; - for (name, _) in self.iter() { + for (name, _) in self.iter_raw() { if !first { f.write_str(" | ")?; } @@ -953,14 +993,6 @@ macro_rules! __impl_internal_bitflags { } } - #[allow( - dead_code, - deprecated, - unused_doc_comments, - unused_attributes, - unused_mut, - non_upper_case_globals - )] impl $InternalBitFlags { #[inline] pub const fn empty() -> Self { @@ -1016,6 +1048,20 @@ macro_rules! __impl_internal_bitflags { Self { bits } } + #[inline] + pub const fn iter(&self) -> Iter { + Iter(self.iter_raw()) + } + + #[inline] + pub const fn iter_raw(&self) -> IterRaw { + IterRaw { + idx: 0, + source: *self, + state: *self, + } + } + #[inline] pub const fn is_empty(&self) -> bool { self.bits == Self::empty().bits @@ -1089,8 +1135,20 @@ macro_rules! __impl_internal_bitflags { pub const fn complement(self) -> Self { Self::from_bits_truncate(!self.bits) } + } - pub fn iter(self) -> impl $crate::__private::core::iter::Iterator { + impl $crate::__private::core::iter::Iterator for Iter { + type Item = <$InternalBitFlags as $crate::__private::InternalFlags>::PublicFlags; + + fn next(&mut self) -> $crate::__private::core::option::Option { + self.0.next().map(|(_, value)| <$InternalBitFlags as $crate::__private::InternalFlags>::PublicFlags::from_bits_retain(value)) + } + } + + impl $crate::__private::core::iter::Iterator for IterRaw { + type Item = (&'static str, $T); + + fn next(&mut self) -> $crate::__private::core::option::Option { use $crate::__private::core::iter::Iterator as _; const NUM_FLAGS: usize = { @@ -1120,38 +1178,33 @@ macro_rules! __impl_internal_bitflags { )* ]; - let mut start = 0; - let mut state = self; - - $crate::__private::core::iter::from_fn(move || { - if state.is_empty() || NUM_FLAGS == 0 { - $crate::__private::core::option::Option::None - } else { - for (flag, flag_name) in OPTIONS[start..NUM_FLAGS].iter().copied() - .zip(OPTIONS_NAMES[start..NUM_FLAGS].iter().copied()) - { - start += 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.contains(Self { bits: flag }) { - state.remove(Self { bits: flag }); - - return $crate::__private::core::option::Option::Some((flag_name, flag)) - } + if self.state.is_empty() || NUM_FLAGS == 0 { + $crate::__private::core::option::Option::None + } else { + 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, flag)) } - - $crate::__private::core::option::Option::None } - }) + + $crate::__private::core::option::Option::None + } } } }; @@ -1181,19 +1234,33 @@ macro_rules! __impl_internal_bitflags_serde { } ) => { impl $crate::__private::serde::Serialize for $InternalBitFlags { - fn serialize(&self, serializer: S) -> $crate::__private::core::result::Result { - $crate::serde_support::serialize_bits_default($crate::__private::core::stringify!($InternalBitFlags), &self.bits, serializer) + fn serialize( + &self, + serializer: S, + ) -> $crate::__private::core::result::Result { + $crate::serde_support::serialize_bits_default( + $crate::__private::core::stringify!($InternalBitFlags), + &self.bits, + serializer, + ) } } impl<'de> $crate::__private::serde::Deserialize<'de> for $InternalBitFlags { - fn deserialize>(deserializer: D) -> $crate::__private::core::result::Result { - let bits = $crate::serde_support::deserialize_bits_default($crate::__private::core::stringify!($InternalBitFlags), deserializer)?; - - $crate::__private::core::result::Result::Ok($InternalBitFlags::from_bits_retain(bits)) + fn deserialize>( + deserializer: D, + ) -> $crate::__private::core::result::Result { + let bits = $crate::serde_support::deserialize_bits_default( + $crate::__private::core::stringify!($InternalBitFlags), + deserializer, + )?; + + $crate::__private::core::result::Result::Ok($InternalBitFlags::from_bits_retain( + bits, + )) } } - } + }; } #[macro_export(local_inner_macros)] @@ -1207,7 +1274,7 @@ macro_rules! __impl_internal_bitflags_serde { $Flag:ident; )* } - ) => { } + ) => {}; } #[cfg(feature = "example_generated")] @@ -1319,18 +1386,9 @@ mod tests { assert_eq!(Flags::from_bits_retain(0b1), Flags::A); assert_eq!(Flags::from_bits_retain(0b10), Flags::B); - assert_eq!( - Flags::from_bits_retain(0b11), - (Flags::A | Flags::B) - ); - assert_eq!( - Flags::from_bits_retain(0b1000), - (extra | Flags::empty()) - ); - assert_eq!( - Flags::from_bits_retain(0b1001), - (extra | Flags::A) - ); + assert_eq!(Flags::from_bits_retain(0b11), (Flags::A | Flags::B)); + assert_eq!(Flags::from_bits_retain(0b1000), (extra | Flags::empty())); + assert_eq!(Flags::from_bits_retain(0b1001), (extra | Flags::A)); let extra = EmptyFlags::from_bits_retain(0b1000); assert_eq!( @@ -1564,8 +1622,7 @@ mod tests { const I = 0b100000000; } } - let iter_test_flags = - || (0..=0b111_1111_1111).map(|bits| Test::from_bits_retain(bits)); + let iter_test_flags = || (0..=0b111_1111_1111).map(|bits| Test::from_bits_retain(bits)); for a in iter_test_flags() { assert_eq!( @@ -1981,10 +2038,7 @@ mod tests { assert_eq!(Flags::A.bits(), 0x0000_0000_0000_0000_0000_0000_0000_0001); assert_eq!(Flags::B.bits(), 0x0000_0000_0000_1000_0000_0000_0000_0000); assert_eq!(Flags::C.bits(), 0x8000_0000_0000_0000_0000_0000_0000_0000); - assert_eq!( - Flags::ABC.bits(), - 0x8000_0000_0000_1000_0000_0000_0000_0001 - ); + assert_eq!(Flags::ABC.bits(), 0x8000_0000_0000_1000_0000_0000_0000_0001); assert_eq!(format!("{:?}", Flags::A), "Flags(A)"); assert_eq!(format!("{:?}", Flags::B), "Flags(B)"); assert_eq!(format!("{:?}", Flags::C), "Flags(C)"); @@ -2052,41 +2106,41 @@ mod tests { }; let flags = Flags::all(); - assert_eq!(flags.iter().count(), count); + assert_eq!(flags.into_iter().count(), count); - for (_, flag) in flags.iter() { + for flag in flags.into_iter() { assert!(flags.contains(flag)); } - let mut iter = flags.iter(); + let mut iter = flags.iter_raw(); - assert_eq!(iter.next().unwrap(), ("ONE", Flags::ONE)); - assert_eq!(iter.next().unwrap(), ("TWO", Flags::TWO)); - assert_eq!(iter.next().unwrap(), ("THREE", Flags::THREE)); + assert_eq!(iter.next().unwrap(), ("ONE", Flags::ONE.bits())); + assert_eq!(iter.next().unwrap(), ("TWO", Flags::TWO.bits())); + assert_eq!(iter.next().unwrap(), ("THREE", Flags::THREE.bits())); #[cfg(unix)] { - assert_eq!(iter.next().unwrap(), ("FOUR_UNIX", Flags::FOUR_UNIX)); + assert_eq!(iter.next().unwrap(), ("FOUR_UNIX", Flags::FOUR_UNIX.bits())); } #[cfg(windows)] { - assert_eq!(iter.next().unwrap(), ("FOUR_WIN", Flags::FOUR_WIN)); + assert_eq!(iter.next().unwrap(), ("FOUR_WIN", Flags::FOUR_WIN.bits())); } - assert_eq!(iter.next().unwrap(), ("FIVE", Flags::FIVE)); + assert_eq!(iter.next().unwrap(), ("FIVE", Flags::FIVE.bits())); assert_eq!(iter.next(), None); let flags = Flags::empty(); - assert_eq!(flags.iter().count(), 0); + assert_eq!(flags.into_iter().count(), 0); let flags = Flags::ONE | Flags::THREE; - assert_eq!(flags.iter().count(), 2); + assert_eq!(flags.into_iter().count(), 2); - let mut iter = flags.iter(); + let mut iter = flags.iter_raw(); - assert_eq!(iter.next().unwrap(), ("ONE", Flags::ONE)); - assert_eq!(iter.next().unwrap(), ("THREE", Flags::THREE)); + assert_eq!(iter.next().unwrap(), ("ONE", Flags::ONE.bits())); + assert_eq!(iter.next().unwrap(), ("THREE", Flags::THREE.bits())); assert_eq!(iter.next(), None); } } diff --git a/src/serde_support.rs b/src/serde_support.rs index 41cf1128..5d30d1c3 100644 --- a/src/serde_support.rs +++ b/src/serde_support.rs @@ -1,15 +1,26 @@ use core::fmt; -use serde::{Serializer, Deserializer, Serialize, Deserialize, ser::SerializeStruct, de::{Error, MapAccess, Visitor}}; +use serde::{ + de::{Error, MapAccess, Visitor}, + ser::SerializeStruct, + Deserialize, Deserializer, Serialize, Serializer, +}; // These methods are compatible with the result of `#[derive(Serialize, Deserialize)]` on bitflags `1.0` types -pub fn serialize_bits_default(name: &'static str, bits: &B, serializer: S) -> Result { +pub fn serialize_bits_default( + name: &'static str, + bits: &B, + serializer: S, +) -> Result { let mut serialize_struct = serializer.serialize_struct(name, 1)?; serialize_struct.serialize_field("bits", bits)?; serialize_struct.end() } -pub fn deserialize_bits_default<'de, B: Deserialize<'de>, D: Deserializer<'de>>(name: &'static str, deserializer: D) -> Result { +pub fn deserialize_bits_default<'de, B: Deserialize<'de>, D: Deserializer<'de>>( + name: &'static str, + deserializer: D, +) -> Result { struct BitsVisitor(core::marker::PhantomData); impl<'de, T: Deserialize<'de>> Visitor<'de> for BitsVisitor { @@ -31,7 +42,7 @@ pub fn deserialize_bits_default<'de, B: Deserialize<'de>, D: Deserializer<'de>>( bits = Some(map.next_value()?); } - v => return Err(Error::unknown_field(v, &["bits"])) + v => return Err(Error::unknown_field(v, &["bits"])), } } @@ -81,4 +92,4 @@ mod tests { assert_eq!(deserialized.bits(), flags.bits()); } -} \ No newline at end of file +} diff --git a/tests/compile-pass/trait/wrapped_iter.rs b/tests/compile-pass/trait/wrapped_iter.rs new file mode 100644 index 00000000..3146d591 --- /dev/null +++ b/tests/compile-pass/trait/wrapped_iter.rs @@ -0,0 +1,22 @@ +#[macro_use] +extern crate bitflags; + +bitflags! { + struct Flags: u32 { + const A = 0b00000001; + } +} + +pub struct WrappedIter(::IntoIter); + +impl Iterator for WrappedIter { + type Item = u32; + + fn next(&mut self) -> Option { + self.0.next().map(|flag| flag.bits()) + } +} + +fn main() { + assert_eq!(1, WrappedIter(Flags::A.into_iter()).count()); +} From 5a817d947740e08593884035028719944e4cdf06 Mon Sep 17 00:00:00 2001 From: KodrAus Date: Thu, 6 Oct 2022 07:21:43 +0200 Subject: [PATCH 2/6] fix up example generated --- src/example_generated.rs | 31 ++++++++++++++++++++++++++++++- src/lib.rs | 38 ++++++++++++++++++++++++-------------- 2 files changed, 54 insertions(+), 15 deletions(-) diff --git a/src/example_generated.rs b/src/example_generated.rs index 18985c75..9a2fab30 100644 --- a/src/example_generated.rs +++ b/src/example_generated.rs @@ -29,8 +29,32 @@ pub struct FlagsField { bits: u32, } +pub struct FlagsIter(FlagsIterRaw); + +impl FlagsIter { + const fn new(flags: &FlagsField) -> Self { + FlagsIter(flags.iter_raw()) + } +} + +pub struct FlagsIterRaw { + idx: usize, + source: FlagsField, + state: FlagsField, +} + +impl FlagsIterRaw { + const fn new(flags: &FlagsField) -> Self { + FlagsIterRaw { + idx: 0, + source: *flags, + state: *flags, + } + } +} + __impl_internal_bitflags! { - FlagsField: u32 { + FlagsField: u32, FlagsIter, FlagsIterRaw { A; B; C; @@ -41,3 +65,8 @@ __impl_internal_bitflags! { impl crate::__private::InternalFlags for FlagsField { type PublicFlags = Flags; } + +impl crate::__private::InternalIter for FlagsField { + type Iter = FlagsIter; + type IterRaw = FlagsIterRaw; +} diff --git a/src/lib.rs b/src/lib.rs index 08f96cbe..19614af9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -445,8 +445,24 @@ macro_rules! bitflags { state: InternalFlags, } + impl Iter { + const fn new(flags: &InternalFlags) -> Self { + Iter(flags.iter_raw()) + } + } + + impl IterRaw { + const fn new(flags: &InternalFlags) -> Self { + IterRaw { + idx: 0, + source: *flags, + state: *flags, + } + } + } + __impl_internal_bitflags! { - InternalFlags: $T { + InternalFlags: $T, Iter, IterRaw { $( $(#[$inner $($args)*])* $Flag; @@ -913,7 +929,7 @@ macro_rules! __impl_public_bitflags { #[doc(hidden)] macro_rules! __impl_internal_bitflags { ( - $InternalBitFlags:ident: $T:ty { + $InternalBitFlags:ident: $T:ty, $Iter:ty, $IterRaw:ty { $( $(#[$attr:ident $($args:tt)*])* $Flag:ident; @@ -1049,17 +1065,13 @@ macro_rules! __impl_internal_bitflags { } #[inline] - pub const fn iter(&self) -> Iter { - Iter(self.iter_raw()) + pub const fn iter(&self) -> $Iter { + <$Iter>::new(self) } #[inline] - pub const fn iter_raw(&self) -> IterRaw { - IterRaw { - idx: 0, - source: *self, - state: *self, - } + pub const fn iter_raw(&self) -> $IterRaw { + <$IterRaw>::new(self) } #[inline] @@ -1137,7 +1149,7 @@ macro_rules! __impl_internal_bitflags { } } - impl $crate::__private::core::iter::Iterator for Iter { + impl $crate::__private::core::iter::Iterator for $Iter { type Item = <$InternalBitFlags as $crate::__private::InternalFlags>::PublicFlags; fn next(&mut self) -> $crate::__private::core::option::Option { @@ -1145,12 +1157,10 @@ macro_rules! __impl_internal_bitflags { } } - impl $crate::__private::core::iter::Iterator for IterRaw { + impl $crate::__private::core::iter::Iterator for $IterRaw { type Item = (&'static str, $T); fn next(&mut self) -> $crate::__private::core::option::Option { - use $crate::__private::core::iter::Iterator as _; - const NUM_FLAGS: usize = { let mut num_flags = 0; From f6a040797ac8309e2cdd1995918de5085aaccd5c Mon Sep 17 00:00:00 2001 From: KodrAus Date: Thu, 6 Oct 2022 13:19:51 +0200 Subject: [PATCH 3/6] simplify bridging code between public and private APIs --- src/bitflags_trait.rs | 16 +--- src/lib.rs | 171 +++++++++++++++++++++++------------------- 2 files changed, 95 insertions(+), 92 deletions(-) diff --git a/src/bitflags_trait.rs b/src/bitflags_trait.rs index 010b8e38..8ea615fd 100644 --- a/src/bitflags_trait.rs +++ b/src/bitflags_trait.rs @@ -116,20 +116,8 @@ impl_bits! { u128, i128, } -/// A marker trait for referencing the `bitflags`-owned internal type +/// A trait for referencing the `bitflags`-owned internal type /// without exposing it publicly. pub trait PublicFlags { - type InternalFlags; -} - -/// A marker trait for referencing the end-user-owned type generically. -pub trait InternalFlags: InternalIter { - type PublicFlags; -} - -/// A marker trait for referencing the `bitflags`-owned internal iterator -/// types without exposing them publicly. -pub trait InternalIter { - type Iter; - type IterRaw; + type Internal; } diff --git a/src/lib.rs b/src/lib.rs index 19614af9..ba78411e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -280,8 +280,9 @@ mod bitflags_trait; #[doc(hidden)] pub mod __private { pub use crate::bitflags_trait::{ - Bits, ImplementedByBitFlagsMacro, InternalFlags, InternalIter, PublicFlags, + Bits, ImplementedByBitFlagsMacro, PublicFlags, }; + pub use core; #[cfg(feature = "serde")] @@ -321,11 +322,7 @@ const _: () = { } impl PublicFlags for MyFlags { - type InternalFlags = InternalFlags; - } - - impl InternalFlags for MyInternalFlags { - type PublicFlags = MyFlags; + type Internal = InternalFlags; } }; ``` @@ -333,8 +330,8 @@ const _: () = { If we want to expose something like a new trait impl for generated flags types, we add it to our generated `MyInternalFlags`, and let `#[derive]` on `MyFlags` pick up that implementation, if an end-user chooses to add one. -The public API is generated in the `__impl_bitflags_public!` macro, and the internal API is generated in -the `__impl_bitflags_internal!` macro. +The public API is generated in the `__impl_public_flags!` macro, and the internal API is generated in +the `__impl_internal_flags!` macro. */ /// The macro used to generate the flag structure. @@ -409,8 +406,10 @@ macro_rules! bitflags { $($t:tt)* ) => { - $(#[$outer])* - $vis struct $BitFlags(<$BitFlags as $crate::__private::PublicFlags>::InternalFlags); + __declare_public_bitflags! { + $(#[$outer])* + $vis struct $BitFlags; + } #[allow( dead_code, @@ -422,47 +421,15 @@ macro_rules! bitflags { non_upper_case_globals )] const _: () = { - __impl_public_bitflags! { - $BitFlags: $T { - $( - $(#[$inner $($args)*])* - $Flag = $value; - )* - } - } - - #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] - #[repr(transparent)] - $vis struct InternalFlags { - bits: $T, - } - - $vis struct Iter(IterRaw); - - $vis struct IterRaw { - idx: usize, - source: InternalFlags, - state: InternalFlags, - } - - impl Iter { - const fn new(flags: &InternalFlags) -> Self { - Iter(flags.iter_raw()) - } - } - - impl IterRaw { - const fn new(flags: &InternalFlags) -> Self { - IterRaw { - idx: 0, - source: *flags, - state: *flags, - } - } + __declare_internal_bitflags! { + $vis struct InternalFlags: $T; + $vis struct Iter; + $vis struct IterRaw; } + // This macro definition is where `derives` for other libraries can be added __impl_internal_bitflags! { - InternalFlags: $T, Iter, IterRaw { + InternalFlags: $T, $BitFlags, Iter, IterRaw { $( $(#[$inner $($args)*])* $Flag; @@ -470,17 +437,13 @@ macro_rules! bitflags { } } - impl $crate::__private::InternalFlags for InternalFlags { - type PublicFlags = $BitFlags; - } - - impl $crate::__private::InternalIter for InternalFlags { - type Iter = Iter; - type IterRaw = IterRaw; - } - - impl $crate::__private::PublicFlags for $BitFlags { - type InternalFlags = InternalFlags; + __impl_public_bitflags! { + $BitFlags: $T, InternalFlags, Iter, IterRaw { + $( + $(#[$inner $($args)*])* + $Flag = $value; + )* + } } }; @@ -491,6 +454,48 @@ macro_rules! bitflags { () => {}; } +/// Declare the user-facing bitflags struct. +/// +/// This type is guaranteed to be a newtype with a `bitflags`-facing type as its single field. +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __declare_public_bitflags { + ( + $(#[$outer:meta])* + $vis:vis struct $BitFlags:ident; + ) => { + $(#[$outer])* + $vis struct $BitFlags(::Internal); + }; +} + +/// Declare the `bitflags`-facing bitflags struct. +/// +/// This type is part of the `bitflags` crate's public API, but not part of the user's. +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __declare_internal_bitflags { + ( + $vis:vis struct $InternalBitFlags:ident: $T:ty; + $iter_vis:vis struct $Iter:ident; + $iter_raw_vis:vis struct $IterRaw:ident; + ) => { + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + #[repr(transparent)] + $vis struct $InternalBitFlags { + bits: $T, + } + + $iter_vis struct $Iter($IterRaw); + + $iter_raw_vis struct $IterRaw { + idx: usize, + source: $InternalBitFlags, + state: $InternalBitFlags, + } + }; +} + /// Implement functions on the public (user-facing) bitflags type. /// /// We need to be careful about adding new methods and trait implementations here because they @@ -499,7 +504,7 @@ macro_rules! bitflags { #[doc(hidden)] macro_rules! __impl_public_bitflags { ( - $PublicBitFlags:ident: $T:ty { + $PublicBitFlags:ident: $T:ty, $InternalBitFlags:ident, $Iter:ident, $IterRaw:ident { $( $(#[$attr:ident $($args:tt)*])* $Flag:ident = $value:expr; @@ -539,13 +544,13 @@ macro_rules! __impl_public_bitflags { /// Returns an empty set of flags. #[inline] pub const fn empty() -> Self { - Self(::InternalFlags::empty()) + Self($InternalBitFlags::empty()) } /// Returns the set containing all flags. #[inline] pub const fn all() -> Self { - Self(::InternalFlags::all()) + Self($InternalBitFlags::all()) } /// Returns the raw value of the flags currently stored. @@ -558,7 +563,7 @@ macro_rules! __impl_public_bitflags { /// representation contains bits that do not correspond to a flag. #[inline] pub const fn from_bits(bits: $T) -> $crate::__private::core::option::Option { - match ::InternalFlags::from_bits(bits) { + match $InternalBitFlags::from_bits(bits) { $crate::__private::core::option::Option::Some(bits) => $crate::__private::core::option::Option::Some(Self(bits)), $crate::__private::core::option::Option::None => $crate::__private::core::option::Option::None, } @@ -568,7 +573,7 @@ macro_rules! __impl_public_bitflags { /// that do not correspond to flags. #[inline] pub const fn from_bits_truncate(bits: $T) -> Self { - Self(::InternalFlags::from_bits_truncate(bits)) + Self($InternalBitFlags::from_bits_truncate(bits)) } /// Convert from underlying bit representation, preserving all @@ -584,18 +589,18 @@ macro_rules! __impl_public_bitflags { /// are valid for this bitflags type. #[inline] pub const fn from_bits_retain(bits: $T) -> Self { - Self(::InternalFlags::from_bits_retain(bits)) + Self($InternalBitFlags::from_bits_retain(bits)) } /// Iterate over enabled flag values. #[inline] - pub const fn iter(&self) -> <::InternalFlags as $crate::__private::InternalIter>::Iter { + pub const fn iter(&self) -> $Iter { self.0.iter() } /// Iterate over the raw names and bits for enabled flag values. #[inline] - pub const fn iter_raw(&self) -> <::InternalFlags as $crate::__private::InternalIter>::IterRaw { + pub const fn iter_raw(&self) -> $IterRaw { self.0.iter_raw() } @@ -839,7 +844,7 @@ macro_rules! __impl_public_bitflags { impl $crate::__private::core::iter::IntoIterator for $PublicBitFlags { type Item = Self; - type IntoIter = <::InternalFlags as $crate::__private::InternalIter>::Iter; + type IntoIter = $Iter; fn into_iter(self) -> Self::IntoIter { self.0.iter() @@ -849,8 +854,8 @@ macro_rules! __impl_public_bitflags { impl $crate::BitFlags for $PublicBitFlags { type Bits = $T; - type Iter = <::InternalFlags as $crate::__private::InternalIter>::Iter; - type IterRaw = <::InternalFlags as $crate::__private::InternalIter>::IterRaw; + type Iter = $Iter; + type IterRaw = $IterRaw; fn empty() -> Self { $PublicBitFlags::empty() @@ -929,7 +934,7 @@ macro_rules! __impl_public_bitflags { #[doc(hidden)] macro_rules! __impl_internal_bitflags { ( - $InternalBitFlags:ident: $T:ty, $Iter:ty, $IterRaw:ty { + $InternalBitFlags:ident: $T:ty, $BitFlags:ident, $Iter:ident, $IterRaw:ident { $( $(#[$attr:ident $($args:tt)*])* $Flag:ident; @@ -937,6 +942,8 @@ macro_rules! __impl_internal_bitflags { } ) => { // Any new library traits impls should be added here + // Use `serde` as an example: generate code when the feature is available, + // and a no-op when it isn't __impl_internal_bitflags_serde! { $InternalBitFlags: $T { $( @@ -946,6 +953,10 @@ macro_rules! __impl_internal_bitflags { } } + impl $crate::__private::PublicFlags for $BitFlags { + type Internal = $InternalBitFlags; + } + impl $crate::__private::core::default::Default for $InternalBitFlags { #[inline] fn default() -> Self { @@ -1051,8 +1062,8 @@ macro_rules! __impl_internal_bitflags { $( $(#[$attr $($args)*])* - if bits & <$InternalBitFlags as $crate::__private::InternalFlags>::PublicFlags::$Flag.bits() == <$InternalBitFlags as $crate::__private::InternalFlags>::PublicFlags::$Flag.bits() { - truncated |= <$InternalBitFlags as $crate::__private::InternalFlags>::PublicFlags::$Flag.bits() + if bits & $BitFlags::$Flag.bits() == $BitFlags::$Flag.bits() { + truncated |= $BitFlags::$Flag.bits() } )* @@ -1066,12 +1077,16 @@ macro_rules! __impl_internal_bitflags { #[inline] pub const fn iter(&self) -> $Iter { - <$Iter>::new(self) + $Iter(self.iter_raw()) } #[inline] pub const fn iter_raw(&self) -> $IterRaw { - <$IterRaw>::new(self) + $IterRaw { + idx: 0, + source: *self, + state: *self, + } } #[inline] @@ -1150,10 +1165,10 @@ macro_rules! __impl_internal_bitflags { } impl $crate::__private::core::iter::Iterator for $Iter { - type Item = <$InternalBitFlags as $crate::__private::InternalFlags>::PublicFlags; + type Item = $BitFlags; fn next(&mut self) -> $crate::__private::core::option::Option { - self.0.next().map(|(_, value)| <$InternalBitFlags as $crate::__private::InternalFlags>::PublicFlags::from_bits_retain(value)) + self.0.next().map(|(_, value)| $BitFlags::from_bits_retain(value)) } } @@ -1177,7 +1192,7 @@ macro_rules! __impl_internal_bitflags { const OPTIONS: [$T; NUM_FLAGS] = [ $( $(#[$attr $($args)*])* - <$InternalBitFlags as $crate::__private::InternalFlags>::PublicFlags::$Flag.bits(), + $BitFlags::$Flag.bits(), )* ]; From 54d43df1a5f77d1702bee5c0e796107de8d6e666 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Fri, 7 Oct 2022 01:08:12 +1000 Subject: [PATCH 4/6] split the macros into modules --- src/example_generated.rs | 71 +- src/external.rs | 88 ++ src/{ => external}/serde_support.rs | 0 src/internal.rs | 328 +++++++ src/lib.rs | 1025 +++------------------- src/public.rs | 449 ++++++++++ src/{bitflags_trait.rs => traits.rs} | 20 + tests/compile-pass/path_based_bits.rs | 14 + tests/compile-pass/trait/generic_iter.rs | 16 + 9 files changed, 1059 insertions(+), 952 deletions(-) create mode 100644 src/external.rs rename src/{ => external}/serde_support.rs (100%) create mode 100644 src/internal.rs create mode 100644 src/public.rs rename src/{bitflags_trait.rs => traits.rs} (95%) create mode 100644 tests/compile-pass/path_based_bits.rs create mode 100644 tests/compile-pass/trait/generic_iter.rs diff --git a/src/example_generated.rs b/src/example_generated.rs index 9a2fab30..272005cc 100644 --- a/src/example_generated.rs +++ b/src/example_generated.rs @@ -1,60 +1,25 @@ //! This module shows an example of code generated by the macro. **IT MUST NOT BE USED OUTSIDE THIS //! CRATE**. +//! +//! Usually, when you call the `bitflags!` macro, only the `Flags` type would be visible. In this +//! example, the `Field0`, `Iter`, and `IterRaw` types are also exposed so that you can explore +//! their APIs. The `Field0` type can be accessed as `self.0` on an instance of `Flags`. -bitflags! { +__declare_public_bitflags! { /// This is the same `Flags` struct defined in the [crate level example](../index.html#example). /// Note that this struct is just for documentation purposes only, it must not be used outside /// this crate. - pub struct Flags: u32 { - const A = 0b00000001; - const B = 0b00000010; - const C = 0b00000100; - const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits(); - } -} - -/// This is the same internal field available as `self.0` on bitflags types. -/// These types aren't reachable by callers of `bitflags!`, they don't appear in the API of your -/// crate, but you can still interact with them through `self.0` in the module that defines the -/// bitflags type. -/// -/// You can use this example as a reference for what methods are available to all internal bitflags -/// fields if you want to add custom functionality to your bitflags types. -/// -/// Note that this struct is just for documentation purposes only, it must not be used outside -/// this crate. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[repr(transparent)] -pub struct FlagsField { - bits: u32, -} - -pub struct FlagsIter(FlagsIterRaw); - -impl FlagsIter { - const fn new(flags: &FlagsField) -> Self { - FlagsIter(flags.iter_raw()) - } + pub struct Flags; } -pub struct FlagsIterRaw { - idx: usize, - source: FlagsField, - state: FlagsField, -} - -impl FlagsIterRaw { - const fn new(flags: &FlagsField) -> Self { - FlagsIterRaw { - idx: 0, - source: *flags, - state: *flags, - } - } +__declare_internal_bitflags! { + pub struct Field0: u32; + pub struct Iter; + pub struct IterRaw; } __impl_internal_bitflags! { - FlagsField: u32, FlagsIter, FlagsIterRaw { + Field0: u32, Flags, Iter, IterRaw { A; B; C; @@ -62,11 +27,11 @@ __impl_internal_bitflags! { } } -impl crate::__private::InternalFlags for FlagsField { - type PublicFlags = Flags; -} - -impl crate::__private::InternalIter for FlagsField { - type Iter = FlagsIter; - type IterRaw = FlagsIterRaw; +__impl_public_bitflags! { + Flags: u32, Field0, Iter, IterRaw { + A = 0b00000001; + B = 0b00000010; + C = 0b00000100; + ABC = Self::A.bits() | Self::B.bits() | Self::C.bits(); + } } diff --git a/src/external.rs b/src/external.rs new file mode 100644 index 00000000..3076710f --- /dev/null +++ b/src/external.rs @@ -0,0 +1,88 @@ +//! Conditional trait implementations for external libraries. + +#[cfg(feature = "serde")] +pub mod serde_support; + +/// Implements traits from external libraries for the internal bitflags type. +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __impl_external_bitflags { + ( + $InternalBitFlags:ident: $T:ty { + $( + $(#[$attr:ident $($args:tt)*])* + $Flag:ident; + )* + } + ) => { + // Any new library traits impls should be added here + // Use `serde` as an example: generate code when the feature is available, + // and a no-op when it isn't + + __impl_external_bitflags_serde! { + $InternalBitFlags: $T { + $( + $(#[$attr $($args)*])* + $Flag; + )* + } + } + }; +} + +/// Implement `Serialize` and `Deserialize` for the internal bitflags type. +#[macro_export(local_inner_macros)] +#[doc(hidden)] +#[cfg(feature = "serde")] +macro_rules! __impl_external_bitflags_serde { + ( + $InternalBitFlags:ident: $T:ty { + $( + $(#[$attr:ident $($args:tt)*])* + $Flag:ident; + )* + } + ) => { + impl $crate::__private::serde::Serialize for $InternalBitFlags { + fn serialize( + &self, + serializer: S, + ) -> $crate::__private::core::result::Result { + $crate::__private::serde_support::serialize_bits_default( + $crate::__private::core::stringify!($InternalBitFlags), + &self.bits, + serializer, + ) + } + } + + impl<'de> $crate::__private::serde::Deserialize<'de> for $InternalBitFlags { + fn deserialize>( + deserializer: D, + ) -> $crate::__private::core::result::Result { + let bits = $crate::__private::serde_support::deserialize_bits_default( + $crate::__private::core::stringify!($InternalBitFlags), + deserializer, + )?; + + $crate::__private::core::result::Result::Ok($InternalBitFlags::from_bits_retain( + bits, + )) + } + } + }; +} + +#[macro_export(local_inner_macros)] +#[doc(hidden)] +#[cfg(not(feature = "serde"))] +macro_rules! __impl_external_bitflags_serde { + ( + $InternalBitFlags:ident: $T:ty { + $( + $(#[$attr:ident $($args:tt)*])* + $Flag:ident; + )* + } + ) => {}; +} diff --git a/src/serde_support.rs b/src/external/serde_support.rs similarity index 100% rename from src/serde_support.rs rename to src/external/serde_support.rs diff --git a/src/internal.rs b/src/internal.rs new file mode 100644 index 00000000..5b5417ef --- /dev/null +++ b/src/internal.rs @@ -0,0 +1,328 @@ +//! Generate the internal `bitflags`-facing flags type. +//! +//! The code generated here is owned by `bitflags`, but still part of its public API. +//! Changes to the types generated here need to be considered like any other public API change. + +/// Declare the `bitflags`-facing bitflags struct. +/// +/// This type is part of the `bitflags` crate's public API, but not part of the user's. +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __declare_internal_bitflags { + ( + $vis:vis struct $InternalBitFlags:ident: $T:ty; + $iter_vis:vis struct $Iter:ident; + $iter_raw_vis:vis struct $IterRaw:ident; + ) => { + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + #[repr(transparent)] + $vis struct $InternalBitFlags { + bits: $T, + } + + $iter_vis struct $Iter($IterRaw); + + $iter_raw_vis struct $IterRaw { + idx: usize, + source: $InternalBitFlags, + state: $InternalBitFlags, + } + }; +} + +/// Implement functions on the private (bitflags-facing) bitflags type. +/// +/// Methods and trait implementations can be freely added here without breaking end-users. +/// If we want to expose new functionality to `#[derive]`, this is the place to do it. +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __impl_internal_bitflags { + ( + $InternalBitFlags:ident: $T:ty, $BitFlags:ident, $Iter:ident, $IterRaw:ident { + $( + $(#[$attr:ident $($args:tt)*])* + $Flag:ident; + )* + } + ) => { + impl $crate::__private::PublicFlags for $BitFlags { + type Internal = $InternalBitFlags; + } + + impl $crate::__private::core::default::Default for $InternalBitFlags { + #[inline] + fn default() -> Self { + $InternalBitFlags::empty() + } + } + + impl $crate::__private::core::fmt::Debug for $InternalBitFlags { + fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result { + // Iterate over the valid flags + let mut first = true; + for (name, _) in self.iter_raw() { + 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 = self.bits & !Self::all().bits; + + if extra_bits != <$T as $crate::__private::Bits>::EMPTY { + if !first { + f.write_str(" | ")?; + } + first = false; + $crate::__private::core::write!(f, "{:#x}", extra_bits)?; + } + + if first { + f.write_str("empty")?; + } + + $crate::__private::core::fmt::Result::Ok(()) + } + } + + 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 { + 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; + + $( + $(#[$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 const fn iter(&self) -> $Iter { + $Iter(self.iter_raw()) + } + + #[inline] + pub const fn iter_raw(&self) -> $IterRaw { + $IterRaw { + 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) + } + } + + impl $crate::__private::core::iter::Iterator for $Iter { + type Item = $BitFlags; + + fn next(&mut self) -> $crate::__private::core::option::Option { + self.0.next().map(|(_, value)| $BitFlags::from_bits_retain(value)) + } + } + + impl $crate::__private::core::iter::Iterator for $IterRaw { + type Item = (&'static str, $T); + + fn next(&mut self) -> $crate::__private::core::option::Option { + const NUM_FLAGS: usize = { + let mut num_flags = 0; + + $( + $(#[$attr $($args)*])* + { + num_flags += 1; + } + )* + + num_flags + }; + + const OPTIONS: [$T; NUM_FLAGS] = [ + $( + $(#[$attr $($args)*])* + $BitFlags::$Flag.bits(), + )* + ]; + + const OPTIONS_NAMES: [&'static str; NUM_FLAGS] = [ + $( + $(#[$attr $($args)*])* + $crate::__private::core::stringify!($Flag), + )* + ]; + + if self.state.is_empty() || NUM_FLAGS == 0 { + $crate::__private::core::option::Option::None + } else { + 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, flag)) + } + } + + $crate::__private::core::option::Option::None + } + } + } + }; +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index ba78411e..45981df8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,14 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! A typesafe bitmask flag generator useful for sets of C-style bitmask flags. -//! It can be used for creating typesafe wrappers around C APIs. +//! A typesafe bitmask flag generator useful for sets of C-style flags. +//! It can be used for creating ergonomic wrappers around C APIs. //! //! The `bitflags!` macro generates `struct`s that manage a set of flags. The -//! flags should only be defined for integer types, otherwise unexpected type -//! errors may occur at compile time. +//! type of those flags must be some primitive integer. //! -//! # Example +//! # Examples //! //! ``` //! use bitflags::bitflags; @@ -43,42 +42,10 @@ //! See [`example_generated::Flags`](./example_generated/struct.Flags.html) for documentation of code //! generated by the above `bitflags!` expansion. //! -//! The generated `struct`s can also be extended with type and trait -//! implementations: -//! -//! ``` -//! use std::fmt; -//! -//! use bitflags::bitflags; -//! -//! bitflags! { -//! #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -//! struct Flags: u32 { -//! const A = 0b00000001; -//! const B = 0b00000010; -//! } -//! } -//! -//! impl Flags { -//! pub fn clear(&mut self) { -//! *self.0.bits_mut() = 0; -//! } -//! } -//! -//! fn main() { -//! let mut flags = Flags::A | Flags::B; -//! flags.clear(); -//! assert!(flags.is_empty()); -//! assert_eq!(format!("{:?}", Flags::A | Flags::B), "Flags(A | B)"); -//! assert_eq!(format!("{:?}", Flags::B), "Flags(B)"); -//! } -//! ``` -//! //! # Visibility //! -//! The generated structs and their associated flag constants are not exported -//! out of the current module by default. A definition can be exported out of -//! the current module by adding `pub` before `struct`: +//! The `bitflags!` macro supports visibility, just like you'd expect when writing a normal +//! Rust `struct`: //! //! ``` //! mod example { @@ -106,13 +73,15 @@ //! //! # Attributes //! -//! Attributes can be attached to the generated `struct`s by placing them -//! before the `struct` keyword. +//! Attributes can be attached to the generated flags types and their constants as normal. //! -//! ## Representations +//! # Representation //! -//! It's valid to add a `#[repr(C)]` or `#[repr(transparent)]` attribute to a type -//! generated by `bitflags!`. In these cases, the type is guaranteed to be a newtype. +//! It's valid to add a `#[repr(C)]` or `#[repr(transparent)]` attribute to a generated flags type. +//! The generated flags type is always guaranteed to be a newtype where its only field has the same +//! ABI as the underlying integer type. +//! +//! In this example, `Flags` has the same ABI as `u32`: //! //! ``` //! use bitflags::bitflags; @@ -128,14 +97,62 @@ //! } //! ``` //! -//! # Trait implementations +//! # Extending +//! +//! Generated flags types belong to you, so you can add trait implementations to them outside +//! of what the `bitflags!` macro gives: +//! +//! ``` +//! use std::fmt; +//! +//! use bitflags::bitflags; +//! +//! bitflags! { +//! #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +//! struct Flags: u32 { +//! const A = 0b00000001; +//! const B = 0b00000010; +//! } +//! } +//! +//! impl Flags { +//! pub fn clear(&mut self) { +//! *self.0.bits_mut() = 0; +//! } +//! } +//! +//! fn main() { +//! let mut flags = Flags::A | Flags::B; +//! +//! flags.clear(); +//! assert!(flags.is_empty()); +//! +//! assert_eq!(format!("{:?}", Flags::A | Flags::B), "Flags(A | B)"); +//! assert_eq!(format!("{:?}", Flags::B), "Flags(B)"); +//! } +//! ``` +//! +//! # What's implemented by `bitflags!` +//! +//! The `bitflags!` trait adds some trait implementations and inherent methods +//! to generated flags types, but leaves room for you to choose the semantics +//! of others. //! -//! The `Extend` and `FromIterator` traits are implemented for the `struct`s. -//! `Extend` adds the union of the instances of the `struct` iterated over, -//! while `FromIterator` calculates the union. +//! ## Iterators //! -//! The `Binary`, `Debug`, `LowerHex`, `Octal` and `UpperHex` traits are also -//! implemented by displaying the bits value of the internal struct. +//! The following iterator traits are implemented for generated flags types: +//! +//! - `Extend`: adds the union of the instances iterated over. +//! - `FromIterator`: calculates the union. +//! - `IntoIterator`: iterates over set flag values. +//! +//! ## Formatting +//! +//! The following formatting traits are implemented for generated flags types: +//! +//! - `Binary`. +//! - `LowerHex` and `UpperHex`. +//! - `Octal`. //! //! ## Operators //! @@ -147,7 +164,7 @@ //! - `Sub` and `SubAssign`: set difference //! - `Not`: set complement //! -//! # Methods +//! ## Methods //! //! The following methods are defined for the generated `struct`s: //! @@ -184,7 +201,18 @@ //! - `complement`: returns a new set of flags, containing all flags which are //! not set in `self`, but which are allowed for this type. //! -//! ## Default +//! # What's not implemented by `bitflags!` +//! +//! Some functionality is not automatically implemented for generated flags types +//! by the `bitflags!` macro, even when it reasonably could be. This is so callers +//! have more freedom to decide on the semantics of their flags types. +//! +//! ## `Clone` and `Copy` +//! +//! Generated flags types are not automatically copyable, even though they can always +//! derive both `Clone` and `Copy`. +//! +//! ## `Default` //! //! The `Default` trait is not automatically implemented for the generated structs. //! @@ -237,7 +265,18 @@ //! } //! ``` //! -//! # Zero Flags +//! ## `Debug` and `Display` +//! +//! The `Debug` trait can be derived for a reasonable implementation. +//! +//! ## `PartialEq` and `PartialOrd` +//! +//! Equality and ordering can be derived for a reasonable implementation, or implemented manually +//! for different semantics. +//! +//! # Edge cases +//! +//! ## Zero Flags //! //! Flags with a value equal to zero will have some strange behavior that one should be aware of. //! @@ -273,14 +312,15 @@ #![doc(html_root_url = "https://docs.rs/bitflags/1.3.2")] #[doc(inline)] -pub use bitflags_trait::BitFlags; +pub use traits::BitFlags; -mod bitflags_trait; +mod traits; #[doc(hidden)] pub mod __private { - pub use crate::bitflags_trait::{ - Bits, ImplementedByBitFlagsMacro, PublicFlags, + pub use crate::{ + traits::*, + external::*, }; pub use core; @@ -332,8 +372,21 @@ and let `#[derive]` on `MyFlags` pick up that implementation, if an end-user cho The public API is generated in the `__impl_public_flags!` macro, and the internal API is generated in the `__impl_internal_flags!` macro. + +The macros are split into 3 modules: + +- `public`: where the user-facing flags types are generated. +- `internal`: where the `bitflags`-facing flags types are generated. +- `external`: where external library traits are implemented conditionally. */ +#[macro_use] +mod public; +#[macro_use] +mod internal; +#[macro_use] +mod external; + /// The macro used to generate the flag structure. /// /// See the [crate level docs](../bitflags/index.html) for complete documentation. @@ -387,8 +440,10 @@ the `__impl_internal_flags!` macro. /// /// fn main() { /// let mut flags = Flags::A | Flags::B; +/// /// flags.clear(); /// assert!(flags.is_empty()); +/// /// assert_eq!(format!("{:?}", Flags::A | Flags::B), "Flags(A | B)"); /// assert_eq!(format!("{:?}", Flags::B), "Flags(B)"); /// } @@ -406,6 +461,8 @@ macro_rules! bitflags { $($t:tt)* ) => { + // Declared in the scope of the `bitflags!` call + // This type appears in the end-user's API __declare_public_bitflags! { $(#[$outer])* $vis struct $BitFlags; @@ -421,13 +478,14 @@ macro_rules! bitflags { non_upper_case_globals )] const _: () = { + // Declared in a "hidden" scope that can't be reached directly + // These types don't appear in the end-user's API __declare_internal_bitflags! { $vis struct InternalFlags: $T; $vis struct Iter; $vis struct IterRaw; } - // This macro definition is where `derives` for other libraries can be added __impl_internal_bitflags! { InternalFlags: $T, $BitFlags, Iter, IterRaw { $( @@ -437,6 +495,16 @@ macro_rules! bitflags { } } + // This is where new library trait implementations can be added + __impl_external_bitflags! { + InternalBitFlags: $T { + $( + $(#[$inner $($args)*])* + $Flag; + )* + } + } + __impl_public_bitflags! { $BitFlags: $T, InternalFlags, Iter, IterRaw { $( @@ -454,787 +522,6 @@ macro_rules! bitflags { () => {}; } -/// Declare the user-facing bitflags struct. -/// -/// This type is guaranteed to be a newtype with a `bitflags`-facing type as its single field. -#[macro_export(local_inner_macros)] -#[doc(hidden)] -macro_rules! __declare_public_bitflags { - ( - $(#[$outer:meta])* - $vis:vis struct $BitFlags:ident; - ) => { - $(#[$outer])* - $vis struct $BitFlags(::Internal); - }; -} - -/// Declare the `bitflags`-facing bitflags struct. -/// -/// This type is part of the `bitflags` crate's public API, but not part of the user's. -#[macro_export(local_inner_macros)] -#[doc(hidden)] -macro_rules! __declare_internal_bitflags { - ( - $vis:vis struct $InternalBitFlags:ident: $T:ty; - $iter_vis:vis struct $Iter:ident; - $iter_raw_vis:vis struct $IterRaw:ident; - ) => { - #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] - #[repr(transparent)] - $vis struct $InternalBitFlags { - bits: $T, - } - - $iter_vis struct $Iter($IterRaw); - - $iter_raw_vis struct $IterRaw { - idx: usize, - source: $InternalBitFlags, - state: $InternalBitFlags, - } - }; -} - -/// Implement functions on the public (user-facing) bitflags type. -/// -/// We need to be careful about adding new methods and trait implementations here because they -/// could conflict with items added by the end-user. -#[macro_export(local_inner_macros)] -#[doc(hidden)] -macro_rules! __impl_public_bitflags { - ( - $PublicBitFlags:ident: $T:ty, $InternalBitFlags:ident, $Iter:ident, $IterRaw:ident { - $( - $(#[$attr:ident $($args:tt)*])* - $Flag:ident = $value:expr; - )* - } - ) => { - impl $crate::__private::core::fmt::Binary for $PublicBitFlags { - fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result { - $crate::__private::core::fmt::Binary::fmt(&self.0, f) - } - } - - impl $crate::__private::core::fmt::Octal for $PublicBitFlags { - fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result { - $crate::__private::core::fmt::Octal::fmt(&self.0, f) - } - } - - impl $crate::__private::core::fmt::LowerHex for $PublicBitFlags { - fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result { - $crate::__private::core::fmt::LowerHex::fmt(&self.0, f) - } - } - - impl $crate::__private::core::fmt::UpperHex for $PublicBitFlags { - fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result { - $crate::__private::core::fmt::UpperHex::fmt(&self.0, f) - } - } - - impl $PublicBitFlags { - $( - $(#[$attr $($args)*])* - pub const $Flag: Self = Self::from_bits_retain($value); - )* - - /// Returns an empty set of flags. - #[inline] - pub const fn empty() -> Self { - Self($InternalBitFlags::empty()) - } - - /// Returns the set containing all flags. - #[inline] - pub const fn all() -> Self { - Self($InternalBitFlags::all()) - } - - /// Returns the raw value of the flags currently stored. - #[inline] - pub const fn bits(&self) -> $T { - self.0.bits() - } - - /// Convert from underlying bit representation, unless that - /// representation contains bits that do not correspond to a flag. - #[inline] - pub const fn from_bits(bits: $T) -> $crate::__private::core::option::Option { - match $InternalBitFlags::from_bits(bits) { - $crate::__private::core::option::Option::Some(bits) => $crate::__private::core::option::Option::Some(Self(bits)), - $crate::__private::core::option::Option::None => $crate::__private::core::option::Option::None, - } - } - - /// Convert from underlying bit representation, dropping any bits - /// that do not correspond to flags. - #[inline] - pub const fn from_bits_truncate(bits: $T) -> Self { - Self($InternalBitFlags::from_bits_truncate(bits)) - } - - /// Convert from underlying bit representation, preserving all - /// bits (even those not corresponding to a defined flag). - /// - /// # Safety - /// - /// The caller of the `bitflags!` macro can choose to allow or - /// disallow extra bits for their bitflags type. - /// - /// The caller of `from_bits_retain()` has to ensure that - /// all bits correspond to a defined flag or that extra bits - /// are valid for this bitflags type. - #[inline] - pub const fn from_bits_retain(bits: $T) -> Self { - Self($InternalBitFlags::from_bits_retain(bits)) - } - - /// Iterate over enabled flag values. - #[inline] - pub const fn iter(&self) -> $Iter { - self.0.iter() - } - - /// Iterate over the raw names and bits for enabled flag values. - #[inline] - pub const fn iter_raw(&self) -> $IterRaw { - self.0.iter_raw() - } - - /// Returns `true` if no flags are currently stored. - #[inline] - pub const fn is_empty(&self) -> bool { - self.0.is_empty() - } - - /// Returns `true` if all flags are currently set. - #[inline] - pub const fn is_all(&self) -> bool { - self.0.is_all() - } - - /// Returns `true` if there are flags common to both `self` and `other`. - #[inline] - pub const fn intersects(&self, other: Self) -> bool { - self.0.intersects(other.0) - } - - /// Returns `true` if all of the flags in `other` are contained within `self`. - #[inline] - pub const fn contains(&self, other: Self) -> bool { - self.0.contains(other.0) - } - - /// Inserts the specified flags in-place. - #[inline] - pub fn insert(&mut self, other: Self) { - self.0.insert(other.0) - } - - /// Removes the specified flags in-place. - #[inline] - pub fn remove(&mut self, other: Self) { - self.0.remove(other.0) - } - - /// Toggles the specified flags in-place. - #[inline] - pub fn toggle(&mut self, other: Self) { - self.0.toggle(other.0) - } - - /// Inserts or removes the specified flags depending on the passed value. - #[inline] - pub fn set(&mut self, other: Self, value: bool) { - self.0.set(other.0, value) - } - - /// 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`. - /// - /// This is equivalent to using the `&` operator (e.g. - /// [`ops::BitAnd`]), as in `flags & other`. - /// - /// [`ops::BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html - #[inline] - #[must_use] - pub const fn intersection(self, other: Self) -> Self { - Self(self.0.intersection(other.0)) - } - - /// 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). - /// - /// This is equivalent to using the `|` operator (e.g. - /// [`ops::BitOr`]), as in `flags | other`. - /// - /// [`ops::BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html - #[inline] - #[must_use] - pub const fn union(self, other: Self) -> Self { - Self(self.0.union(other.0)) - } - - /// 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`. - /// - /// It is also conceptually equivalent to the "bit-clear" operation: - /// `flags & !other` (and this syntax is also supported). - /// - /// This is equivalent to using the `-` operator (e.g. - /// [`ops::Sub`]), as in `flags - other`. - /// - /// [`ops::Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html - #[inline] - #[must_use] - pub const fn difference(self, other: Self) -> Self { - Self(self.0.difference(other.0)) - } - - /// 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`. - /// - /// This is equivalent to using the `^` operator (e.g. - /// [`ops::BitXor`]), as in `flags ^ other`. - /// - /// [sym-diff]: https://en.wikipedia.org/wiki/Symmetric_difference - /// [`ops::BitXor`]: https://doc.rust-lang.org/std/ops/trait.BitXor.html - #[inline] - #[must_use] - pub const fn symmetric_difference(self, other: Self) -> Self { - Self(self.0.symmetric_difference(other.0)) - } - - /// 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. - /// - /// Alternatively, it can be thought of as the set difference - /// between [`Self::all()`] and `self` (e.g. `Self::all() - self`) - /// - /// This is equivalent to using the `!` operator (e.g. - /// [`ops::Not`]), as in `!flags`. - /// - /// [`Self::all()`]: Self::all - /// [`ops::Not`]: https://doc.rust-lang.org/std/ops/trait.Not.html - #[inline] - #[must_use] - pub const fn complement(self) -> Self { - Self(self.0.complement()) - } - } - - impl $crate::__private::core::ops::BitOr for $PublicBitFlags { - type Output = Self; - - /// Returns the union of the two sets of flags. - #[inline] - fn bitor(self, other: $PublicBitFlags) -> Self { - self.union(other) - } - } - - impl $crate::__private::core::ops::BitOrAssign for $PublicBitFlags { - /// Adds the set of flags. - #[inline] - fn bitor_assign(&mut self, other: Self) { - self.0 = self.0.union(other.0); - } - } - - impl $crate::__private::core::ops::BitXor for $PublicBitFlags { - type Output = Self; - - /// Returns the left flags, but with all the right flags toggled. - #[inline] - fn bitxor(self, other: Self) -> Self { - self.symmetric_difference(other) - } - } - - impl $crate::__private::core::ops::BitXorAssign for $PublicBitFlags { - /// Toggles the set of flags. - #[inline] - fn bitxor_assign(&mut self, other: Self) { - self.0 = self.0.symmetric_difference(other.0); - } - } - - impl $crate::__private::core::ops::BitAnd for $PublicBitFlags { - type Output = Self; - - /// Returns the intersection between the two sets of flags. - #[inline] - fn bitand(self, other: Self) -> Self { - self.intersection(other) - } - } - - impl $crate::__private::core::ops::BitAndAssign for $PublicBitFlags { - /// Disables all flags disabled in the set. - #[inline] - fn bitand_assign(&mut self, other: Self) { - self.0 = self.0.intersection(other.0); - } - } - - impl $crate::__private::core::ops::Sub for $PublicBitFlags { - type Output = Self; - - /// Returns the set difference of the two sets of flags. - #[inline] - fn sub(self, other: Self) -> Self { - self.difference(other) - } - } - - impl $crate::__private::core::ops::SubAssign for $PublicBitFlags { - /// Disables all flags enabled in the set. - #[inline] - fn sub_assign(&mut self, other: Self) { - self.0 = self.0.difference(other.0); - } - } - - impl $crate::__private::core::ops::Not for $PublicBitFlags { - type Output = Self; - - /// Returns the complement of this set of flags. - #[inline] - fn not(self) -> Self { - self.complement() - } - } - - impl $crate::__private::core::iter::Extend<$PublicBitFlags> for $PublicBitFlags { - fn extend>(&mut self, iterator: T) { - for item in iterator { - self.insert(item) - } - } - } - - impl $crate::__private::core::iter::FromIterator<$PublicBitFlags> for $PublicBitFlags { - fn from_iter>(iterator: T) -> Self { - use $crate::__private::core::iter::Extend; - - let mut result = Self::empty(); - result.extend(iterator); - result - } - } - - impl $crate::__private::core::iter::IntoIterator for $PublicBitFlags { - type Item = Self; - type IntoIter = $Iter; - - fn into_iter(self) -> Self::IntoIter { - self.0.iter() - } - } - - impl $crate::BitFlags for $PublicBitFlags { - type Bits = $T; - - type Iter = $Iter; - type IterRaw = $IterRaw; - - fn empty() -> Self { - $PublicBitFlags::empty() - } - - fn all() -> Self { - $PublicBitFlags::all() - } - - fn bits(&self) -> $T { - $PublicBitFlags::bits(self) - } - - fn from_bits(bits: $T) -> $crate::__private::core::option::Option<$PublicBitFlags> { - $PublicBitFlags::from_bits(bits) - } - - fn from_bits_truncate(bits: $T) -> $PublicBitFlags { - $PublicBitFlags::from_bits_truncate(bits) - } - - fn from_bits_retain(bits: $T) -> $PublicBitFlags { - $PublicBitFlags::from_bits_retain(bits) - } - - fn iter(&self) -> Self::Iter { - $PublicBitFlags::iter(self) - } - - fn iter_raw(&self) -> Self::IterRaw { - $PublicBitFlags::iter_raw(self) - } - - fn is_empty(&self) -> bool { - $PublicBitFlags::is_empty(self) - } - - fn is_all(&self) -> bool { - $PublicBitFlags::is_all(self) - } - - fn intersects(&self, other: $PublicBitFlags) -> bool { - $PublicBitFlags::intersects(self, other) - } - - fn contains(&self, other: $PublicBitFlags) -> bool { - $PublicBitFlags::contains(self, other) - } - - fn insert(&mut self, other: $PublicBitFlags) { - $PublicBitFlags::insert(self, other) - } - - fn remove(&mut self, other: $PublicBitFlags) { - $PublicBitFlags::remove(self, other) - } - - fn toggle(&mut self, other: $PublicBitFlags) { - $PublicBitFlags::toggle(self, other) - } - - fn set(&mut self, other: $PublicBitFlags, value: bool) { - $PublicBitFlags::set(self, other, value) - } - } - - impl $crate::__private::ImplementedByBitFlagsMacro for $PublicBitFlags {} - }; -} - -/// Implement functions on the private (bitflags-facing) bitflags type. -/// -/// Methods and trait implementations can be freely added here without breaking end-users. -/// If we want to expose new functionality to `#[derive]`, this is the place to do it. -#[macro_export(local_inner_macros)] -#[doc(hidden)] -macro_rules! __impl_internal_bitflags { - ( - $InternalBitFlags:ident: $T:ty, $BitFlags:ident, $Iter:ident, $IterRaw:ident { - $( - $(#[$attr:ident $($args:tt)*])* - $Flag:ident; - )* - } - ) => { - // Any new library traits impls should be added here - // Use `serde` as an example: generate code when the feature is available, - // and a no-op when it isn't - __impl_internal_bitflags_serde! { - $InternalBitFlags: $T { - $( - $(#[$attr $($args)*])* - $Flag; - )* - } - } - - impl $crate::__private::PublicFlags for $BitFlags { - type Internal = $InternalBitFlags; - } - - impl $crate::__private::core::default::Default for $InternalBitFlags { - #[inline] - fn default() -> Self { - $InternalBitFlags::empty() - } - } - - impl $crate::__private::core::fmt::Debug for $InternalBitFlags { - fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result { - // Iterate over the valid flags - let mut first = true; - for (name, _) in self.iter_raw() { - 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 = self.bits & !Self::all().bits; - - if extra_bits != <$T as $crate::__private::Bits>::EMPTY { - if !first { - f.write_str(" | ")?; - } - first = false; - $crate::__private::core::write!(f, "{:#x}", extra_bits)?; - } - - if first { - f.write_str("empty")?; - } - - $crate::__private::core::fmt::Result::Ok(()) - } - } - - 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 { - 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; - - $( - $(#[$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 const fn iter(&self) -> $Iter { - $Iter(self.iter_raw()) - } - - #[inline] - pub const fn iter_raw(&self) -> $IterRaw { - $IterRaw { - 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) - } - } - - impl $crate::__private::core::iter::Iterator for $Iter { - type Item = $BitFlags; - - fn next(&mut self) -> $crate::__private::core::option::Option { - self.0.next().map(|(_, value)| $BitFlags::from_bits_retain(value)) - } - } - - impl $crate::__private::core::iter::Iterator for $IterRaw { - type Item = (&'static str, $T); - - fn next(&mut self) -> $crate::__private::core::option::Option { - const NUM_FLAGS: usize = { - let mut num_flags = 0; - - $( - $(#[$attr $($args)*])* - { - num_flags += 1; - } - )* - - num_flags - }; - - const OPTIONS: [$T; NUM_FLAGS] = [ - $( - $(#[$attr $($args)*])* - $BitFlags::$Flag.bits(), - )* - ]; - - const OPTIONS_NAMES: [&'static str; NUM_FLAGS] = [ - $( - $(#[$attr $($args)*])* - $crate::__private::core::stringify!($Flag), - )* - ]; - - if self.state.is_empty() || NUM_FLAGS == 0 { - $crate::__private::core::option::Option::None - } else { - 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, flag)) - } - } - - $crate::__private::core::option::Option::None - } - } - } - }; -} - // Optional features // // These macros implement additional library traits for the internal bitflags type so that @@ -1245,69 +532,9 @@ macro_rules! __impl_internal_bitflags { // they'll expand to some impl blocks based on a re-export of the library. If the optional feature // is not enabled then they expand to a no-op. -/// Implement `Serialize` and `Deserialize` for the internal bitflags type. -#[macro_export(local_inner_macros)] -#[doc(hidden)] -#[cfg(feature = "serde")] -macro_rules! __impl_internal_bitflags_serde { - ( - $InternalBitFlags:ident: $T:ty { - $( - $(#[$attr:ident $($args:tt)*])* - $Flag:ident; - )* - } - ) => { - impl $crate::__private::serde::Serialize for $InternalBitFlags { - fn serialize( - &self, - serializer: S, - ) -> $crate::__private::core::result::Result { - $crate::serde_support::serialize_bits_default( - $crate::__private::core::stringify!($InternalBitFlags), - &self.bits, - serializer, - ) - } - } - - impl<'de> $crate::__private::serde::Deserialize<'de> for $InternalBitFlags { - fn deserialize>( - deserializer: D, - ) -> $crate::__private::core::result::Result { - let bits = $crate::serde_support::deserialize_bits_default( - $crate::__private::core::stringify!($InternalBitFlags), - deserializer, - )?; - - $crate::__private::core::result::Result::Ok($InternalBitFlags::from_bits_retain( - bits, - )) - } - } - }; -} - -#[macro_export(local_inner_macros)] -#[doc(hidden)] -#[cfg(not(feature = "serde"))] -macro_rules! __impl_internal_bitflags_serde { - ( - $InternalBitFlags:ident: $T:ty { - $( - $(#[$attr:ident $($args:tt)*])* - $Flag:ident; - )* - } - ) => {}; -} - #[cfg(feature = "example_generated")] pub mod example_generated; -#[cfg(feature = "serde")] -pub mod serde_support; - #[cfg(test)] mod tests { use std::collections::hash_map::DefaultHasher; diff --git a/src/public.rs b/src/public.rs new file mode 100644 index 00000000..4623e661 --- /dev/null +++ b/src/public.rs @@ -0,0 +1,449 @@ +//! Generate the user-facing flags type. +//! +//! The code here belongs to the end-user, so new trait implementations and methods can't be +//! added without potentially breaking users. + +/// Declare the user-facing bitflags struct. +/// +/// This type is guaranteed to be a newtype with a `bitflags`-facing type as its single field. +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __declare_public_bitflags { + ( + $(#[$outer:meta])* + $vis:vis struct $BitFlags:ident; + ) => { + $(#[$outer])* + $vis struct $BitFlags(::Internal); + }; +} + +/// Implement functions on the public (user-facing) bitflags type. +/// +/// We need to be careful about adding new methods and trait implementations here because they +/// could conflict with items added by the end-user. +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __impl_public_bitflags { + ( + $PublicBitFlags:ident: $T:ty, $InternalBitFlags:ident, $Iter:ident, $IterRaw:ident { + $( + $(#[$attr:ident $($args:tt)*])* + $Flag:ident = $value:expr; + )* + } + ) => { + impl $crate::__private::core::fmt::Binary for $PublicBitFlags { + fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result { + $crate::__private::core::fmt::Binary::fmt(&self.0, f) + } + } + + impl $crate::__private::core::fmt::Octal for $PublicBitFlags { + fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result { + $crate::__private::core::fmt::Octal::fmt(&self.0, f) + } + } + + impl $crate::__private::core::fmt::LowerHex for $PublicBitFlags { + fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result { + $crate::__private::core::fmt::LowerHex::fmt(&self.0, f) + } + } + + impl $crate::__private::core::fmt::UpperHex for $PublicBitFlags { + fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result { + $crate::__private::core::fmt::UpperHex::fmt(&self.0, f) + } + } + + impl $PublicBitFlags { + $( + $(#[$attr $($args)*])* + pub const $Flag: Self = Self::from_bits_retain($value); + )* + + /// Returns an empty set of flags. + #[inline] + pub const fn empty() -> Self { + Self($InternalBitFlags::empty()) + } + + /// Returns the set containing all flags. + #[inline] + pub const fn all() -> Self { + Self($InternalBitFlags::all()) + } + + /// Returns the raw value of the flags currently stored. + #[inline] + pub const fn bits(&self) -> $T { + self.0.bits() + } + + /// Convert from underlying bit representation, unless that + /// representation contains bits that do not correspond to a flag. + #[inline] + pub const fn from_bits(bits: $T) -> $crate::__private::core::option::Option { + match $InternalBitFlags::from_bits(bits) { + $crate::__private::core::option::Option::Some(bits) => $crate::__private::core::option::Option::Some(Self(bits)), + $crate::__private::core::option::Option::None => $crate::__private::core::option::Option::None, + } + } + + /// Convert from underlying bit representation, dropping any bits + /// that do not correspond to flags. + #[inline] + pub const fn from_bits_truncate(bits: $T) -> Self { + Self($InternalBitFlags::from_bits_truncate(bits)) + } + + /// Convert from underlying bit representation, preserving all + /// bits (even those not corresponding to a defined flag). + /// + /// # Safety + /// + /// The caller of the `bitflags!` macro can choose to allow or + /// disallow extra bits for their bitflags type. + /// + /// The caller of `from_bits_retain()` has to ensure that + /// all bits correspond to a defined flag or that extra bits + /// are valid for this bitflags type. + #[inline] + pub const fn from_bits_retain(bits: $T) -> Self { + Self($InternalBitFlags::from_bits_retain(bits)) + } + + /// Iterate over enabled flag values. + #[inline] + pub const fn iter(&self) -> $Iter { + self.0.iter() + } + + /// Iterate over the raw names and bits for enabled flag values. + #[inline] + pub const fn iter_raw(&self) -> $IterRaw { + self.0.iter_raw() + } + + /// Returns `true` if no flags are currently stored. + #[inline] + pub const fn is_empty(&self) -> bool { + self.0.is_empty() + } + + /// Returns `true` if all flags are currently set. + #[inline] + pub const fn is_all(&self) -> bool { + self.0.is_all() + } + + /// Returns `true` if there are flags common to both `self` and `other`. + #[inline] + pub const fn intersects(&self, other: Self) -> bool { + self.0.intersects(other.0) + } + + /// Returns `true` if all of the flags in `other` are contained within `self`. + #[inline] + pub const fn contains(&self, other: Self) -> bool { + self.0.contains(other.0) + } + + /// Inserts the specified flags in-place. + #[inline] + pub fn insert(&mut self, other: Self) { + self.0.insert(other.0) + } + + /// Removes the specified flags in-place. + #[inline] + pub fn remove(&mut self, other: Self) { + self.0.remove(other.0) + } + + /// Toggles the specified flags in-place. + #[inline] + pub fn toggle(&mut self, other: Self) { + self.0.toggle(other.0) + } + + /// Inserts or removes the specified flags depending on the passed value. + #[inline] + pub fn set(&mut self, other: Self, value: bool) { + self.0.set(other.0, value) + } + + /// 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`. + /// + /// This is equivalent to using the `&` operator (e.g. + /// [`ops::BitAnd`]), as in `flags & other`. + /// + /// [`ops::BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html + #[inline] + #[must_use] + pub const fn intersection(self, other: Self) -> Self { + Self(self.0.intersection(other.0)) + } + + /// 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). + /// + /// This is equivalent to using the `|` operator (e.g. + /// [`ops::BitOr`]), as in `flags | other`. + /// + /// [`ops::BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html + #[inline] + #[must_use] + pub const fn union(self, other: Self) -> Self { + Self(self.0.union(other.0)) + } + + /// 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`. + /// + /// It is also conceptually equivalent to the "bit-clear" operation: + /// `flags & !other` (and this syntax is also supported). + /// + /// This is equivalent to using the `-` operator (e.g. + /// [`ops::Sub`]), as in `flags - other`. + /// + /// [`ops::Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html + #[inline] + #[must_use] + pub const fn difference(self, other: Self) -> Self { + Self(self.0.difference(other.0)) + } + + /// 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`. + /// + /// This is equivalent to using the `^` operator (e.g. + /// [`ops::BitXor`]), as in `flags ^ other`. + /// + /// [sym-diff]: https://en.wikipedia.org/wiki/Symmetric_difference + /// [`ops::BitXor`]: https://doc.rust-lang.org/std/ops/trait.BitXor.html + #[inline] + #[must_use] + pub const fn symmetric_difference(self, other: Self) -> Self { + Self(self.0.symmetric_difference(other.0)) + } + + /// 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. + /// + /// Alternatively, it can be thought of as the set difference + /// between [`Self::all()`] and `self` (e.g. `Self::all() - self`) + /// + /// This is equivalent to using the `!` operator (e.g. + /// [`ops::Not`]), as in `!flags`. + /// + /// [`Self::all()`]: Self::all + /// [`ops::Not`]: https://doc.rust-lang.org/std/ops/trait.Not.html + #[inline] + #[must_use] + pub const fn complement(self) -> Self { + Self(self.0.complement()) + } + } + + impl $crate::__private::core::ops::BitOr for $PublicBitFlags { + type Output = Self; + + /// Returns the union of the two sets of flags. + #[inline] + fn bitor(self, other: $PublicBitFlags) -> Self { + self.union(other) + } + } + + impl $crate::__private::core::ops::BitOrAssign for $PublicBitFlags { + /// Adds the set of flags. + #[inline] + fn bitor_assign(&mut self, other: Self) { + self.0 = self.0.union(other.0); + } + } + + impl $crate::__private::core::ops::BitXor for $PublicBitFlags { + type Output = Self; + + /// Returns the left flags, but with all the right flags toggled. + #[inline] + fn bitxor(self, other: Self) -> Self { + self.symmetric_difference(other) + } + } + + impl $crate::__private::core::ops::BitXorAssign for $PublicBitFlags { + /// Toggles the set of flags. + #[inline] + fn bitxor_assign(&mut self, other: Self) { + self.0 = self.0.symmetric_difference(other.0); + } + } + + impl $crate::__private::core::ops::BitAnd for $PublicBitFlags { + type Output = Self; + + /// Returns the intersection between the two sets of flags. + #[inline] + fn bitand(self, other: Self) -> Self { + self.intersection(other) + } + } + + impl $crate::__private::core::ops::BitAndAssign for $PublicBitFlags { + /// Disables all flags disabled in the set. + #[inline] + fn bitand_assign(&mut self, other: Self) { + self.0 = self.0.intersection(other.0); + } + } + + impl $crate::__private::core::ops::Sub for $PublicBitFlags { + type Output = Self; + + /// Returns the set difference of the two sets of flags. + #[inline] + fn sub(self, other: Self) -> Self { + self.difference(other) + } + } + + impl $crate::__private::core::ops::SubAssign for $PublicBitFlags { + /// Disables all flags enabled in the set. + #[inline] + fn sub_assign(&mut self, other: Self) { + self.0 = self.0.difference(other.0); + } + } + + impl $crate::__private::core::ops::Not for $PublicBitFlags { + type Output = Self; + + /// Returns the complement of this set of flags. + #[inline] + fn not(self) -> Self { + self.complement() + } + } + + impl $crate::__private::core::iter::Extend<$PublicBitFlags> for $PublicBitFlags { + fn extend>(&mut self, iterator: T) { + for item in iterator { + self.insert(item) + } + } + } + + impl $crate::__private::core::iter::FromIterator<$PublicBitFlags> for $PublicBitFlags { + fn from_iter>(iterator: T) -> Self { + use $crate::__private::core::iter::Extend; + + let mut result = Self::empty(); + result.extend(iterator); + result + } + } + + impl $crate::__private::core::iter::IntoIterator for $PublicBitFlags { + type Item = Self; + type IntoIter = $Iter; + + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } + } + + impl $crate::BitFlags for $PublicBitFlags { + type Bits = $T; + + type Iter = $Iter; + type IterRaw = $IterRaw; + + fn empty() -> Self { + $PublicBitFlags::empty() + } + + fn all() -> Self { + $PublicBitFlags::all() + } + + fn bits(&self) -> $T { + $PublicBitFlags::bits(self) + } + + fn from_bits(bits: $T) -> $crate::__private::core::option::Option<$PublicBitFlags> { + $PublicBitFlags::from_bits(bits) + } + + fn from_bits_truncate(bits: $T) -> $PublicBitFlags { + $PublicBitFlags::from_bits_truncate(bits) + } + + fn from_bits_retain(bits: $T) -> $PublicBitFlags { + $PublicBitFlags::from_bits_retain(bits) + } + + fn iter(&self) -> Self::Iter { + $PublicBitFlags::iter(self) + } + + fn iter_raw(&self) -> Self::IterRaw { + $PublicBitFlags::iter_raw(self) + } + + fn is_empty(&self) -> bool { + $PublicBitFlags::is_empty(self) + } + + fn is_all(&self) -> bool { + $PublicBitFlags::is_all(self) + } + + fn intersects(&self, other: $PublicBitFlags) -> bool { + $PublicBitFlags::intersects(self, other) + } + + fn contains(&self, other: $PublicBitFlags) -> bool { + $PublicBitFlags::contains(self, other) + } + + fn insert(&mut self, other: $PublicBitFlags) { + $PublicBitFlags::insert(self, other) + } + + fn remove(&mut self, other: $PublicBitFlags) { + $PublicBitFlags::remove(self, other) + } + + fn toggle(&mut self, other: $PublicBitFlags) { + $PublicBitFlags::toggle(self, other) + } + + fn set(&mut self, other: $PublicBitFlags, value: bool) { + $PublicBitFlags::set(self, other, value) + } + } + + impl $crate::__private::ImplementedByBitFlagsMacro for $PublicBitFlags {} + }; +} \ No newline at end of file diff --git a/src/bitflags_trait.rs b/src/traits.rs similarity index 95% rename from src/bitflags_trait.rs rename to src/traits.rs index 8ea615fd..d62e043a 100644 --- a/src/bitflags_trait.rs +++ b/src/traits.rs @@ -6,44 +6,63 @@ use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, pub trait BitFlags: ImplementedByBitFlagsMacro { /// The underlying integer type. type Bits: Bits; + /// 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 IterRaw: Iterator; /// Returns an empty set of flags. fn empty() -> Self; + /// Returns the set containing all flags. fn all() -> Self; + /// Returns the raw value of the flags currently stored. fn bits(&self) -> Self::Bits; + /// Convert from underlying bit representation, unless that /// representation contains bits that do not correspond to a flag. fn from_bits(bits: Self::Bits) -> Option where Self: Sized; + /// Convert from underlying bit representation, dropping any bits /// that do not correspond to flags. fn from_bits_truncate(bits: Self::Bits) -> Self; + /// Convert from underlying bit representation, preserving all /// bits (even those not corresponding to a defined flag). fn from_bits_retain(bits: Self::Bits) -> Self; + + /// Iterate over enabled flag values. fn iter(&self) -> Self::Iter; + + /// Iterate over the raw names and bits for enabled flag values. fn iter_raw(&self) -> Self::IterRaw; + /// Returns `true` if no flags are currently stored. fn is_empty(&self) -> bool; + /// Returns `true` if all flags are currently set. fn is_all(&self) -> bool; + /// Returns `true` if there are flags common to both `self` and `other`. fn intersects(&self, other: Self) -> bool; + /// Returns `true` all of the flags in `other` are contained within `self`. fn contains(&self, other: Self) -> bool; + /// Inserts the specified flags in-place. fn insert(&mut self, other: Self); + /// Removes the specified flags in-place. fn remove(&mut self, other: Self); + /// Toggles the specified flags in-place. fn toggle(&mut self, other: Self); + /// Inserts or removes the specified flags depending on the passed value. fn set(&mut self, other: Self, value: bool); } @@ -119,5 +138,6 @@ impl_bits! { /// A trait for referencing the `bitflags`-owned internal type /// without exposing it publicly. pub trait PublicFlags { + /// The type of the internal field on the generated flags type. type Internal; } diff --git a/tests/compile-pass/path_based_bits.rs b/tests/compile-pass/path_based_bits.rs new file mode 100644 index 00000000..1ecdafcf --- /dev/null +++ b/tests/compile-pass/path_based_bits.rs @@ -0,0 +1,14 @@ +#[macro_use] +extern crate bitflags; + +pub mod bits { + pub type Bits = i32; +} + +bitflags! { + pub struct Flags1: bits::Bits { + const A = 1; + } +} + +fn main() {} diff --git a/tests/compile-pass/trait/generic_iter.rs b/tests/compile-pass/trait/generic_iter.rs new file mode 100644 index 00000000..686a303f --- /dev/null +++ b/tests/compile-pass/trait/generic_iter.rs @@ -0,0 +1,16 @@ +use bitflags::{bitflags, BitFlags}; + +bitflags! { + struct Flags: u32 { + const A = 0b00000001; + const B = 0b00000010; + } +} + +fn count_flags(flags: &F) -> usize { + flags.iter().count() +} + +fn main() { + assert_eq!(2, count_flags(&(Flags::A | Flags::B))); +} From 471e2241e55d700d3c6fbb70e2416aec92346245 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Fri, 7 Oct 2022 01:17:17 +1000 Subject: [PATCH 5/6] fix up serde support --- src/lib.rs | 66 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 45981df8..aede586d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -307,6 +307,36 @@ //! ``` //! //! Users should generally avoid defining a flag with a value of zero. +//! +//! # The `BitFlags` trait +//! +//! This library defines a `BitFlags` trait that's implemented by all generated flags types. +//! The trait makes it possible to work with flags types generically: +//! +//! ``` +//! fn count_unset_flags(flags: &F) -> usize { +//! // Find out how many flags there are in total +//! let total = F::all().iter().count(); +//! +//! // Find out how many flags are set +//! let set = flags.iter().count(); +//! +//! total - set +//! } +//! +//! use bitflags::bitflags; +//! +//! bitflags! { +//! #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +//! struct Flags: u32 { +//! const A = 0b00000001; +//! const B = 0b00000010; +//! const C = 0b00000100; +//! } +//! } +//! +//! assert_eq!(2, count_unset_flags(&Flags::B)); +//! ``` #![cfg_attr(not(test), no_std)] #![doc(html_root_url = "https://docs.rs/bitflags/1.3.2")] @@ -352,22 +382,22 @@ bitflags! { What they'd end up with looks something like this: ```rust -pub struct MyFlags(::InternalFlags); +pub struct MyFlags(::InternalBitFlags); const _: () = { #[repr(transparent)] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub struct MyInternalFlags { + pub struct MyInternalBitFlags { bits: u32, } impl PublicFlags for MyFlags { - type Internal = InternalFlags; + type Internal = InternalBitFlags; } }; ``` -If we want to expose something like a new trait impl for generated flags types, we add it to our generated `MyInternalFlags`, +If we want to expose something like a new trait impl for generated flags types, we add it to our generated `MyInternalBitFlags`, and let `#[derive]` on `MyFlags` pick up that implementation, if an end-user chooses to add one. The public API is generated in the `__impl_public_flags!` macro, and the internal API is generated in @@ -380,13 +410,6 @@ The macros are split into 3 modules: - `external`: where external library traits are implemented conditionally. */ -#[macro_use] -mod public; -#[macro_use] -mod internal; -#[macro_use] -mod external; - /// The macro used to generate the flag structure. /// /// See the [crate level docs](../bitflags/index.html) for complete documentation. @@ -481,13 +504,13 @@ macro_rules! bitflags { // Declared in a "hidden" scope that can't be reached directly // These types don't appear in the end-user's API __declare_internal_bitflags! { - $vis struct InternalFlags: $T; + $vis struct InternalBitFlags: $T; $vis struct Iter; $vis struct IterRaw; } __impl_internal_bitflags! { - InternalFlags: $T, $BitFlags, Iter, IterRaw { + InternalBitFlags: $T, $BitFlags, Iter, IterRaw { $( $(#[$inner $($args)*])* $Flag; @@ -506,7 +529,7 @@ macro_rules! bitflags { } __impl_public_bitflags! { - $BitFlags: $T, InternalFlags, Iter, IterRaw { + $BitFlags: $T, InternalBitFlags, Iter, IterRaw { $( $(#[$inner $($args)*])* $Flag = $value; @@ -522,15 +545,12 @@ macro_rules! bitflags { () => {}; } -// Optional features -// -// These macros implement additional library traits for the internal bitflags type so that -// the end-user can either implement or derive those same traits based on the implementation -// we provide in `bitflags`. -// -// These macros all follow a similar pattern. If an optional feature of `bitflags` is enabled -// they'll expand to some impl blocks based on a re-export of the library. If the optional feature -// is not enabled then they expand to a no-op. +#[macro_use] +mod public; +#[macro_use] +mod internal; +#[macro_use] +mod external; #[cfg(feature = "example_generated")] pub mod example_generated; From 62352c857f1b0cbf865e4bbb0b4d73aa2b24c519 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Fri, 7 Oct 2022 01:18:09 +1000 Subject: [PATCH 6/6] run fmt --- src/internal.rs | 2 +- src/lib.rs | 5 +---- src/public.rs | 2 +- src/traits.rs | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/internal.rs b/src/internal.rs index 5b5417ef..f78c89b4 100644 --- a/src/internal.rs +++ b/src/internal.rs @@ -325,4 +325,4 @@ macro_rules! __impl_internal_bitflags { } } }; -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index aede586d..251ab3f8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -348,10 +348,7 @@ mod traits; #[doc(hidden)] pub mod __private { - pub use crate::{ - traits::*, - external::*, - }; + pub use crate::{external::*, traits::*}; pub use core; diff --git a/src/public.rs b/src/public.rs index 4623e661..65477ff0 100644 --- a/src/public.rs +++ b/src/public.rs @@ -446,4 +446,4 @@ macro_rules! __impl_public_bitflags { impl $crate::__private::ImplementedByBitFlagsMacro for $PublicBitFlags {} }; -} \ No newline at end of file +} diff --git a/src/traits.rs b/src/traits.rs index d62e043a..703526ae 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -6,7 +6,7 @@ use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, pub trait BitFlags: ImplementedByBitFlagsMacro { /// The underlying integer type. type Bits: Bits; - + /// An iterator over enabled flags in an instance of the type. type Iter: Iterator;