From 21931c1b1d59d37855a60df2ec77c86638faa0c9 Mon Sep 17 00:00:00 2001 From: Arturo Castro Date: Thu, 18 Jun 2020 16:44:33 +0200 Subject: [PATCH 1/6] BitFlags trait Adds a BitFlags trait that is implemented by every bitflags. The trait includes documentation so it the current hack to document methods through an example could be removed Closes #154 --- src/bitflags_trait.rs | 54 +++++++++++++++++++++++++++++++++++++ src/lib.rs | 63 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 src/bitflags_trait.rs diff --git a/src/bitflags_trait.rs b/src/bitflags_trait.rs new file mode 100644 index 00000000..8398c434 --- /dev/null +++ b/src/bitflags_trait.rs @@ -0,0 +1,54 @@ +pub trait BitFlags: + core::ops::BitOr + + core::ops::BitOrAssign + + core::ops::BitXor + + core::ops::BitXorAssign + + core::ops::BitAnd + + core::ops::BitAndAssign + + core::ops::Sub + + core::ops::SubAssign + + core::ops::Not + + core::iter::Extend + + core::iter::FromIterator +{ + /// 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) -> T; + /// Convert from underlying bit representation, unless that + /// representation contains bits that do not correspond to a flag. + fn from_bits(bits: T) -> core::option::Option; + /// Convert from underlying bit representation, dropping any bits + /// that do not correspond to flags. + unsafe fn from_bits_truncate(bits: T) -> Self; + /// Convert from underlying bit representation, preserving all + /// bits (even those not corresponding to a defined flag). + /// + /// # Safety + /// + /// The caller of the `bitflags!` macro can chose to allow or + /// disallow extra bits for their bitflags type. + /// + /// The caller of `from_bits_unchecked()` has to ensure that + /// all bits correspond to a defined flag or that extra bits + /// are valid for this bitflags type. + unsafe fn from_bits_unchecked(bits: T) -> Self; + /// 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); +} diff --git a/src/lib.rs b/src/lib.rs index 55daa5ea..c56d26e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -262,6 +262,11 @@ extern crate std; #[doc(hidden)] pub extern crate core as _core; +#[doc(inlined)] +pub use bitflags_trait::BitFlags; + +mod bitflags_trait; + /// The macro used to generate the flag structure. /// /// See the [crate level docs](../bitflags/index.html) for complete documentation. @@ -814,6 +819,64 @@ macro_rules! __impl_bitflags { result } } + + impl $crate::BitFlags<$T> for $BitFlags { + fn empty() -> Self { + $BitFlags::empty() + } + + fn all() -> Self { + $BitFlags::all() + } + + fn bits(&self) -> $T { + $BitFlags::bits(self) + } + + fn from_bits(bits: $T) -> $crate::_core::option::Option<$BitFlags> { + $BitFlags::from_bits(bits) + } + + unsafe fn from_bits_truncate(bits: $T) -> $BitFlags { + $BitFlags::from_bits_truncate(bits) + } + + unsafe fn from_bits_unchecked(bits: $T) -> $BitFlags { + $BitFlags::from_bits_unchecked(bits) + } + + fn is_empty(&self) -> bool { + $BitFlags::is_empty(self) + } + + fn is_all(&self) -> bool { + $BitFlags::is_all(self) + } + + fn intersects(&self, other: $BitFlags) -> bool { + $BitFlags::intersects(self, other) + } + + fn contains(&self, other: $BitFlags) -> bool { + $BitFlags::contains(self, other) + } + + fn insert(&mut self, other: $BitFlags) { + $BitFlags::insert(self, other) + } + + fn remove(&mut self, other: $BitFlags) { + $BitFlags::remove(self, other) + } + + fn toggle(&mut self, other: $BitFlags) { + $BitFlags::toggle(self, other) + } + + fn set(&mut self, other: $BitFlags, value: bool) { + $BitFlags::set(self, other, value) + } + } }; // Every attribute that the user writes on a const is applied to the From cd6c42de299da76d52e0c37986c113ccfebd9eff Mon Sep 17 00:00:00 2001 From: Arturo Castro Date: Thu, 18 Jun 2020 17:06:06 +0200 Subject: [PATCH 2/6] missing trait bounds for BitFlags trait --- src/bitflags_trait.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/bitflags_trait.rs b/src/bitflags_trait.rs index 8398c434..45dcff01 100644 --- a/src/bitflags_trait.rs +++ b/src/bitflags_trait.rs @@ -10,6 +10,18 @@ pub trait BitFlags: + core::ops::Not + core::iter::Extend + core::iter::FromIterator + + core::fmt::Debug + + core::cmp::PartialEq + + core::cmp::Eq + + core::cmp::PartialOrd + + core::cmp::Ord + + core::hash::Hash + + Copy + + core::fmt::Octal + + core::fmt::Binary + + core::fmt::LowerHex + + core::fmt::UpperHex + + Clone { /// Returns an empty set of flags. fn empty() -> Self; From 65632b956c6069f655789da41c7ba349248cb23c Mon Sep 17 00:00:00 2001 From: Arturo Castro Date: Thu, 18 Jun 2020 17:06:21 +0200 Subject: [PATCH 3/6] error output doesn't match current compiler --- test_suite/tests/compile-fail/private_flags.stderr | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test_suite/tests/compile-fail/private_flags.stderr b/test_suite/tests/compile-fail/private_flags.stderr index 63748191..c72b6ff6 100644 --- a/test_suite/tests/compile-fail/private_flags.stderr +++ b/test_suite/tests/compile-fail/private_flags.stderr @@ -2,4 +2,15 @@ error[E0603]: struct `Flags2` is private --> $DIR/private_flags.rs:19:26 | 19 | let flag2 = example::Flags2::FLAG_B; - | ^^^^^^ + | ^^^^^^ private struct + | +note: the struct `Flags2` is defined here + --> $DIR/private_flags.rs:10:5 + | +10 | / bitflags! { +11 | | struct Flags2: u32 { +12 | | const FLAG_B = 0b00000010; +13 | | } +14 | | } + | |_____^ + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) From 358d598e3d5ad4d1cb1faaf9c31e8bf23f35f672 Mon Sep 17 00:00:00 2001 From: Arturo Castro Date: Thu, 18 Jun 2020 17:15:20 +0200 Subject: [PATCH 4/6] fix trait bounds for older compilers --- src/bitflags_trait.rs | 46 ++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/src/bitflags_trait.rs b/src/bitflags_trait.rs index 45dcff01..e6ea2c6b 100644 --- a/src/bitflags_trait.rs +++ b/src/bitflags_trait.rs @@ -1,27 +1,29 @@ +use core as _core; + pub trait BitFlags: - core::ops::BitOr - + core::ops::BitOrAssign - + core::ops::BitXor - + core::ops::BitXorAssign - + core::ops::BitAnd - + core::ops::BitAndAssign - + core::ops::Sub - + core::ops::SubAssign - + core::ops::Not - + core::iter::Extend - + core::iter::FromIterator - + core::fmt::Debug - + core::cmp::PartialEq - + core::cmp::Eq - + core::cmp::PartialOrd - + core::cmp::Ord - + core::hash::Hash - + Copy - + core::fmt::Octal - + core::fmt::Binary - + core::fmt::LowerHex - + core::fmt::UpperHex + _core::ops::BitOr + + _core::ops::BitOrAssign + + _core::ops::BitXor + + _core::ops::BitXorAssign + + _core::ops::BitAnd + + _core::ops::BitAndAssign + + _core::ops::Sub + + _core::ops::SubAssign + + _core::ops::Not + + _core::iter::Extend + + _core::iter::FromIterator + + _core::fmt::Debug + + _core::cmp::PartialEq + + _core::cmp::Eq + + _core::cmp::PartialOrd + + _core::cmp::Ord + + _core::hash::Hash + + _core::fmt::Octal + + _core::fmt::Binary + + _core::fmt::LowerHex + + _core::fmt::UpperHex + Clone + + Copy { /// Returns an empty set of flags. fn empty() -> Self; From 7f77a4fa7b1b782286d6c83918173058fa526559 Mon Sep 17 00:00:00 2001 From: Arturo Castro Date: Thu, 18 Jun 2020 17:26:38 +0200 Subject: [PATCH 5/6] fix BitFlags trait for old compilers --- src/bitflags_trait.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitflags_trait.rs b/src/bitflags_trait.rs index e6ea2c6b..48345881 100644 --- a/src/bitflags_trait.rs +++ b/src/bitflags_trait.rs @@ -33,7 +33,7 @@ pub trait BitFlags: fn bits(&self) -> T; /// Convert from underlying bit representation, unless that /// representation contains bits that do not correspond to a flag. - fn from_bits(bits: T) -> core::option::Option; + fn from_bits(bits: T) -> _core::option::Option; /// Convert from underlying bit representation, dropping any bits /// that do not correspond to flags. unsafe fn from_bits_truncate(bits: T) -> Self; From 09e523e46fc70dfd67a20ce14127cffa42f08f00 Mon Sep 17 00:00:00 2001 From: Arturo Castro Date: Sun, 16 May 2021 17:57:13 +0200 Subject: [PATCH 6/6] implement suggestions on PR --- src/bitflags_trait.rs | 36 +++++++----------------------------- src/lib.rs | 6 ++++-- 2 files changed, 11 insertions(+), 31 deletions(-) diff --git a/src/bitflags_trait.rs b/src/bitflags_trait.rs index 48345881..0b8facbb 100644 --- a/src/bitflags_trait.rs +++ b/src/bitflags_trait.rs @@ -1,42 +1,20 @@ use core as _core; -pub trait BitFlags: - _core::ops::BitOr - + _core::ops::BitOrAssign - + _core::ops::BitXor - + _core::ops::BitXorAssign - + _core::ops::BitAnd - + _core::ops::BitAndAssign - + _core::ops::Sub - + _core::ops::SubAssign - + _core::ops::Not - + _core::iter::Extend - + _core::iter::FromIterator - + _core::fmt::Debug - + _core::cmp::PartialEq - + _core::cmp::Eq - + _core::cmp::PartialOrd - + _core::cmp::Ord - + _core::hash::Hash - + _core::fmt::Octal - + _core::fmt::Binary - + _core::fmt::LowerHex - + _core::fmt::UpperHex - + Clone - + Copy -{ +pub trait BitFlags { + type Bits; /// 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) -> T; + 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: T) -> _core::option::Option; + fn from_bits(bits: Self::Bits) -> _core::option::Option + where Self: Sized; /// Convert from underlying bit representation, dropping any bits /// that do not correspond to flags. - unsafe fn from_bits_truncate(bits: T) -> Self; + fn from_bits_truncate(bits: Self::Bits) -> Self; /// Convert from underlying bit representation, preserving all /// bits (even those not corresponding to a defined flag). /// @@ -48,7 +26,7 @@ pub trait BitFlags: /// The caller of `from_bits_unchecked()` has to ensure that /// all bits correspond to a defined flag or that extra bits /// are valid for this bitflags type. - unsafe fn from_bits_unchecked(bits: T) -> Self; + unsafe fn from_bits_unchecked(bits: Self::Bits) -> Self; /// Returns `true` if no flags are currently stored. fn is_empty(&self) -> bool; /// Returns `true` if all flags are currently set. diff --git a/src/lib.rs b/src/lib.rs index f169aaf5..705ddf35 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -869,7 +869,9 @@ macro_rules! __impl_bitflags { } } - impl $crate::BitFlags<$T> for $BitFlags { + impl $crate::BitFlags for $BitFlags { + type Bits = $T; + fn empty() -> Self { $BitFlags::empty() } @@ -886,7 +888,7 @@ macro_rules! __impl_bitflags { $BitFlags::from_bits(bits) } - unsafe fn from_bits_truncate(bits: $T) -> $BitFlags { + fn from_bits_truncate(bits: $T) -> $BitFlags { $BitFlags::from_bits_truncate(bits) }