aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Walbran <qwandor@google.com>2023-06-14 16:37:52 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-06-14 16:37:52 +0000
commitc4af5ed2fa5e1b7ed989a39a6b1e3dfa8a8b19b4 (patch)
tree680ec0b7c7385389bf019efd940a1690c6aac350
parent45a157cc95331987bfbd03b856007a470eeda21b (diff)
parent976ee2c4aca4f6a98daa9d5ff32d1950c1fad9fa (diff)
downloadbitflags-c4af5ed2fa5e1b7ed989a39a6b1e3dfa8a8b19b4.tar.gz
Update to 2.3.2. am: ff6563b406 am: 4cb5dac10a am: f67ee5f0b8 am: a6cfe4692d am: 88d3d13639 am: 976ee2c4ac
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/bitflags/+/2624429 Change-Id: I6f18177b5d32d151f5c47c542496555b0b46eec2 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--.github/workflows/rust.yml56
-rw-r--r--Android.bp2
-rw-r--r--CHANGELOG.md24
-rw-r--r--Cargo.toml5
-rw-r--r--Cargo.toml.orig3
-rw-r--r--METADATA8
-rw-r--r--README.md2
-rw-r--r--examples/custom_bits_type.rs85
-rw-r--r--examples/custom_derive.rs23
-rw-r--r--examples/fmt.rs50
-rw-r--r--examples/macro_free.rs58
-rw-r--r--src/example_generated.rs35
-rw-r--r--src/external.rs98
-rw-r--r--src/external/arbitrary.rs (renamed from src/external/arbitrary_support.rs)14
-rw-r--r--src/external/bytemuck.rs (renamed from src/external/bytemuck_support.rs)0
-rw-r--r--src/external/serde.rs (renamed from src/external/serde_support.rs)41
-rw-r--r--src/internal.rs505
-rw-r--r--src/iter.rs133
-rw-r--r--src/lib.rs513
-rw-r--r--src/parser.rs113
-rw-r--r--src/public.rs575
-rw-r--r--src/traits.rs310
-rw-r--r--tests/basic.rs20
-rw-r--r--tests/compile-fail/.gitignore1
-rw-r--r--tests/compile-fail/impls/copy.rs10
-rw-r--r--tests/compile-fail/impls/copy.stderr.beta27
-rw-r--r--tests/compile-fail/impls/eq.rs10
-rw-r--r--tests/compile-fail/impls/eq.stderr.beta55
-rw-r--r--tests/compile-fail/non_integer_base/all_defined.rs123
-rw-r--r--tests/compile-fail/non_integer_base/all_defined.stderr.beta27
-rw-r--r--tests/compile-fail/non_integer_base/all_missing.rs13
-rw-r--r--tests/compile-fail/non_integer_base/all_missing.stderr.beta13
-rw-r--r--tests/compile-fail/visibility/private_field.rs13
-rw-r--r--tests/compile-fail/visibility/private_field.stderr.beta10
-rw-r--r--tests/compile-fail/visibility/private_flags.rs18
-rw-r--r--tests/compile-fail/visibility/private_flags.stderr.beta18
-rw-r--r--tests/compile-fail/visibility/pub_const.rs9
-rw-r--r--tests/compile-fail/visibility/pub_const.stderr.beta5
-rw-r--r--tests/compile-pass/impls/convert.rs17
-rw-r--r--tests/compile-pass/impls/default.rs10
-rw-r--r--tests/compile-pass/impls/inherent_methods.rs15
-rw-r--r--tests/compile-pass/redefinition/core.rs14
-rw-r--r--tests/compile-pass/redefinition/stringify.rs19
-rw-r--r--tests/compile-pass/repr/c.rs10
-rw-r--r--tests/compile-pass/repr/transparent.rs10
-rw-r--r--tests/compile-pass/visibility/bits_field.rs11
-rw-r--r--tests/compile-pass/visibility/pub_in.rs19
-rw-r--r--tests/compile.rs63
49 files changed, 1645 insertions, 1570 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index b28c102..6877a2f 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
{
"git": {
- "sha1": "0c318c0d77ed63ad4ee9bfdf1d2c486993b18b37"
+ "sha1": "09f71f492d0f76d63cd286c3869c70676297e204"
},
"path_in_vcs": ""
} \ No newline at end of file
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
deleted file mode 100644
index ffe0eda..0000000
--- a/.github/workflows/rust.yml
+++ /dev/null
@@ -1,56 +0,0 @@
-name: Rust
-
-on: [push, pull_request]
-
-env:
- CARGO_TERM_COLOR: always
-
-jobs:
- check:
- name: Test
- runs-on: ubuntu-latest
- strategy:
- fail-fast: true
- matrix:
- rust:
- - stable
- - beta
- - nightly
- - 1.46.0
- steps:
- - name: Checkout sources
- uses: actions/checkout@v2
-
- - name: Install Rust toolchain
- uses: actions-rs/toolchain@v1
- with:
- profile: minimal
- toolchain: ${{ matrix.rust }}
- override: true
-
- - name: Default features
- uses: actions-rs/cargo@v1
- with:
- command: test
- args: --features example_generated
-
- embedded:
- name: Build (embedded)
- runs-on: ubuntu-latest
- steps:
- - name: Checkout sources
- uses: actions/checkout@v2
-
- - name: Install Rust toolchain
- uses: actions-rs/toolchain@v1
- with:
- profile: minimal
- toolchain: nightly
- target: thumbv6m-none-eabi
- override: true
-
- - name: Default features
- uses: actions-rs/cargo@v1
- with:
- command: build
- args: -Z avoid-dev-deps --features example_generated --target thumbv6m-none-eabi
diff --git a/Android.bp b/Android.bp
index a6761c1..6d4d347 100644
--- a/Android.bp
+++ b/Android.bp
@@ -42,7 +42,7 @@ rust_library {
host_supported: true,
crate_name: "bitflags",
cargo_env_compat: true,
- cargo_pkg_version: "2.2.1",
+ cargo_pkg_version: "2.3.2",
srcs: ["src/lib.rs"],
edition: "2021",
apex_available: [
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5c6df58..5512ceb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,27 @@
+# 2.3.2
+
+## What's Changed
+* [doc] [src/lib.rs] delete redundant path prefix by @OccupyMars2025 in https://github.com/bitflags/bitflags/pull/361
+
+## New Contributors
+* @OccupyMars2025 made their first contribution in https://github.com/bitflags/bitflags/pull/361
+
+**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.3.1...2.3.2
+
+# 2.3.1
+
+## What's Changed
+* Fix Self in flags value expressions by @KodrAus in https://github.com/bitflags/bitflags/pull/355
+
+**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.3.0...2.3.1
+
+# 2.3.0
+
+## What's Changed
+* Support ejecting flags types from the bitflags macro by @KodrAus in https://github.com/bitflags/bitflags/pull/351
+
+**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.2.1...2.3.0
+
# 2.2.1
## What's Changed
diff --git a/Cargo.toml b/Cargo.toml
index 06afeef..7b9cfb0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@
edition = "2021"
rust-version = "1.56.0"
name = "bitflags"
-version = "2.2.1"
+version = "2.3.2"
authors = ["The Rust Project Developers"]
exclude = [
"tests",
@@ -83,6 +83,9 @@ version = "1.0"
[dev-dependencies.trybuild]
version = "1.0"
+[dev-dependencies.zerocopy]
+version = "0.6"
+
[features]
example_generated = []
rustc-dep-of-std = [
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index a239132..7d57882 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -3,7 +3,7 @@ name = "bitflags"
# NB: When modifying, also modify:
# 1. html_root_url in lib.rs
# 2. number in readme (for breaking changes)
-version = "2.2.1"
+version = "2.3.2"
edition = "2021"
rust-version = "1.56.0"
authors = ["The Rust Project Developers"]
@@ -32,6 +32,7 @@ rustversion = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
serde_test = "1.0"
+zerocopy = "0.6"
arbitrary = { version = "1.0", features = ["derive"] }
bytemuck = { version = "1.0", features = ["derive"] }
diff --git a/METADATA b/METADATA
index a0bd701..0872db8 100644
--- a/METADATA
+++ b/METADATA
@@ -11,13 +11,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/bitflags/bitflags-2.2.1.crate"
+ value: "https://static.crates.io/crates/bitflags/bitflags-2.3.2.crate"
}
- version: "2.2.1"
+ version: "2.3.2"
license_type: NOTICE
last_upgrade_date {
year: 2023
- month: 4
- day: 26
+ month: 6
+ day: 13
}
}
diff --git a/README.md b/README.md
index f9a5bb4..fada7a6 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ Add this to your `Cargo.toml`:
```toml
[dependencies]
-bitflags = "2.2.1"
+bitflags = "2.3.2"
```
and this to your source code:
diff --git a/examples/custom_bits_type.rs b/examples/custom_bits_type.rs
new file mode 100644
index 0000000..0364a2b
--- /dev/null
+++ b/examples/custom_bits_type.rs
@@ -0,0 +1,85 @@
+use std::ops::{BitAnd, BitOr, BitXor, Not};
+
+use bitflags::{Flags, Flag, Bits};
+
+// Define a custom container that can be used in flags types
+// Note custom bits types can't be used in `bitflags!`
+// without making the trait impls `const`. This is currently
+// unstable
+#[derive(Clone, Copy, Debug)]
+pub struct CustomBits([bool; 3]);
+
+impl Bits for CustomBits {
+ const EMPTY: Self = CustomBits([false; 3]);
+
+ const ALL: Self = CustomBits([true; 3]);
+}
+
+impl PartialEq for CustomBits {
+ fn eq(&self, other: &Self) -> bool {
+ self.0 == other.0
+ }
+}
+
+impl BitAnd for CustomBits {
+ type Output = Self;
+
+ fn bitand(self, other: Self) -> Self {
+ CustomBits([self.0[0] & other.0[0], self.0[1] & other.0[1], self.0[2] & other.0[2]])
+ }
+}
+
+impl BitOr for CustomBits {
+ type Output = Self;
+
+ fn bitor(self, other: Self) -> Self {
+ CustomBits([self.0[0] | other.0[0], self.0[1] | other.0[1], self.0[2] | other.0[2]])
+ }
+}
+
+impl BitXor for CustomBits {
+ type Output = Self;
+
+ fn bitxor(self, other: Self) -> Self {
+ CustomBits([self.0[0] & other.0[0], self.0[1] & other.0[1], self.0[2] & other.0[2]])
+ }
+}
+
+impl Not for CustomBits {
+ type Output = Self;
+
+ fn not(self) -> Self {
+ CustomBits([!self.0[0], !self.0[1], !self.0[2]])
+ }
+}
+
+#[derive(Clone, Copy, Debug)]
+pub struct CustomFlags(CustomBits);
+
+impl CustomFlags {
+ pub const A: Self = CustomFlags(CustomBits([true, false, false]));
+ pub const B: Self = CustomFlags(CustomBits([false, true, false]));
+ pub const C: Self = CustomFlags(CustomBits([false, false, true]));
+}
+
+impl Flags for CustomFlags {
+ const FLAGS: &'static [Flag<Self>] = &[
+ Flag::new("A", Self::A),
+ Flag::new("B", Self::B),
+ Flag::new("C", Self::C),
+ ];
+
+ type Bits = CustomBits;
+
+ fn bits(&self) -> Self::Bits {
+ self.0
+ }
+
+ fn from_bits_retain(bits: Self::Bits) -> Self {
+ CustomFlags(bits)
+ }
+}
+
+fn main() {
+ println!("{:?}", CustomFlags::A.union(CustomFlags::C));
+}
diff --git a/examples/custom_derive.rs b/examples/custom_derive.rs
new file mode 100644
index 0000000..5a85afb
--- /dev/null
+++ b/examples/custom_derive.rs
@@ -0,0 +1,23 @@
+//! An example of implementing the `BitFlags` trait manually for a flags type.
+
+use std::str;
+
+use bitflags::bitflags;
+
+// Define a flags type outside of the `bitflags` macro as a newtype
+// It can accept custom derives for libaries `bitflags` doesn't support natively
+#[derive(zerocopy::AsBytes, zerocopy::FromBytes)]
+#[repr(transparent)]
+pub struct ManualFlags(u32);
+
+// Next: use `impl Flags` instead of `struct Flags`
+bitflags! {
+ impl ManualFlags: u32 {
+ const A = 0b00000001;
+ const B = 0b00000010;
+ const C = 0b00000100;
+ const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits();
+ }
+}
+
+fn main() {}
diff --git a/examples/fmt.rs b/examples/fmt.rs
index 3bb9b8c..724b207 100644
--- a/examples/fmt.rs
+++ b/examples/fmt.rs
@@ -2,40 +2,40 @@
use core::{fmt, str};
-fn main() -> Result<(), bitflags::parser::ParseError> {
- bitflags::bitflags! {
- // You can `#[derive]` the `Debug` trait, but implementing it manually
- // can produce output like `A | B` instead of `Flags(A | B)`.
- // #[derive(Debug)]
- #[derive(PartialEq, Eq)]
- pub struct Flags: u32 {
- const A = 1;
- const B = 2;
- const C = 4;
- const D = 8;
- }
+bitflags::bitflags! {
+ // You can `#[derive]` the `Debug` trait, but implementing it manually
+ // can produce output like `A | B` instead of `Flags(A | B)`.
+ // #[derive(Debug)]
+ #[derive(PartialEq, Eq)]
+ pub struct Flags: u32 {
+ const A = 1;
+ const B = 2;
+ const C = 4;
+ const D = 8;
}
+}
- impl fmt::Debug for Flags {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Debug::fmt(&self.0, f)
- }
+impl fmt::Debug for Flags {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ bitflags::parser::to_writer(self, f)
}
+}
- impl fmt::Display for Flags {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(&self.0, f)
- }
+impl fmt::Display for Flags {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ bitflags::parser::to_writer(self, f)
}
+}
- impl str::FromStr for Flags {
- type Err = bitflags::parser::ParseError;
+impl str::FromStr for Flags {
+ type Err = bitflags::parser::ParseError;
- fn from_str(flags: &str) -> Result<Self, Self::Err> {
- Ok(Self(flags.parse()?))
- }
+ fn from_str(flags: &str) -> Result<Self, Self::Err> {
+ bitflags::parser::from_str(flags)
}
+}
+fn main() -> Result<(), bitflags::parser::ParseError> {
let flags = Flags::A | Flags::B;
println!("{}", flags);
diff --git a/examples/macro_free.rs b/examples/macro_free.rs
new file mode 100644
index 0000000..ec3a8cb
--- /dev/null
+++ b/examples/macro_free.rs
@@ -0,0 +1,58 @@
+//! An example of implementing the `BitFlags` trait manually for a flags type.
+//!
+//! This example doesn't use any macros.
+
+use std::{fmt, str};
+
+use bitflags::{Flags, Flag};
+
+// First: Define your flags type. It just needs to be `Sized + 'static`.
+pub struct ManualFlags(u32);
+
+// Not required: Define some constants for valid flags
+impl ManualFlags {
+ pub const A: ManualFlags = ManualFlags(0b00000001);
+ pub const B: ManualFlags = ManualFlags(0b00000010);
+ pub const C: ManualFlags = ManualFlags(0b00000100);
+ pub const ABC: ManualFlags = ManualFlags(0b00000111);
+}
+
+// Next: Implement the `BitFlags` trait, specifying your set of valid flags
+// and iterators
+impl Flags for ManualFlags {
+ const FLAGS: &'static [Flag<Self>] = &[
+ Flag::new("A", Self::A),
+ Flag::new("B", Self::B),
+ Flag::new("C", Self::C),
+ ];
+
+ type Bits = u32;
+
+ fn bits(&self) -> u32 {
+ self.0
+ }
+
+ fn from_bits_retain(bits: u32) -> Self {
+ Self(bits)
+ }
+}
+
+// Not required: Add parsing support
+impl str::FromStr for ManualFlags {
+ type Err = bitflags::parser::ParseError;
+
+ fn from_str(input: &str) -> Result<Self, Self::Err> {
+ bitflags::parser::from_str(input)
+ }
+}
+
+// Not required: Add formatting support
+impl fmt::Display for ManualFlags {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ bitflags::parser::to_writer(self, f)
+ }
+}
+
+fn main() {
+ println!("{}", ManualFlags::A.union(ManualFlags::B).union(ManualFlags::C));
+}
diff --git a/src/example_generated.rs b/src/example_generated.rs
index b758901..7f8a5c5 100644
--- a/src/example_generated.rs
+++ b/src/example_generated.rs
@@ -9,30 +9,41 @@ __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;
+ pub struct Flags
}
__declare_internal_bitflags! {
- pub struct Field0: u32;
- pub struct Iter;
- pub struct IterRaw;
+ pub struct Field0: u32
}
__impl_internal_bitflags! {
- Field0: u32, Flags, Iter, IterRaw {
- A;
- B;
- C;
- ABC;
+ Field0: u32, Flags {
+ // Field `A`.
+ ///
+ /// This flag has the value `0b00000001`.
+ A = 0b00000001;
+ /// Field `B`.
+ ///
+ /// This flag has the value `0b00000010`.
+ B = 0b00000010;
+ /// Field `C`.
+ ///
+ /// This flag has the value `0b00000100`.
+ C = 0b00000100;
+ ABC = Self::A.bits() | Self::B.bits() | Self::C.bits();
}
}
-__impl_public_bitflags! {
- Flags: u32, Field0, Iter, IterRaw;
+__impl_public_bitflags_forward! {
+ Flags: u32, Field0
+}
+
+__impl_public_bitflags_iter! {
+ Flags: u32, Flags
}
__impl_public_bitflags_consts! {
- Flags {
+ Flags: u32 {
/// Field `A`.
///
/// This flag has the value `0b00000001`.
diff --git a/src/external.rs b/src/external.rs
index 6b07ff6..103b5d1 100644
--- a/src/external.rs
+++ b/src/external.rs
@@ -5,7 +5,13 @@ How do I support a new external library?
Let's say we want to add support for `my_library`.
-First, we define a macro like so:
+First, we create a module under `external`, like `serde` with any specialized code.
+Ideally, any utilities in here should just work off the `Flags` trait and maybe a
+few other assumed bounds.
+
+Next, re-export the library from the `__private` module here.
+
+Next, define a macro like so:
```rust
#[macro_export(local_inner_macros)]
@@ -13,7 +19,7 @@ First, we define a macro like so:
#[cfg(feature = "serde")]
macro_rules! __impl_external_bitflags_my_library {
(
- $InternalBitFlags:ident: $T:ty {
+ $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident {
$(
$(#[$attr:ident $($args:tt)*])*
$Flag:ident;
@@ -29,7 +35,7 @@ macro_rules! __impl_external_bitflags_my_library {
#[cfg(not(feature = "my_library"))]
macro_rules! __impl_external_bitflags_my_library {
(
- $InternalBitFlags:ident: $T:ty {
+ $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident {
$(
$(#[$attr:ident $($args:tt)*])*
$Flag:ident;
@@ -49,7 +55,7 @@ Now, we add our macro call to the `__impl_external_bitflags` macro body:
```rust
__impl_external_bitflags_my_library! {
- $InternalBitFlags: $T {
+ $InternalBitFlags: $T, $PublicBitFlags {
$(
$(#[$attr $($args)*])*
$Flag;
@@ -57,34 +63,25 @@ __impl_external_bitflags_my_library! {
}
}
```
-
-What about libraries that _must_ be supported through `#[derive]`?
-
-In these cases, the attributes will need to be added to the `__declare_internal_bitflags` macro when
-the internal type is declared.
*/
-#[cfg(feature = "serde")]
-pub mod serde_support;
-#[cfg(feature = "serde")]
-pub use serde;
+pub(crate) mod __private {
+ #[cfg(feature = "serde")]
+ pub use serde;
-#[cfg(feature = "arbitrary")]
-pub mod arbitrary_support;
-#[cfg(feature = "arbitrary")]
-pub use arbitrary;
+ #[cfg(feature = "arbitrary")]
+ pub use arbitrary;
-#[cfg(feature = "bytemuck")]
-pub mod bytemuck_support;
-#[cfg(feature = "bytemuck")]
-pub use bytemuck;
+ #[cfg(feature = "bytemuck")]
+ pub use bytemuck;
+}
/// 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 {
+ $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident {
$(
$(#[$attr:ident $($args:tt)*])*
$Flag:ident;
@@ -96,7 +93,7 @@ macro_rules! __impl_external_bitflags {
// and a no-op when it isn't
__impl_external_bitflags_serde! {
- $InternalBitFlags: $T {
+ $InternalBitFlags: $T, $PublicBitFlags {
$(
$(#[$attr $($args)*])*
$Flag;
@@ -105,7 +102,7 @@ macro_rules! __impl_external_bitflags {
}
__impl_external_bitflags_arbitrary! {
- $InternalBitFlags: $T {
+ $InternalBitFlags: $T, $PublicBitFlags {
$(
$(#[$attr $($args)*])*
$Flag;
@@ -114,7 +111,7 @@ macro_rules! __impl_external_bitflags {
}
__impl_external_bitflags_bytemuck! {
- $InternalBitFlags: $T {
+ $InternalBitFlags: $T, $PublicBitFlags {
$(
$(#[$attr $($args)*])*
$Flag;
@@ -124,13 +121,16 @@ macro_rules! __impl_external_bitflags {
};
}
+#[cfg(feature = "serde")]
+pub mod serde;
+
/// 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 {
+ $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident {
$(
$(#[$attr:ident $($args:tt)*])*
$Flag:ident;
@@ -142,8 +142,8 @@ macro_rules! __impl_external_bitflags_serde {
&self,
serializer: S,
) -> $crate::__private::core::result::Result<S::Ok, S::Error> {
- $crate::__private::serde_support::serialize_bits_default::<$InternalBitFlags, $T, S>(
- &self,
+ $crate::serde::serialize(
+ &$PublicBitFlags::from_bits_retain(self.bits()),
serializer,
)
}
@@ -153,9 +153,11 @@ macro_rules! __impl_external_bitflags_serde {
fn deserialize<D: $crate::__private::serde::Deserializer<'de>>(
deserializer: D,
) -> $crate::__private::core::result::Result<Self, D::Error> {
- $crate::__private::serde_support::deserialize_bits_default::<$InternalBitFlags, $T, D>(
+ let flags: $PublicBitFlags = $crate::serde::deserialize(
deserializer,
- )
+ )?;
+
+ Ok(flags.0)
}
}
};
@@ -166,7 +168,7 @@ macro_rules! __impl_external_bitflags_serde {
#[cfg(not(feature = "serde"))]
macro_rules! __impl_external_bitflags_serde {
(
- $InternalBitFlags:ident: $T:ty {
+ $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident {
$(
$(#[$attr:ident $($args:tt)*])*
$Flag:ident;
@@ -175,13 +177,19 @@ macro_rules! __impl_external_bitflags_serde {
) => {};
}
+#[cfg(feature = "arbitrary")]
+pub mod arbitrary;
+
+#[cfg(feature = "bytemuck")]
+mod bytemuck;
+
/// Implement `Arbitrary` for the internal bitflags type.
#[macro_export(local_inner_macros)]
#[doc(hidden)]
#[cfg(feature = "arbitrary")]
macro_rules! __impl_external_bitflags_arbitrary {
(
- $InternalBitFlags:ident: $T:ty {
+ $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident {
$(
$(#[$attr:ident $($args:tt)*])*
$Flag:ident;
@@ -192,7 +200,7 @@ macro_rules! __impl_external_bitflags_arbitrary {
fn arbitrary(
u: &mut $crate::__private::arbitrary::Unstructured<'a>,
) -> $crate::__private::arbitrary::Result<Self> {
- Self::from_bits(u.arbitrary()?).ok_or_else(|| $crate::__private::arbitrary::Error::IncorrectFormat)
+ $crate::arbitrary::arbitrary::<$PublicBitFlags>(u).map(|flags| flags.0)
}
}
};
@@ -203,12 +211,12 @@ macro_rules! __impl_external_bitflags_arbitrary {
#[cfg(not(feature = "arbitrary"))]
macro_rules! __impl_external_bitflags_arbitrary {
(
- $InternalBitFlags:ident: $T:ty {
- $(
- $(#[$attr:ident $($args:tt)*])*
- $Flag:ident;
- )*
- }
+ $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident {
+ $(
+ $(#[$attr:ident $($args:tt)*])*
+ $Flag:ident;
+ )*
+ }
) => {};
}
@@ -218,11 +226,11 @@ macro_rules! __impl_external_bitflags_arbitrary {
#[cfg(feature = "bytemuck")]
macro_rules! __impl_external_bitflags_bytemuck {
(
- $InternalBitFlags:ident: $T:ty {
+ $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident {
$(
$(#[$attr:ident $($args:tt)*])*
- $Flag:ident;
- )*
+ $Flag:ident;
+ )*
}
) => {
// SAFETY: $InternalBitFlags is guaranteed to have the same ABI as $T,
@@ -250,11 +258,11 @@ macro_rules! __impl_external_bitflags_bytemuck {
#[cfg(not(feature = "bytemuck"))]
macro_rules! __impl_external_bitflags_bytemuck {
(
- $InternalBitFlags:ident: $T:ty {
+ $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident {
$(
$(#[$attr:ident $($args:tt)*])*
- $Flag:ident;
- )*
+ $Flag:ident;
+ )*
}
) => {};
}
diff --git a/src/external/arbitrary_support.rs b/src/external/arbitrary.rs
index 56708f0..ae59677 100644
--- a/src/external/arbitrary_support.rs
+++ b/src/external/arbitrary.rs
@@ -1,3 +1,17 @@
+//! Specialized fuzzing for flags types using `arbitrary`.
+
+use crate::Flags;
+
+/// Get a random known flags value.
+pub fn arbitrary<'a, B: Flags>(
+ u: &mut arbitrary::Unstructured<'a>,
+) -> arbitrary::Result<B>
+where
+ B::Bits: arbitrary::Arbitrary<'a>
+{
+ B::from_bits(u.arbitrary()?).ok_or_else(|| arbitrary::Error::IncorrectFormat)
+}
+
#[cfg(test)]
mod tests {
use arbitrary::Arbitrary;
diff --git a/src/external/bytemuck_support.rs b/src/external/bytemuck.rs
index 5ab109e..5ab109e 100644
--- a/src/external/bytemuck_support.rs
+++ b/src/external/bytemuck.rs
diff --git a/src/external/serde_support.rs b/src/external/serde.rs
index 7c202a2..bc1f2ec 100644
--- a/src/external/serde_support.rs
+++ b/src/external/serde.rs
@@ -1,59 +1,66 @@
+//! Specialized serialization for flags types using `serde`.
+
use core::{fmt, str};
+use crate::{Flags, parser::{self, ParseHex, WriteHex}};
use serde::{
de::{Error, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
};
-pub fn serialize_bits_default<T: fmt::Display + AsRef<B>, B: Serialize, S: Serializer>(
- flags: &T,
+/// Serialize a set of flags as a human-readable string or their underlying bits.
+pub fn serialize<B: Flags, S: Serializer>(
+ flags: &B,
serializer: S,
-) -> Result<S::Ok, S::Error> {
+) -> Result<S::Ok, S::Error>
+where
+ B::Bits: WriteHex + Serialize,
+{
// Serialize human-readable flags as a string like `"A | B"`
if serializer.is_human_readable() {
- serializer.collect_str(flags)
+ serializer.collect_str(&parser::AsDisplay(flags))
}
// Serialize non-human-readable flags directly as the underlying bits
else {
- flags.as_ref().serialize(serializer)
+ flags.bits().serialize(serializer)
}
}
-pub fn deserialize_bits_default<
+/// Deserialize a set of flags from a human-readable string or their underlying bits.
+pub fn deserialize<
'de,
- T: str::FromStr + From<B>,
- B: Deserialize<'de>,
+ B: Flags,
D: Deserializer<'de>,
>(
deserializer: D,
-) -> Result<T, D::Error>
+) -> Result<B, D::Error>
where
- <T as str::FromStr>::Err: fmt::Display,
+ B::Bits: ParseHex + Deserialize<'de>,
{
if deserializer.is_human_readable() {
// Deserialize human-readable flags by parsing them from strings like `"A | B"`
- struct FlagsVisitor<T>(core::marker::PhantomData<T>);
+ struct FlagsVisitor<B>(core::marker::PhantomData<B>);
- impl<'de, T: str::FromStr> Visitor<'de> for FlagsVisitor<T>
+ impl<'de, B: Flags> Visitor<'de> for FlagsVisitor<B>
where
- <T as str::FromStr>::Err: fmt::Display,
+ B::Bits: ParseHex,
{
- type Value = T;
+ type Value = B;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a string value of `|` separated flags")
}
fn visit_str<E: Error>(self, flags: &str) -> Result<Self::Value, E> {
- flags.parse().map_err(|e| E::custom(e))
+ parser::from_str(flags).map_err(|e| E::custom(e))
}
}
deserializer.deserialize_str(FlagsVisitor(Default::default()))
} else {
// Deserialize non-human-readable flags directly from the underlying bits
- let bits = B::deserialize(deserializer)?;
+ let bits = B::Bits::deserialize(deserializer)?;
- Ok(bits.into())
+ Ok(B::from_bits_retain(bits))
}
}
diff --git a/src/internal.rs b/src/internal.rs
index eca0a30..c4fb653 100644
--- a/src/internal.rs
+++ b/src/internal.rs
@@ -10,29 +10,14 @@
#[doc(hidden)]
macro_rules! __declare_internal_bitflags {
(
- $vis:vis struct $InternalBitFlags:ident: $T:ty;
- $iter_vis:vis struct $Iter:ident;
- $iter_names_vis:vis struct $IterNames:ident;
+ $vis:vis struct $InternalBitFlags:ident: $T:ty
) => {
// NOTE: The ABI of this type is _guaranteed_ to be the same as `T`
// This is relied on by some external libraries like `bytemuck` to make
// its `unsafe` trait impls sound.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
- $vis struct $InternalBitFlags {
- bits: $T,
- }
-
- $iter_vis struct $Iter {
- inner: $IterNames,
- done: bool,
- }
-
- $iter_names_vis struct $IterNames {
- idx: usize,
- source: $InternalBitFlags,
- state: $InternalBitFlags,
- }
+ $vis struct $InternalBitFlags($T);
};
}
@@ -44,14 +29,18 @@ macro_rules! __declare_internal_bitflags {
#[doc(hidden)]
macro_rules! __impl_internal_bitflags {
(
- $InternalBitFlags:ident: $T:ty, $BitFlags:ident, $Iter:ident, $IterNames:ident {
+ $InternalBitFlags:ident: $T:ty, $PublicBitFlags:ident {
$(
$(#[$attr:ident $($args:tt)*])*
- $Flag:ident;
+ $Flag:ident = $value:expr;
)*
}
) => {
- impl $crate::__private::PublicFlags for $BitFlags {
+ // NOTE: This impl is also used to prevent using bits types from non-primitive types
+ // in the `bitflags` macro. If this approach is changed, this guard will need to be
+ // retained somehow
+ impl $crate::__private::PublicFlags for $PublicBitFlags {
+ type Primitive = $T;
type Internal = $InternalBitFlags;
}
@@ -73,7 +62,7 @@ macro_rules! __impl_internal_bitflags {
// We can remove this `0x0` and remain compatible with `FromStr`,
// because an empty string will still parse to an empty set of flags,
// just like `0x0` does.
- $crate::__private::core::write!(f, "{:#x}", <$T as $crate::__private::Bits>::EMPTY)
+ $crate::__private::core::write!(f, "{:#x}", <$T as $crate::Bits>::EMPTY)
} else {
$crate::__private::core::fmt::Display::fmt(self, f)
}
@@ -82,278 +71,21 @@ macro_rules! __impl_internal_bitflags {
impl $crate::__private::core::fmt::Display for $InternalBitFlags {
fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter<'_>) -> $crate::__private::core::fmt::Result {
- // A formatter for bitflags that produces text output like:
- //
- // A | B | 0xf6
- //
- // The names of set flags are written in a bar-separated-format,
- // followed by a hex number of any remaining bits that are set
- // but don't correspond to any flags.
-
- // Iterate over the valid flags
- let mut first = true;
- let mut iter = self.iter_names();
- for (name, _) in &mut iter {
- if !first {
- f.write_str(" | ")?;
- }
-
- first = false;
- f.write_str(name)?;
- }
-
- // Append any extra bits that correspond to flags to the end of the format
- let extra_bits = iter.state.bits();
- if extra_bits != <$T as $crate::__private::Bits>::EMPTY {
- if !first {
- f.write_str(" | ")?;
- }
-
- $crate::__private::core::write!(f, "{:#x}", extra_bits)?;
- }
-
- $crate::__private::core::fmt::Result::Ok(())
+ $crate::parser::to_writer(&$PublicBitFlags(*self), f)
}
}
- // The impl for `FromStr` should parse anything produced by `Display`
impl $crate::__private::core::str::FromStr for $InternalBitFlags {
type Err = $crate::parser::ParseError;
fn from_str(s: &str) -> $crate::__private::core::result::Result<Self, Self::Err> {
- let s = s.trim();
-
- let mut parsed_flags = Self::empty();
-
- // If the input is empty then return an empty set of flags
- if s.is_empty() {
- return $crate::__private::core::result::Result::Ok(parsed_flags);
- }
-
- for flag in s.split('|') {
- let flag = flag.trim();
-
- // If the flag is empty then we've got missing input
- if flag.is_empty() {
- return $crate::__private::core::result::Result::Err($crate::parser::ParseError::empty_flag());
- }
-
- // If the flag starts with `0x` then it's a hex number
- // Parse it directly to the underlying bits type
- let parsed_flag = if let $crate::__private::core::option::Option::Some(flag) = flag.strip_prefix("0x") {
- let bits = <$T>::from_str_radix(flag, 16).map_err(|_| $crate::parser::ParseError::invalid_hex_flag(flag))?;
-
- Self::from_bits_retain(bits)
- }
- // Otherwise the flag is a name
- // The generated flags type will determine whether
- // or not it's a valid identifier
- else {
- Self::from_name(flag).ok_or_else(|| $crate::parser::ParseError::invalid_named_flag(flag))?
- };
-
- parsed_flags.insert(parsed_flag);
- }
-
- $crate::__private::core::result::Result::Ok(parsed_flags)
- }
- }
-
- impl $crate::__private::core::fmt::Binary for $InternalBitFlags {
- fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result {
- $crate::__private::core::fmt::Binary::fmt(&self.bits(), f)
- }
- }
-
- impl $crate::__private::core::fmt::Octal for $InternalBitFlags {
- fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result {
- $crate::__private::core::fmt::Octal::fmt(&self.bits(), f)
- }
- }
-
- impl $crate::__private::core::fmt::LowerHex for $InternalBitFlags {
- fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result {
- $crate::__private::core::fmt::LowerHex::fmt(&self.bits(), f)
- }
- }
-
- impl $crate::__private::core::fmt::UpperHex for $InternalBitFlags {
- fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result {
- $crate::__private::core::fmt::UpperHex::fmt(&self.bits(), f)
- }
- }
-
- impl $InternalBitFlags {
- #[inline]
- pub const fn empty() -> Self {
- Self { bits: <$T as $crate::__private::Bits>::EMPTY }
- }
-
- #[inline]
- pub const fn all() -> Self {
- Self::from_bits_truncate(<$T as $crate::__private::Bits>::ALL)
- }
-
- #[inline]
- pub const fn bits(&self) -> $T {
- self.bits
- }
-
- #[inline]
- pub fn bits_mut(&mut self) -> &mut $T {
- &mut self.bits
- }
-
- #[inline]
- pub const fn from_bits(bits: $T) -> $crate::__private::core::option::Option<Self> {
- let truncated = Self::from_bits_truncate(bits).bits;
-
- if truncated == bits {
- $crate::__private::core::option::Option::Some(Self { bits })
- } else {
- $crate::__private::core::option::Option::None
- }
- }
-
- #[inline]
- pub const fn from_bits_truncate(bits: $T) -> Self {
- if bits == <$T as $crate::__private::Bits>::EMPTY {
- return Self { bits }
- }
-
- let mut truncated = <$T as $crate::__private::Bits>::EMPTY;
-
- $(
- __expr_safe_flags!(
- $(#[$attr $($args)*])*
- {
- if bits & $BitFlags::$Flag.bits() == $BitFlags::$Flag.bits() {
- truncated |= $BitFlags::$Flag.bits()
- }
- }
- );
- )*
-
- Self { bits: truncated }
- }
-
- #[inline]
- pub const fn from_bits_retain(bits: $T) -> Self {
- Self { bits }
- }
-
- #[inline]
- pub fn from_name(name: &str) -> $crate::__private::core::option::Option<Self> {
- $(
- __expr_safe_flags!(
- $(#[$attr $($args)*])*
- {
- if name == $crate::__private::core::stringify!($Flag) {
- return $crate::__private::core::option::Option::Some(Self { bits: $BitFlags::$Flag.bits() });
- }
- }
- );
- )*
-
- let _ = name;
- $crate::__private::core::option::Option::None
- }
-
- #[inline]
- pub const fn iter(&self) -> $Iter {
- $Iter {
- inner: self.iter_names(),
- done: false,
- }
- }
-
- #[inline]
- pub const fn iter_names(&self) -> $IterNames {
- $IterNames {
- idx: 0,
- source: *self,
- state: *self,
- }
- }
-
- #[inline]
- pub const fn is_empty(&self) -> bool {
- self.bits == Self::empty().bits
- }
-
- #[inline]
- pub const fn is_all(&self) -> bool {
- Self::all().bits | self.bits == self.bits
- }
-
- #[inline]
- pub const fn intersects(&self, other: Self) -> bool {
- !(Self { bits: self.bits & other.bits}).is_empty()
- }
-
- #[inline]
- pub const fn contains(&self, other: Self) -> bool {
- (self.bits & other.bits) == other.bits
- }
-
- #[inline]
- pub fn insert(&mut self, other: Self) {
- self.bits |= other.bits;
- }
-
- #[inline]
- pub fn remove(&mut self, other: Self) {
- self.bits &= !other.bits;
- }
-
- #[inline]
- pub fn toggle(&mut self, other: Self) {
- self.bits ^= other.bits;
- }
-
- #[inline]
- pub fn set(&mut self, other: Self, value: bool) {
- if value {
- self.insert(other);
- } else {
- self.remove(other);
- }
- }
-
- #[inline]
- #[must_use]
- pub const fn intersection(self, other: Self) -> Self {
- Self { bits: self.bits & other.bits }
- }
-
- #[inline]
- #[must_use]
- pub const fn union(self, other: Self) -> Self {
- Self { bits: self.bits | other.bits }
- }
-
- #[inline]
- #[must_use]
- pub const fn difference(self, other: Self) -> Self {
- Self { bits: self.bits & !other.bits }
- }
-
- #[inline]
- #[must_use]
- pub const fn symmetric_difference(self, other: Self) -> Self {
- Self { bits: self.bits ^ other.bits }
- }
-
- #[inline]
- #[must_use]
- pub const fn complement(self) -> Self {
- Self::from_bits_truncate(!self.bits)
+ $crate::parser::from_str::<$PublicBitFlags>(s).map(|flags| flags.0)
}
}
impl $crate::__private::core::convert::AsRef<$T> for $InternalBitFlags {
fn as_ref(&self) -> &$T {
- &self.bits
+ &self.0
}
}
@@ -363,208 +95,27 @@ macro_rules! __impl_internal_bitflags {
}
}
- impl $crate::__private::core::iter::Iterator for $Iter {
- type Item = $BitFlags;
-
- fn next(&mut self) -> $crate::__private::core::option::Option<Self::Item> {
- match self.inner.next().map(|(_, value)| value) {
- $crate::__private::core::option::Option::Some(value) => $crate::__private::core::option::Option::Some(value),
- $crate::__private::core::option::Option::None if !self.done => {
- self.done = true;
+ // The internal flags type offers a similar API to the public one
- // After iterating through valid names, if there are any bits left over
- // then return one final value that includes them. This makes `into_iter`
- // and `from_iter` roundtrip
- if self.inner.state != $InternalBitFlags::empty() {
- $crate::__private::core::option::Option::Some($BitFlags::from_bits_retain(self.inner.state.bits()))
- } else {
- $crate::__private::core::option::Option::None
- }
- },
- _ => $crate::__private::core::option::Option::None,
- }
+ __impl_public_bitflags! {
+ $InternalBitFlags: $T, $PublicBitFlags {
+ $(
+ $(#[$attr $($args)*])*
+ $Flag;
+ )*
}
}
- impl $crate::__private::core::iter::Iterator for $IterNames {
- type Item = (&'static str, $BitFlags);
-
- fn next(&mut self) -> $crate::__private::core::option::Option<Self::Item> {
- const NUM_FLAGS: usize = {
- let mut num_flags = 0;
-
- $(
- __expr_safe_flags!(
- $(#[$attr $($args)*])*
- {
- { num_flags += 1; }
- }
- );
- )*
-
- num_flags
- };
-
- const OPTIONS: [$T; NUM_FLAGS] = [
- $(
- __expr_safe_flags!(
- $(#[$attr $($args)*])*
- {
- $BitFlags::$Flag.bits()
- }
- ),
- )*
- ];
-
- const OPTIONS_NAMES: [&'static str; NUM_FLAGS] = [
- $(
- __expr_safe_flags!(
- $(#[$attr $($args)*])*
- {
- $crate::__private::core::stringify!($Flag)
- }
- ),
- )*
- ];
-
- if self.state.is_empty() || NUM_FLAGS == 0 {
- $crate::__private::core::option::Option::None
- } else {
- #[allow(clippy::indexing_slicing)]
- for (flag, flag_name) in OPTIONS[self.idx..NUM_FLAGS].iter().copied()
- .zip(OPTIONS_NAMES[self.idx..NUM_FLAGS].iter().copied())
- {
- self.idx += 1;
-
- // NOTE: We check whether the flag exists in self, but remove it from
- // a different value. This ensure that overlapping flags are handled
- // properly. Take the following example:
- //
- // const A: 0b00000001;
- // const B: 0b00000101;
- //
- // Given the bits 0b00000101, both A and B are set. But if we removed A
- // as we encountered it we'd be left with 0b00000100, which doesn't
- // correspond to a valid flag on its own.
- if self.source.contains($InternalBitFlags { bits: flag }) {
- self.state.remove($InternalBitFlags { bits: flag });
-
- return $crate::__private::core::option::Option::Some((flag_name, $BitFlags::from_bits_retain(flag)))
- }
- }
-
- $crate::__private::core::option::Option::None
- }
- }
+ __impl_public_bitflags_iter! {
+ $InternalBitFlags: $T, $PublicBitFlags
}
- };
-}
-/// A macro that processed the input to `bitflags!` and shuffles attributes around
-/// based on whether or not they're "expression-safe".
-///
-/// This macro is a token-tree muncher that works on 2 levels:
-///
-/// For each attribute, we explicitly match on its identifier, like `cfg` to determine
-/// whether or not it should be considered expression-safe.
-///
-/// If you find yourself with an attribute that should be considered expression-safe
-/// and isn't, it can be added here.
-#[macro_export(local_inner_macros)]
-#[doc(hidden)]
-macro_rules! __expr_safe_flags {
- // Entrypoint: Move all flags and all attributes into `unprocessed` lists
- // where they'll be munched one-at-a-time
- (
- $(#[$inner:ident $($args:tt)*])*
- { $e:expr }
- ) => {
- __expr_safe_flags! {
- expr: { $e },
- attrs: {
- // All attributes start here
- unprocessed: [$(#[$inner $($args)*])*],
- processed: {
- // Attributes that are safe on expressions go here
- expr: [],
- },
- },
- }
- };
- // Process the next attribute on the current flag
- // `cfg`: The next flag should be propagated to expressions
- // NOTE: You can copy this rules block and replace `cfg` with
- // your attribute name that should be considered expression-safe
- (
- expr: { $e:expr },
- attrs: {
- unprocessed: [
- // cfg matched here
- #[cfg $($args:tt)*]
- $($attrs_rest:tt)*
- ],
- processed: {
- expr: [$($expr:tt)*],
- },
- },
- ) => {
- __expr_safe_flags! {
- expr: { $e },
- attrs: {
- unprocessed: [
- $($attrs_rest)*
- ],
- processed: {
- expr: [
- $($expr)*
- // cfg added here
- #[cfg $($args)*]
- ],
- },
- },
- }
- };
- // Process the next attribute on the current flag
- // `$other`: The next flag should not be propagated to expressions
- (
- expr: { $e:expr },
- attrs: {
- unprocessed: [
- // $other matched here
- #[$other:ident $($args:tt)*]
- $($attrs_rest:tt)*
- ],
- processed: {
- expr: [$($expr:tt)*],
- },
- },
- ) => {
- __expr_safe_flags! {
- expr: { $e },
- attrs: {
- unprocessed: [
- $($attrs_rest)*
- ],
- processed: {
- expr: [
- // $other not added here
- $($expr)*
- ],
- },
- },
+ impl $InternalBitFlags {
+ /// Returns a mutable reference to the raw value of the flags currently stored.
+ #[inline]
+ pub fn bits_mut(&mut self) -> &mut $T {
+ &mut self.0
+ }
}
};
- // Once all attributes on all flags are processed, generate the actual code
- (
- expr: { $e:expr },
- attrs: {
- unprocessed: [],
- processed: {
- expr: [$(#[$expr:ident $($exprargs:tt)*])*],
- },
- },
- ) => {
- $(#[$expr $($exprargs)*])*
- { $e }
- }
}
diff --git a/src/iter.rs b/src/iter.rs
new file mode 100644
index 0000000..4b6210e
--- /dev/null
+++ b/src/iter.rs
@@ -0,0 +1,133 @@
+//! Iterating over set flag values.
+
+use crate::{Flags, Flag};
+
+/// An iterator over a set of flags.
+///
+/// Any bits that don't correspond to a valid flag will be yielded
+/// as a final item from the iterator.
+pub struct Iter<B: 'static> {
+ inner: IterNames<B>,
+ done: bool,
+}
+
+impl<B: Flags> Iter<B> {
+ /// Create a new iterator over the given set of flags.
+ pub(crate) fn new(flags: &B) -> Self {
+ Iter {
+ inner: IterNames::new(flags),
+ done: false,
+ }
+ }
+}
+
+impl<B: 'static> Iter<B> {
+ #[doc(hidden)]
+ pub const fn __private_const_new(flags: &'static [Flag<B>], source: B, state: B) -> Self {
+ Iter {
+ inner: IterNames::__private_const_new(flags, source, state),
+ done: false,
+ }
+ }
+}
+
+impl<B: Flags> Iterator for Iter<B> {
+ type Item = B;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ match self.inner.next() {
+ Some((_, flag)) => Some(flag),
+ None if !self.done => {
+ self.done = true;
+
+ // After iterating through valid names, if there are any bits left over
+ // then return one final value that includes them. This makes `into_iter`
+ // and `from_iter` roundtrip
+ if !self.inner.remaining().is_empty() {
+ Some(B::from_bits_retain(self.inner.state.bits()))
+ } else {
+ None
+ }
+ }
+ None => None,
+ }
+ }
+}
+
+/// An iterator over a set of flags and their names.
+///
+/// Any bits that don't correspond to a valid flag will be ignored.
+pub struct IterNames<B: 'static> {
+ flags: &'static [Flag<B>],
+ idx: usize,
+ source: B,
+ state: B,
+}
+
+impl<B: Flags> IterNames<B> {
+ /// Create a new iterator over the given set of flags.
+ pub(crate) fn new(flags: &B) -> Self {
+ IterNames {
+ flags: B::FLAGS,
+ idx: 0,
+ state: B::from_bits_retain(flags.bits()),
+ source: B::from_bits_retain(flags.bits()),
+ }
+ }
+}
+
+impl<B: 'static> IterNames<B> {
+ #[doc(hidden)]
+ pub const fn __private_const_new(flags: &'static [Flag<B>], source: B, state: B) -> Self {
+ IterNames {
+ flags,
+ idx: 0,
+ state,
+ source,
+ }
+ }
+
+ /// Get the remaining (unyielded) flags.
+ ///
+ /// Once the iterator has finished, this method can be used to
+ /// check whether or not there are any bits that didn't correspond
+ /// to a valid flag remaining.
+ pub fn remaining(&self) -> &B {
+ &self.state
+ }
+}
+
+impl<B: Flags> Iterator for IterNames<B> {
+ type Item = (&'static str, B);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ while let Some(flag) = self.flags.get(self.idx) {
+ // Short-circuit if our state is empty
+ if self.state.is_empty() {
+ return None;
+ }
+
+ self.idx += 1;
+
+ let bits = flag.value().bits();
+
+ // 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(B::from_bits_retain(bits)) {
+ self.state.remove(B::from_bits_retain(bits));
+
+ return Some((flag.name(), B::from_bits_retain(bits)));
+ }
+ }
+
+ None
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 35eabca..37d5540 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -281,7 +281,7 @@
//! use bitflags::bitflags;
//! use std::{fmt, str};
//!
-//! bitflags::bitflags! {
+//! bitflags! {
//! pub struct Flags: u32 {
//! const A = 1;
//! const B = 2;
@@ -374,16 +374,16 @@
//! }
//! ```
//!
-//! [`from_bits`]: BitFlags::from_bits
-//! [`from_bits_truncate`]: BitFlags::from_bits_truncate
+//! [`from_bits`]: Flags::from_bits
+//! [`from_bits_truncate`]: Flags::from_bits_truncate
//!
-//! # The `BitFlags` trait
+//! # The `Flags` trait
//!
-//! This library defines a `BitFlags` trait that's implemented by all generated flags types.
+//! This library defines a `Flags` trait that's implemented by all generated flags types.
//! The trait makes it possible to work with flags types generically:
//!
//! ```
-//! fn count_unset_flags<F: bitflags::BitFlags>(flags: &F) -> usize {
+//! fn count_unset_flags<F: bitflags::Flags>(flags: &F) -> usize {
//! // Find out how many flags there are in total
//! let total = F::all().iter().count();
//!
@@ -423,22 +423,29 @@
// ANDROID: Use std to allow building as a dylib.
#![cfg_attr(not(any(feature = "std", test, android_dylib)), no_std)]
#![cfg_attr(not(test), forbid(unsafe_code))]
-
-#![doc(html_root_url = "https://docs.rs/bitflags/2.2.1")]
+#![doc(html_root_url = "https://docs.rs/bitflags/2.3.2")]
#[doc(inline)]
-pub use traits::BitFlags;
+pub use traits::{Flags, Flag, Bits};
+pub mod iter;
pub mod parser;
+
mod traits;
#[doc(hidden)]
pub mod __private {
- pub use crate::{external::*, traits::*};
+ pub use crate::{external::__private::*, traits::__private::*};
pub use core;
}
+#[allow(unused_imports)]
+pub use external::*;
+
+#[allow(deprecated)]
+pub use traits::BitFlags;
+
/*
How does the bitflags crate work?
@@ -564,20 +571,14 @@ macro_rules! bitflags {
// This type appears in the end-user's API
__declare_public_bitflags! {
$(#[$outer])*
- $vis struct $BitFlags;
+ $vis struct $BitFlags
}
// Workaround for: https://github.com/bitflags/bitflags/issues/320
__impl_public_bitflags_consts! {
- $BitFlags {
+ $BitFlags: $T {
$(
$(#[$inner $($args)*])*
- #[allow(
- dead_code,
- deprecated,
- unused_attributes,
- non_upper_case_globals
- )]
$Flag = $value;
)*
}
@@ -590,29 +591,28 @@ macro_rules! bitflags {
unused_attributes,
unused_mut,
unused_imports,
- non_upper_case_globals
+ non_upper_case_globals,
+ clippy::assign_op_pattern
)]
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 InternalBitFlags: $T;
- $vis struct Iter;
- $vis struct IterRaw;
+ $vis struct InternalBitFlags: $T
}
__impl_internal_bitflags! {
- InternalBitFlags: $T, $BitFlags, Iter, IterRaw {
+ InternalBitFlags: $T, $BitFlags {
$(
$(#[$inner $($args)*])*
- $Flag;
+ $Flag = $value;
)*
}
}
// This is where new library trait implementations can be added
__impl_external_bitflags! {
- InternalBitFlags: $T {
+ InternalBitFlags: $T, $BitFlags {
$(
$(#[$inner $($args)*])*
$Flag;
@@ -620,8 +620,60 @@ macro_rules! bitflags {
}
}
+ __impl_public_bitflags_forward! {
+ $BitFlags: $T, InternalBitFlags
+ }
+
+ __impl_public_bitflags_iter! {
+ $BitFlags: $T, $BitFlags
+ }
+ };
+
+ bitflags! {
+ $($t)*
+ }
+ };
+ (
+ impl $BitFlags:ident: $T:ty {
+ $(
+ $(#[$inner:ident $($args:tt)*])*
+ const $Flag:ident = $value:expr;
+ )*
+ }
+
+ $($t:tt)*
+ ) => {
+ __impl_public_bitflags_consts! {
+ $BitFlags: $T {
+ $(
+ $(#[$inner $($args)*])*
+ $Flag = $value;
+ )*
+ }
+ }
+
+ #[allow(
+ dead_code,
+ deprecated,
+ unused_doc_comments,
+ unused_attributes,
+ unused_mut,
+ unused_imports,
+ non_upper_case_globals,
+ clippy::assign_op_pattern
+ )]
+ const _: () = {
__impl_public_bitflags! {
- $BitFlags: $T, InternalBitFlags, Iter, IterRaw;
+ $BitFlags: $T, $BitFlags {
+ $(
+ $(#[$inner $($args)*])*
+ $Flag;
+ )*
+ }
+ }
+
+ __impl_public_bitflags_iter! {
+ $BitFlags: $T, $BitFlags
}
};
@@ -632,6 +684,357 @@ macro_rules! bitflags {
() => {};
}
+/// Implement functions on bitflags types.
+///
+/// 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_bitflags {
+ (
+ $PublicBitFlags:ident: $T:ty {
+ fn empty() $empty:block
+ fn all() $all:block
+ fn bits($bits0:ident) $bits:block
+ fn from_bits($from_bits0:ident) $from_bits:block
+ fn from_bits_truncate($from_bits_truncate0:ident) $from_bits_truncate:block
+ fn from_bits_retain($from_bits_retain0:ident) $from_bits_retain:block
+ fn from_name($from_name0:ident) $from_name:block
+ fn is_empty($is_empty0:ident) $is_empty:block
+ fn is_all($is_all0:ident) $is_all:block
+ fn intersects($intersects0:ident, $intersects1:ident) $intersects:block
+ fn contains($contains0:ident, $contains1:ident) $contains:block
+ fn insert($insert0:ident, $insert1:ident) $insert:block
+ fn remove($remove0:ident, $remove1:ident) $remove:block
+ fn toggle($toggle0:ident, $toggle1:ident) $toggle:block
+ fn set($set0:ident, $set1:ident, $set2:ident) $set:block
+ fn intersection($intersection0:ident, $intersection1:ident) $intersection:block
+ fn union($union0:ident, $union1:ident) $union:block
+ fn difference($difference0:ident, $difference1:ident) $difference:block
+ fn symmetric_difference($symmetric_difference0:ident, $symmetric_difference1:ident) $symmetric_difference:block
+ fn complement($complement0:ident) $complement:block
+ }
+ ) => {
+ #[allow(
+ dead_code,
+ deprecated,
+ unused_attributes
+ )]
+ impl $PublicBitFlags {
+ /// Returns an empty set of flags.
+ #[inline]
+ pub const fn empty() -> Self {
+ $empty
+ }
+
+ /// Returns the set containing all flags.
+ #[inline]
+ pub const fn all() -> Self {
+ $all
+ }
+
+ /// Returns the raw value of the flags currently stored.
+ #[inline]
+ pub const fn bits(&self) -> $T {
+ let $bits0 = self;
+ $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<Self> {
+ let $from_bits0 = bits;
+ $from_bits
+ }
+
+ /// Convert from underlying bit representation, dropping any bits
+ /// that do not correspond to flags.
+ #[inline]
+ pub const fn from_bits_truncate(bits: $T) -> Self {
+ let $from_bits_truncate0 = bits;
+ $from_bits_truncate
+ }
+
+ /// Convert from underlying bit representation, preserving all
+ /// bits (even those not corresponding to a defined flag).
+ #[inline]
+ pub const fn from_bits_retain(bits: $T) -> Self {
+ let $from_bits_retain0 = bits;
+ $from_bits_retain
+ }
+
+ /// Get the value for a flag from its stringified name.
+ ///
+ /// Names are _case-sensitive_, so must correspond exactly to
+ /// the identifier given to the flag.
+ #[inline]
+ pub fn from_name(name: &str) -> $crate::__private::core::option::Option<Self> {
+ let $from_name0 = name;
+ $from_name
+ }
+
+ /// Returns `true` if no flags are currently stored.
+ #[inline]
+ pub const fn is_empty(&self) -> bool {
+ let $is_empty0 = self;
+ $is_empty
+ }
+
+ /// Returns `true` if all flags are currently set.
+ #[inline]
+ pub const fn is_all(&self) -> bool {
+ let $is_all0 = self;
+ $is_all
+ }
+
+ /// Returns `true` if there are flags common to both `self` and `other`.
+ #[inline]
+ pub const fn intersects(&self, other: Self) -> bool {
+ let $intersects0 = self;
+ let $intersects1 = other;
+ $intersects
+ }
+
+ /// Returns `true` if all of the flags in `other` are contained within `self`.
+ #[inline]
+ pub const fn contains(&self, other: Self) -> bool {
+ let $contains0 = self;
+ let $contains1 = other;
+ $contains
+ }
+
+ /// Inserts the specified flags in-place.
+ #[inline]
+ pub fn insert(&mut self, other: Self) {
+ let $insert0 = self;
+ let $insert1 = other;
+ $insert
+ }
+
+ /// Removes the specified flags in-place.
+ #[inline]
+ pub fn remove(&mut self, other: Self) {
+ let $remove0 = self;
+ let $remove1 = other;
+ $remove
+ }
+
+ /// Toggles the specified flags in-place.
+ #[inline]
+ pub fn toggle(&mut self, other: Self) {
+ let $toggle0 = self;
+ let $toggle1 = other;
+ $toggle
+ }
+
+ /// Inserts or removes the specified flags depending on the passed value.
+ #[inline]
+ pub fn set(&mut self, other: Self, value: bool) {
+ let $set0 = self;
+ let $set1 = other;
+ let $set2 = value;
+ $set
+ }
+
+ /// 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 {
+ let $intersection0 = self;
+ let $intersection1 = other;
+ $intersection
+ }
+
+ /// 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 {
+ let $union0 = self;
+ let $union1 = other;
+ $union
+ }
+
+ /// 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 {
+ let $difference0 = self;
+ let $difference1 = other;
+ $difference
+ }
+
+ /// 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 {
+ let $symmetric_difference0 = self;
+ let $symmetric_difference1 = other;
+ $symmetric_difference
+ }
+
+ /// 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 {
+ let $complement0 = self;
+ $complement
+ }
+ }
+ };
+}
+
+/// A macro that processed the input to `bitflags!` and shuffles attributes around
+/// based on whether or not they're "expression-safe".
+///
+/// This macro is a token-tree muncher that works on 2 levels:
+///
+/// For each attribute, we explicitly match on its identifier, like `cfg` to determine
+/// whether or not it should be considered expression-safe.
+///
+/// If you find yourself with an attribute that should be considered expression-safe
+/// and isn't, it can be added here.
+#[macro_export(local_inner_macros)]
+#[doc(hidden)]
+macro_rules! __bitflags_expr_safe_attrs {
+ // Entrypoint: Move all flags and all attributes into `unprocessed` lists
+ // where they'll be munched one-at-a-time
+ (
+ $(#[$inner:ident $($args:tt)*])*
+ { $e:expr }
+ ) => {
+ __bitflags_expr_safe_attrs! {
+ expr: { $e },
+ attrs: {
+ // All attributes start here
+ unprocessed: [$(#[$inner $($args)*])*],
+ // Attributes that are safe on expressions go here
+ processed: [],
+ },
+ }
+ };
+ // Process the next attribute on the current flag
+ // `cfg`: The next flag should be propagated to expressions
+ // NOTE: You can copy this rules block and replace `cfg` with
+ // your attribute name that should be considered expression-safe
+ (
+ expr: { $e:expr },
+ attrs: {
+ unprocessed: [
+ // cfg matched here
+ #[cfg $($args:tt)*]
+ $($attrs_rest:tt)*
+ ],
+ processed: [$($expr:tt)*],
+ },
+ ) => {
+ __bitflags_expr_safe_attrs! {
+ expr: { $e },
+ attrs: {
+ unprocessed: [
+ $($attrs_rest)*
+ ],
+ processed: [
+ $($expr)*
+ // cfg added here
+ #[cfg $($args)*]
+ ],
+ },
+ }
+ };
+ // Process the next attribute on the current flag
+ // `$other`: The next flag should not be propagated to expressions
+ (
+ expr: { $e:expr },
+ attrs: {
+ unprocessed: [
+ // $other matched here
+ #[$other:ident $($args:tt)*]
+ $($attrs_rest:tt)*
+ ],
+ processed: [$($expr:tt)*],
+ },
+ ) => {
+ __bitflags_expr_safe_attrs! {
+ expr: { $e },
+ attrs: {
+ unprocessed: [
+ $($attrs_rest)*
+ ],
+ processed: [
+ // $other not added here
+ $($expr)*
+ ],
+ },
+ }
+ };
+ // Once all attributes on all flags are processed, generate the actual code
+ (
+ expr: { $e:expr },
+ attrs: {
+ unprocessed: [],
+ processed: [$(#[$expr:ident $($exprargs:tt)*])*],
+ },
+ ) => {
+ $(#[$expr $($exprargs)*])*
+ { $e }
+ }
+}
+
#[macro_use]
mod public;
#[macro_use]
@@ -651,6 +1054,9 @@ mod tests {
str,
};
+ #[derive(Debug, PartialEq, Eq)]
+ pub struct ManualFlags(u32);
+
bitflags! {
#[doc = "> The first principle is that you must not fool yourself — and"]
#[doc = "> you are the easiest person to fool."]
@@ -687,6 +1093,17 @@ mod tests {
struct LongFlags: u32 {
const LONG_A = 0b1111111111111111;
}
+
+ impl ManualFlags: u32 {
+ const A = 0b00000001;
+ #[doc = "<pcwalton> macros are way better at generating code than trans is"]
+ const B = 0b00000010;
+ const C = 0b00000100;
+ #[doc = "* cmr bed"]
+ #[doc = "* strcat table"]
+ #[doc = "<strcat> wait what?"]
+ const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits();
+ }
}
bitflags! {
@@ -725,6 +1142,8 @@ mod tests {
assert_eq!(Flags::A.bits(), 0b00000001);
assert_eq!(Flags::ABC.bits(), 0b00000111);
+ assert_eq!(<Flags as crate::Flags>::bits(&Flags::ABC), 0b00000111);
+
assert_eq!(AnotherSetOfFlags::empty().bits(), 0b00);
assert_eq!(AnotherSetOfFlags::ANOTHER_FLAG.bits(), !0_i8);
@@ -739,6 +1158,8 @@ mod tests {
assert_eq!(Flags::from_bits(0b11), Some(Flags::A | Flags::B));
assert_eq!(Flags::from_bits(0b1000), None);
+ assert_eq!(<Flags as crate::Flags>::from_bits(0b11), Some(Flags::A | Flags::B));
+
assert_eq!(
AnotherSetOfFlags::from_bits(!0_i8),
Some(AnotherSetOfFlags::ANOTHER_FLAG)
@@ -757,6 +1178,8 @@ mod tests {
assert_eq!(Flags::from_bits_truncate(0b1000), Flags::empty());
assert_eq!(Flags::from_bits_truncate(0b1001), Flags::A);
+ assert_eq!(<Flags as crate::Flags>::from_bits_truncate(0b11), (Flags::A | Flags::B));
+
assert_eq!(
AnotherSetOfFlags::from_bits_truncate(0_i8),
AnotherSetOfFlags::empty()
@@ -777,6 +1200,8 @@ mod tests {
assert_eq!(Flags::from_bits_retain(0b1000), (extra | Flags::empty()));
assert_eq!(Flags::from_bits_retain(0b1001), (extra | Flags::A));
+ assert_eq!(<Flags as crate::Flags>::from_bits_retain(0b11), (Flags::A | Flags::B));
+
let extra = EmptyFlags::from_bits_retain(0b1000);
assert_eq!(
EmptyFlags::from_bits_retain(0b1000),
@@ -790,6 +1215,8 @@ mod tests {
assert!(!Flags::A.is_empty());
assert!(!Flags::ABC.is_empty());
+ assert!(!<Flags as crate::Flags>::is_empty(&Flags::ABC));
+
assert!(!AnotherSetOfFlags::ANOTHER_FLAG.is_empty());
assert!(EmptyFlags::empty().is_empty());
@@ -807,6 +1234,8 @@ mod tests {
assert!(!(Flags::A | extra).is_all());
assert!((Flags::ABC | extra).is_all());
+ assert!(<Flags as crate::Flags>::is_all(&Flags::all()));
+
assert!(AnotherSetOfFlags::ANOTHER_FLAG.is_all());
assert!(EmptyFlags::all().is_all());
@@ -819,6 +1248,8 @@ mod tests {
let e2 = Flags::empty();
assert!(!e1.intersects(e2));
+ assert!(!<Flags as crate::Flags>::intersects(&e1, e2));
+
assert!(AnotherSetOfFlags::ANOTHER_FLAG.intersects(AnotherSetOfFlags::ANOTHER_FLAG));
}
@@ -827,6 +1258,8 @@ mod tests {
let e1 = Flags::empty();
let e2 = Flags::ABC;
assert!(!e1.intersects(e2));
+
+ assert!(!<Flags as crate::Flags>::intersects(&e1, e2));
}
#[test]
@@ -834,6 +1267,8 @@ mod tests {
let e1 = Flags::A;
let e2 = Flags::B;
assert!(!e1.intersects(e2));
+
+ assert!(!<Flags as crate::Flags>::intersects(&e1, e2));
}
#[test]
@@ -841,6 +1276,8 @@ mod tests {
let e1 = Flags::A;
let e2 = Flags::A | Flags::B;
assert!(e1.intersects(e2));
+
+ assert!(<Flags as crate::Flags>::intersects(&e1, e2));
}
#[test]
@@ -851,6 +1288,8 @@ mod tests {
assert!(e2.contains(e1));
assert!(Flags::ABC.contains(e2));
+ assert!(<Flags as crate::Flags>::contains(&Flags::ABC, e2));
+
assert!(AnotherSetOfFlags::ANOTHER_FLAG.contains(AnotherSetOfFlags::ANOTHER_FLAG));
assert!(EmptyFlags::empty().contains(EmptyFlags::empty()));
@@ -863,6 +1302,11 @@ mod tests {
e1.insert(e2);
assert_eq!(e1, e2);
+ let mut e1 = Flags::A;
+ let e2 = Flags::A | Flags::B;
+ <Flags as crate::Flags>::insert(&mut e1, e2);
+ assert_eq!(e1, e2);
+
let mut e3 = AnotherSetOfFlags::empty();
e3.insert(AnotherSetOfFlags::ANOTHER_FLAG);
assert_eq!(e3, AnotherSetOfFlags::ANOTHER_FLAG);
@@ -875,6 +1319,11 @@ mod tests {
e1.remove(e2);
assert_eq!(e1, Flags::B);
+ let mut e1 = Flags::A | Flags::B;
+ let e2 = Flags::A | Flags::C;
+ <Flags as crate::Flags>::remove(&mut e1, e2);
+ assert_eq!(e1, Flags::B);
+
let mut e3 = AnotherSetOfFlags::ANOTHER_FLAG;
e3.remove(AnotherSetOfFlags::ANOTHER_FLAG);
assert_eq!(e3, AnotherSetOfFlags::empty());
@@ -927,6 +1376,8 @@ mod tests {
assert_eq!(ac, Flags::C.union(Flags::A));
assert_eq!(bc, Flags::C.union(Flags::B));
+ assert_eq!(ac, <Flags as crate::Flags>::union(Flags::A, Flags::C));
+
assert_eq!(ac, Flags::A | Flags::C);
assert_eq!(bc, Flags::B | Flags::C);
assert_eq!(ab.union(bc), Flags::ABC);
@@ -942,15 +1393,24 @@ mod tests {
assert_eq!(ac.intersection(bc), Flags::C);
assert_eq!(bc.intersection(ac), Flags::C);
+ assert_eq!(Flags::C, <Flags as crate::Flags>::intersection(ac, bc));
+
assert_eq!(ac.difference(bc), ac - bc);
assert_eq!(bc.difference(ac), bc - ac);
assert_eq!(ac.difference(bc), Flags::A);
assert_eq!(bc.difference(ac), Flags::B);
+ assert_eq!(bc, <Flags as crate::Flags>::difference(bc, Flags::A));
+
assert_eq!(bc.complement(), !bc);
assert_eq!(bc.complement(), Flags::A);
+
+ assert_eq!(Flags::A, <Flags as crate::Flags>::complement(bc));
+
assert_eq!(ac.symmetric_difference(bc), Flags::A.union(Flags::B));
assert_eq!(bc.symmetric_difference(ac), Flags::A.union(Flags::B));
+
+ assert_eq!(ab, <Flags as crate::Flags>::symmetric_difference(ac, bc));
}
#[test]
@@ -1288,7 +1748,6 @@ mod tests {
parse_case(FmtFlags::empty(), "");
parse_case(FmtFlags::empty(), " \r\n\t");
parse_case(FmtFlags::empty(), "0x0");
- parse_case(FmtFlags::empty(), "0x0");
parse_case(FmtFlags::고양이, "고양이");
parse_case(FmtFlags::고양이, " 고양이 ");
diff --git a/src/parser.rs b/src/parser.rs
index 48f3c61..aac9042 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -28,7 +28,118 @@
#![allow(clippy::let_unit_value)]
-use core::fmt;
+use core::fmt::{self, Write};
+
+use crate::{Flags, Bits};
+
+/// Write a set of flags to a writer.
+///
+/// Any bits that don't correspond to a valid flag will be formatted
+/// as a hex number.
+pub fn to_writer<B: Flags>(flags: &B, mut writer: impl Write) -> Result<(), fmt::Error>
+where
+ B::Bits: WriteHex,
+{
+ // A formatter for bitflags that produces text output like:
+ //
+ // A | B | 0xf6
+ //
+ // The names of set flags are written in a bar-separated-format,
+ // followed by a hex number of any remaining bits that are set
+ // but don't correspond to any flags.
+
+ // Iterate over the valid flags
+ let mut first = true;
+ let mut iter = flags.iter_names();
+ for (name, _) in &mut iter {
+ if !first {
+ writer.write_str(" | ")?;
+ }
+
+ first = false;
+ writer.write_str(name)?;
+ }
+
+ // Append any extra bits that correspond to flags to the end of the format
+ let remaining = iter.remaining().bits();
+ if remaining != B::Bits::EMPTY {
+ if !first {
+ writer.write_str(" | ")?;
+ }
+
+ writer.write_str("0x")?;
+ remaining.write_hex(writer)?;
+ }
+
+ fmt::Result::Ok(())
+}
+
+pub(crate) struct AsDisplay<'a, B>(pub(crate) &'a B);
+
+impl<'a, B: Flags> fmt::Display for AsDisplay<'a, B>
+where
+ B::Bits: WriteHex,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ to_writer(self.0, f)
+ }
+}
+
+/// Parse a set of flags from text.
+///
+/// This function will fail on unknown flags rather than ignore them.
+pub fn from_str<B: Flags>(input: &str) -> Result<B, ParseError>
+where
+ B::Bits: ParseHex,
+{
+ let mut parsed_flags = B::empty();
+
+ // If the input is empty then return an empty set of flags
+ if input.trim().is_empty() {
+ return Ok(parsed_flags);
+ }
+
+ for flag in input.split('|') {
+ let flag = flag.trim();
+
+ // If the flag is empty then we've got missing input
+ if flag.is_empty() {
+ return Err(ParseError::empty_flag());
+ }
+
+ // If the flag starts with `0x` then it's a hex number
+ // Parse it directly to the underlying bits type
+ let parsed_flag = if let Some(flag) = flag.strip_prefix("0x") {
+ let bits = <B::Bits>::parse_hex(flag).map_err(|_| ParseError::invalid_hex_flag(flag))?;
+
+ B::from_bits_retain(bits)
+ }
+ // Otherwise the flag is a name
+ // The generated flags type will determine whether
+ // or not it's a valid identifier
+ else {
+ B::from_name(flag).ok_or_else(|| ParseError::invalid_named_flag(flag))?
+ };
+
+ parsed_flags.insert(parsed_flag);
+ }
+
+ Ok(parsed_flags)
+}
+
+/// Encode a value as a hex number.
+pub trait WriteHex {
+ /// Write the value as hex.
+ fn write_hex<W: fmt::Write>(&self, writer: W) -> fmt::Result;
+}
+
+/// Parse a value from a number encoded as a hex string.
+pub trait ParseHex {
+ /// Parse the value from hex.
+ fn parse_hex(input: &str) -> Result<Self, ParseError>
+ where
+ Self: Sized;
+}
/// An error encountered while parsing flags from text.
#[derive(Debug)]
diff --git a/src/public.rs b/src/public.rs
index 643f843..57ab0ea 100644
--- a/src/public.rs
+++ b/src/public.rs
@@ -11,10 +11,10 @@
macro_rules! __declare_public_bitflags {
(
$(#[$outer:meta])*
- $vis:vis struct $BitFlags:ident;
+ $vis:vis struct $PublicBitFlags:ident
) => {
$(#[$outer])*
- $vis struct $BitFlags(<$BitFlags as $crate::__private::PublicFlags>::Internal);
+ $vis struct $PublicBitFlags(<$PublicBitFlags as $crate::__private::PublicFlags>::Internal);
};
}
@@ -24,236 +24,302 @@ macro_rules! __declare_public_bitflags {
/// could conflict with items added by the end-user.
#[macro_export(local_inner_macros)]
#[doc(hidden)]
-macro_rules! __impl_public_bitflags {
+macro_rules! __impl_public_bitflags_forward {
(
- $PublicBitFlags:ident: $T:ty, $InternalBitFlags:ident, $Iter:ident, $IterNames:ident;
+ $PublicBitFlags:ident: $T:ty, $InternalBitFlags:ident
) => {
- 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_bitflags! {
+ $PublicBitFlags: $T {
+ fn empty() {
+ Self($InternalBitFlags::empty())
+ }
- 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)
- }
- }
+ fn all() {
+ Self($InternalBitFlags::all())
+ }
- 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)
+ fn bits(f) {
+ f.0.bits()
+ }
+
+ fn 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,
+ }
+ }
+
+ fn from_bits_truncate(bits) {
+ Self($InternalBitFlags::from_bits_truncate(bits))
+ }
+
+ fn from_bits_retain(bits) {
+ Self($InternalBitFlags::from_bits_retain(bits))
+ }
+
+ fn from_name(name) {
+ match $InternalBitFlags::from_name(name) {
+ $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,
+ }
+ }
+
+ fn is_empty(f) {
+ f.0.is_empty()
+ }
+
+ fn is_all(f) {
+ f.0.is_all()
+ }
+
+ fn intersects(f, other) {
+ f.0.intersects(other.0)
+ }
+
+ fn contains(f, other) {
+ f.0.contains(other.0)
+ }
+
+ fn insert(f, other) {
+ f.0.insert(other.0)
+ }
+
+ fn remove(f, other) {
+ f.0.remove(other.0)
+ }
+
+ fn toggle(f, other) {
+ f.0.toggle(other.0)
+ }
+
+ fn set(f, other, value) {
+ f.0.set(other.0, value)
+ }
+
+ fn intersection(f, other) {
+ Self(f.0.intersection(other.0))
+ }
+
+ fn union(f, other) {
+ Self(f.0.union(other.0))
+ }
+
+ fn difference(f, other) {
+ Self(f.0.difference(other.0))
+ }
+
+ fn symmetric_difference(f, other) {
+ Self(f.0.symmetric_difference(other.0))
+ }
+
+ fn complement(f) {
+ Self(f.0.complement())
+ }
}
}
- 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_public_bitflags_ops!($PublicBitFlags);
+ };
+}
+
+/// 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 {
+ (
+ $BitFlags:ident: $T:ty, $PublicBitFlags:ident {
+ $(
+ $(#[$attr:ident $($args:tt)*])*
+ $Flag:ident;
+ )*
}
+ ) => {
+ __impl_bitflags! {
+ $BitFlags: $T {
+ fn empty() {
+ Self(<$T as $crate::Bits>::EMPTY)
+ }
- impl $PublicBitFlags {
- /// Returns an empty set of flags.
- #[inline]
- pub const fn empty() -> Self {
- Self($InternalBitFlags::empty())
- }
+ fn all() {
+ Self::from_bits_truncate(<$T as $crate::Bits>::ALL)
+ }
- /// Returns the set containing all flags.
- #[inline]
- pub const fn all() -> Self {
- Self($InternalBitFlags::all())
- }
+ fn bits(f) {
+ f.0
+ }
- /// Returns the raw value of the flags currently stored.
- #[inline]
- pub const fn bits(&self) -> $T {
- self.0.bits()
- }
+ fn from_bits(bits) {
+ let truncated = Self::from_bits_truncate(bits).0;
- /// 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<Self> {
- 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,
+ if truncated == bits {
+ $crate::__private::core::option::Option::Some(Self(bits))
+ } else {
+ $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))
- }
+ fn from_bits_truncate(bits) {
+ if bits == <$T as $crate::Bits>::EMPTY {
+ return Self(bits)
+ }
+
+ let mut truncated = <$T as $crate::Bits>::EMPTY;
+
+ $(
+ __bitflags_expr_safe_attrs!(
+ $(#[$attr $($args)*])*
+ {
+ if bits & $PublicBitFlags::$Flag.bits() == $PublicBitFlags::$Flag.bits() {
+ truncated = truncated | $PublicBitFlags::$Flag.bits()
+ }
+ }
+ );
+ )*
+
+ Self(truncated)
+ }
- /// Convert from underlying bit representation, preserving all
- /// bits (even those not corresponding to a defined flag).
- #[inline]
- pub const fn from_bits_retain(bits: $T) -> Self {
- Self($InternalBitFlags::from_bits_retain(bits))
- }
+ fn from_bits_retain(bits) {
+ Self(bits)
+ }
- /// Get the value for a flag from its stringified name.
- ///
- /// Names are _case-sensitive_, so must correspond exactly to
- /// the identifier given to the flag.
- #[inline]
- pub fn from_name(name: &str) -> $crate::__private::core::option::Option<Self> {
- match $InternalBitFlags::from_name(name) {
- $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,
+ fn from_name(name) {
+ $(
+ __bitflags_expr_safe_attrs!(
+ $(#[$attr $($args)*])*
+ {
+ if name == $crate::__private::core::stringify!($Flag) {
+ return $crate::__private::core::option::Option::Some(Self($PublicBitFlags::$Flag.bits()));
+ }
+ }
+ );
+ )*
+
+ let _ = name;
+ $crate::__private::core::option::Option::None
}
- }
- /// Iterate over enabled flag values.
- #[inline]
- pub const fn iter(&self) -> $Iter {
- self.0.iter()
- }
+ fn is_empty(f) {
+ f.0 == Self::empty().0
+ }
- /// Iterate over enabled flag values with their stringified names.
- #[inline]
- pub const fn iter_names(&self) -> $IterNames {
- self.0.iter_names()
- }
+ fn is_all(f) {
+ Self::all().0 | f.0 == f.0
+ }
- /// Returns `true` if no flags are currently stored.
- #[inline]
- pub const fn is_empty(&self) -> bool {
- self.0.is_empty()
- }
+ fn intersects(f, other) {
+ !(Self(f.0 & other.0)).is_empty()
+ }
- /// Returns `true` if all flags are currently set.
- #[inline]
- pub const fn is_all(&self) -> bool {
- self.0.is_all()
- }
+ fn contains(f, other) {
+ (f.0 & other.0) == other.0
+ }
- /// 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)
- }
+ fn insert(f, other) {
+ f.0 = f.0 | 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)
- }
+ fn remove(f, other) {
+ f.0 = f.0 & !other.0;
+ }
- /// Inserts the specified flags in-place.
- #[inline]
- pub fn insert(&mut self, other: Self) {
- self.0.insert(other.0)
- }
+ fn toggle(f, other) {
+ f.0 = f.0 ^ other.0;
+ }
- /// Removes the specified flags in-place.
- #[inline]
- pub fn remove(&mut self, other: Self) {
- self.0.remove(other.0)
+ fn set(f, other, value) {
+ if value {
+ f.insert(other);
+ } else {
+ f.remove(other);
+ }
+ }
+
+ fn intersection(f, other) {
+ Self(f.0 & other.0)
+ }
+
+ fn union(f, other) {
+ Self(f.0 | other.0)
+ }
+
+ fn difference(f, other) {
+ Self(f.0 & !other.0)
+ }
+
+ fn symmetric_difference(f, other) {
+ Self(f.0 ^ other.0)
+ }
+
+ fn complement(f) {
+ Self::from_bits_truncate(!f.0)
+ }
}
+ }
+
+ __impl_public_bitflags_ops!($BitFlags);
+ };
+}
- /// Toggles the specified flags in-place.
+/// Implement iterators on the public (user-facing) bitflags type.
+#[macro_export(local_inner_macros)]
+#[doc(hidden)]
+macro_rules! __impl_public_bitflags_iter {
+ ($BitFlags:ident: $T:ty, $PublicBitFlags:ident) => {
+ impl $BitFlags {
+ /// Iterate over enabled flag values.
#[inline]
- pub fn toggle(&mut self, other: Self) {
- self.0.toggle(other.0)
+ pub const fn iter(&self) -> $crate::iter::Iter<$PublicBitFlags> {
+ $crate::iter::Iter::__private_const_new(<$PublicBitFlags as $crate::Flags>::FLAGS, $PublicBitFlags::from_bits_retain(self.bits()), $PublicBitFlags::from_bits_retain(self.bits()))
}
- /// Inserts or removes the specified flags depending on the passed value.
+ /// Iterate over enabled flag values with their stringified names.
#[inline]
- pub fn set(&mut self, other: Self, value: bool) {
- self.0.set(other.0, value)
+ pub const fn iter_names(&self) -> $crate::iter::IterNames<$PublicBitFlags> {
+ $crate::iter::IterNames::__private_const_new(<$PublicBitFlags as $crate::Flags>::FLAGS, $PublicBitFlags::from_bits_retain(self.bits()), $PublicBitFlags::from_bits_retain(self.bits()))
}
+ }
- /// 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))
+ impl $crate::__private::core::iter::IntoIterator for $BitFlags {
+ type Item = $PublicBitFlags;
+ type IntoIter = $crate::iter::Iter<$PublicBitFlags>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter()
}
+ }
+ };
+}
- /// 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))
+/// Implement traits on the public (user-facing) bitflags type.
+#[macro_export(local_inner_macros)]
+#[doc(hidden)]
+macro_rules! __impl_public_bitflags_ops {
+ ($PublicBitFlags:ident) => {
+ 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)
}
+ }
- /// 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))
+ 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)
}
+ }
- /// 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))
+ 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)
}
+ }
- /// 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::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)
}
}
@@ -271,7 +337,7 @@ macro_rules! __impl_public_bitflags {
/// Adds the set of flags.
#[inline]
fn bitor_assign(&mut self, other: Self) {
- self.0 = self.0.union(other.0);
+ self.0 = self.0 | other.0;
}
}
@@ -289,7 +355,7 @@ macro_rules! __impl_public_bitflags {
/// Toggles the set of flags.
#[inline]
fn bitxor_assign(&mut self, other: Self) {
- self.0 = self.0.symmetric_difference(other.0);
+ self.0 = self.0 ^ other.0
}
}
@@ -307,7 +373,7 @@ macro_rules! __impl_public_bitflags {
/// Disables all flags disabled in the set.
#[inline]
fn bitand_assign(&mut self, other: Self) {
- self.0 = self.0.intersection(other.0);
+ self.0 = self.0 & other.0;
}
}
@@ -325,7 +391,7 @@ macro_rules! __impl_public_bitflags {
/// Disables all flags enabled in the set.
#[inline]
fn sub_assign(&mut self, other: Self) {
- self.0 = self.0.difference(other.0);
+ self.0 = self.0 & !other.0;
}
}
@@ -356,92 +422,6 @@ macro_rules! __impl_public_bitflags {
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 IterNames = $IterNames;
-
- 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 from_name(name: &str) -> $crate::__private::core::option::Option<$PublicBitFlags> {
- $PublicBitFlags::from_name(name)
- }
-
- fn iter(&self) -> Self::Iter {
- $PublicBitFlags::iter(self)
- }
-
- fn iter_names(&self) -> Self::IterNames {
- $PublicBitFlags::iter_names(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 {}
};
}
@@ -450,7 +430,7 @@ macro_rules! __impl_public_bitflags {
#[doc(hidden)]
macro_rules! __impl_public_bitflags_consts {
(
- $PublicBitFlags:ident {
+ $PublicBitFlags:ident: $T:ty {
$(
$(#[$attr:ident $($args:tt)*])*
$Flag:ident = $value:expr;
@@ -460,8 +440,39 @@ macro_rules! __impl_public_bitflags_consts {
impl $PublicBitFlags {
$(
$(#[$attr $($args)*])*
+ #[allow(
+ deprecated,
+ non_upper_case_globals,
+ )]
pub const $Flag: Self = Self::from_bits_retain($value);
)*
}
+
+ impl $crate::Flags for $PublicBitFlags {
+ const FLAGS: &'static [$crate::Flag<$PublicBitFlags>] = &[
+ $(
+ __bitflags_expr_safe_attrs!(
+ $(#[$attr $($args)*])*
+ {
+ #[allow(
+ deprecated,
+ non_upper_case_globals,
+ )]
+ $crate::Flag::new($crate::__private::core::stringify!($Flag), $PublicBitFlags::$Flag)
+ }
+ ),
+ )*
+ ];
+
+ type Bits = $T;
+
+ fn bits(&self) -> $T {
+ $PublicBitFlags::bits(self)
+ }
+
+ fn from_bits_retain(bits: $T) -> $PublicBitFlags {
+ $PublicBitFlags::from_bits_retain(bits)
+ }
+ }
};
}
diff --git a/src/traits.rs b/src/traits.rs
index 85503e6..f8fc757 100644
--- a/src/traits.rs
+++ b/src/traits.rs
@@ -1,23 +1,50 @@
-use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};
+use core::{fmt, ops::{BitAnd, BitOr, BitXor, Not}};
-/// A trait that is automatically implemented for all bitflags.
-///
-/// It should not be implemented manually.
-pub trait BitFlags: ImplementedByBitFlagsMacro {
- /// The underlying integer type.
- type Bits: Bits;
+use crate::{parser::{ParseError, ParseHex, WriteHex}, iter};
- /// An iterator over enabled flags in an instance of the type.
- type Iter: Iterator<Item = Self>;
+/// Metadata for an individual flag.
+pub struct Flag<B> {
+ name: &'static str,
+ value: B,
+}
- /// An iterator over the raw names and bits for enabled flags in an instance of the type.
- type IterNames: Iterator<Item = (&'static str, Self)>;
+impl<B> Flag<B> {
+ /// Create a new flag with the given name and value.
+ pub const fn new(name: &'static str, value: B) -> Self {
+ Flag { name, value }
+ }
+
+ /// Get the name of this flag.
+ pub const fn name(&self) -> &'static str {
+ self.name
+ }
+
+ /// Get the value of this flag.
+ pub const fn value(&self) -> &B {
+ &self.value
+ }
+}
+
+/// A set of flags.
+///
+/// This trait is automatically implemented for flags types defined using the `bitflags!` macro.
+/// It can also be implemented manually for custom flags types.
+pub trait Flags: Sized + 'static {
+ /// The set of available flags and their names.
+ const FLAGS: &'static [Flag<Self>];
+
+ /// The underlying storage type.
+ type Bits: Bits;
/// Returns an empty set of flags.
- fn empty() -> Self;
+ fn empty() -> Self {
+ Self::from_bits_retain(Self::Bits::EMPTY)
+ }
/// Returns the set containing all flags.
- fn all() -> Self;
+ fn all() -> Self {
+ Self::from_bits_truncate(Self::Bits::ALL)
+ }
/// Returns the raw value of the flags currently stored.
fn bits(&self) -> Self::Bits;
@@ -28,9 +55,15 @@ pub trait BitFlags: ImplementedByBitFlagsMacro {
/// Note that each [multi-bit flag] is treated as a unit for this comparison.
///
/// [multi-bit flag]: index.html#multi-bit-flags
- fn from_bits(bits: Self::Bits) -> Option<Self>
- where
- Self: Sized;
+ fn from_bits(bits: Self::Bits) -> Option<Self> {
+ let truncated = Self::from_bits_truncate(bits);
+
+ if truncated.bits() == bits {
+ Some(truncated)
+ } else {
+ None
+ }
+ }
/// Convert from underlying bit representation, dropping any bits
/// that do not correspond to flags.
@@ -38,81 +71,181 @@ pub trait BitFlags: ImplementedByBitFlagsMacro {
/// Note that each [multi-bit flag] is treated as a unit for this comparison.
///
/// [multi-bit flag]: index.html#multi-bit-flags
- fn from_bits_truncate(bits: Self::Bits) -> Self;
+ fn from_bits_truncate(bits: Self::Bits) -> Self {
+ if bits == Self::Bits::EMPTY {
+ return Self::empty();
+ }
+
+ let mut truncated = Self::Bits::EMPTY;
+
+ for flag in Self::FLAGS.iter() {
+ let flag = flag.value();
+
+ if bits & flag.bits() == flag.bits() {
+ truncated = truncated | flag.bits();
+ }
+ }
+
+ Self::from_bits_retain(truncated)
+ }
/// Convert from underlying bit representation, preserving all
/// bits (even those not corresponding to a defined flag).
fn from_bits_retain(bits: Self::Bits) -> Self;
/// Get the flag for a particular name.
- fn from_name(name: &str) -> Option<Self>
- where
- Self: Sized;
+ fn from_name(name: &str) -> Option<Self> {
+ for flag in Self::FLAGS {
+ if flag.name() == name {
+ return Some(Self::from_bits_retain(flag.value().bits()))
+ }
+ }
+
+ None
+ }
/// Iterate over enabled flag values.
- fn iter(&self) -> Self::Iter;
+ fn iter(&self) -> iter::Iter<Self> {
+ iter::Iter::new(self)
+ }
/// Iterate over the raw names and bits for enabled flag values.
- fn iter_names(&self) -> Self::IterNames;
+ fn iter_names(&self) -> iter::IterNames<Self> {
+ iter::IterNames::new(self)
+ }
/// Returns `true` if no flags are currently stored.
- fn is_empty(&self) -> bool;
+ fn is_empty(&self) -> bool {
+ self.bits() == Self::Bits::EMPTY
+ }
/// Returns `true` if all flags are currently set.
- fn is_all(&self) -> bool;
+ fn is_all(&self) -> bool {
+ // NOTE: We check against `Self::all` here, not `Self::Bits::ALL`
+ // because the set of all flags may not use all bits
+ Self::all().bits() | self.bits() == self.bits()
+ }
/// Returns `true` if there are flags common to both `self` and `other`.
- fn intersects(&self, other: Self) -> bool;
+ fn intersects(&self, other: Self) -> bool
+ where
+ Self: Sized,
+ {
+ self.bits() & other.bits() != Self::Bits::EMPTY
+ }
/// Returns `true` if all of the flags in `other` are contained within `self`.
- fn contains(&self, other: Self) -> bool;
+ fn contains(&self, other: Self) -> bool
+ where
+ Self: Sized,
+ {
+ self.bits() & other.bits() == other.bits()
+ }
/// Inserts the specified flags in-place.
- fn insert(&mut self, other: Self);
+ fn insert(&mut self, other: Self)
+ where
+ Self: Sized,
+ {
+ *self = Self::from_bits_retain(self.bits() | other.bits());
+ }
/// Removes the specified flags in-place.
- fn remove(&mut self, other: Self);
+ fn remove(&mut self, other: Self)
+ where
+ Self: Sized,
+ {
+ *self = Self::from_bits_retain(self.bits() & !other.bits());
+ }
/// Toggles the specified flags in-place.
- fn toggle(&mut self, other: Self);
+ fn toggle(&mut self, other: Self)
+ where
+ Self: Sized,
+ {
+ *self = Self::from_bits_retain(self.bits() ^ other.bits());
+ }
/// Inserts or removes the specified flags depending on the passed value.
- fn set(&mut self, other: Self, value: bool);
-}
+ fn set(&mut self, other: Self, value: bool)
+ where
+ Self: Sized,
+ {
+ if value {
+ self.insert(other);
+ } else {
+ self.remove(other);
+ }
+ }
-/// A marker trait that signals that an implementation of `BitFlags` came from the `bitflags!` macro.
-///
-/// There's nothing stopping an end-user from implementing this trait, but we don't guarantee their
-/// manual implementations won't break between non-breaking releases.
-#[doc(hidden)]
-pub trait ImplementedByBitFlagsMacro {}
+ /// 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`.
+ #[must_use]
+ fn intersection(self, other: Self) -> Self {
+ Self::from_bits_retain(self.bits() & other.bits())
+ }
-// Not re-exported
-pub trait Sealed {}
+ /// 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).
+ #[must_use]
+ fn union(self, other: Self) -> Self {
+ Self::from_bits_retain(self.bits() | other.bits())
+ }
-// Private implementation details
-//
-// The `Bits`, `PublicFlags`, and `InternalFlags` traits are implementation details of the `bitflags!`
-// macro that we're free to change here. They work with the `bitflags!` macro to separate the generated
-// code that belongs to end-users, and the generated code that belongs to this library.
+ /// 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).
+ #[must_use]
+ fn difference(self, other: Self) -> Self {
+ Self::from_bits_retain(self.bits() & !other.bits())
+ }
-/// A private trait that encodes the requirements of underlying bits types that can hold flags.
-///
-/// This trait may be made public at some future point, but it presents a compatibility hazard
-/// so is left internal for now.
-#[doc(hidden)]
+ /// 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`.
+ ///
+ /// [sym-diff]: https://en.wikipedia.org/wiki/Symmetric_difference
+ #[must_use]
+ fn symmetric_difference(self, other: Self) -> Self {
+ Self::from_bits_retain(self.bits() ^ other.bits())
+ }
+
+ /// 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.
+ #[must_use]
+ fn complement(self) -> Self {
+ Self::from_bits_truncate(!self.bits())
+ }
+}
+
+/// Underlying storage for a flags type.
pub trait Bits:
Clone
+ Copy
- + BitAnd
- + BitAndAssign
- + BitOr
- + BitOrAssign
- + BitXor
- + BitXorAssign
- + Not
+ + PartialEq
+ + BitAnd<Output = Self>
+ + BitOr<Output = Self>
+ + BitXor<Output = Self>
+ + Not<Output = Self>
+ Sized
- + Sealed
+ + 'static
{
/// The value of `Self` where no bits are set.
const EMPTY: Self;
@@ -121,6 +254,10 @@ pub trait Bits:
const ALL: Self;
}
+// Not re-exported: prevent custom `Bits` impls being used in the `bitflags!` macro,
+// or they may fail to compile based on crate features
+pub trait Primitive {}
+
macro_rules! impl_bits {
($($u:ty, $i:ty,)*) => {
$(
@@ -134,8 +271,32 @@ macro_rules! impl_bits {
const ALL: $i = <$u>::MAX as $i;
}
- impl Sealed for $u {}
- impl Sealed for $i {}
+ impl ParseHex for $u {
+ fn parse_hex(input: &str) -> Result<Self, ParseError> {
+ <$u>::from_str_radix(input, 16).map_err(|_| ParseError::invalid_hex_flag(input))
+ }
+ }
+
+ impl ParseHex for $i {
+ fn parse_hex(input: &str) -> Result<Self, ParseError> {
+ <$i>::from_str_radix(input, 16).map_err(|_| ParseError::invalid_hex_flag(input))
+ }
+ }
+
+ impl WriteHex for $u {
+ fn write_hex<W: fmt::Write>(&self, mut writer: W) -> fmt::Result {
+ write!(writer, "{:x}", self)
+ }
+ }
+
+ impl WriteHex for $i {
+ fn write_hex<W: fmt::Write>(&self, mut writer: W) -> fmt::Result {
+ write!(writer, "{:x}", self)
+ }
+ }
+
+ impl Primitive for $i {}
+ impl Primitive for $u {}
)*
}
}
@@ -152,6 +313,37 @@ impl_bits! {
/// A trait for referencing the `bitflags`-owned internal type
/// without exposing it publicly.
pub trait PublicFlags {
+ /// The type of the underlying storage.
+ type Primitive: Primitive;
+
/// The type of the internal field on the generated flags type.
type Internal;
}
+
+#[deprecated(note = "use the `Flags` trait instead")]
+pub trait BitFlags: ImplementedByBitFlagsMacro + Flags {
+ /// An iterator over enabled flags in an instance of the type.
+ type Iter: Iterator<Item = Self>;
+
+ /// An iterator over the raw names and bits for enabled flags in an instance of the type.
+ type IterNames: Iterator<Item = (&'static str, Self)>;
+}
+
+#[allow(deprecated)]
+impl<B: Flags> BitFlags for B {
+ type Iter = iter::Iter<Self>;
+ type IterNames = iter::IterNames<Self>;
+}
+
+impl<B: Flags> ImplementedByBitFlagsMacro for B {}
+
+/// A marker trait that signals that an implementation of `BitFlags` came from the `bitflags!` macro.
+///
+/// There's nothing stopping an end-user from implementing this trait, but we don't guarantee their
+/// manual implementations won't break between non-breaking releases.
+#[doc(hidden)]
+pub trait ImplementedByBitFlagsMacro {}
+
+pub(crate) mod __private {
+ pub use super::{ImplementedByBitFlagsMacro, PublicFlags};
+}
diff --git a/tests/basic.rs b/tests/basic.rs
deleted file mode 100644
index 73a52be..0000000
--- a/tests/basic.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-#![no_std]
-
-use bitflags::bitflags;
-
-bitflags! {
- /// baz
- struct Flags: u32 {
- const A = 0b00000001;
- #[doc = "bar"]
- const B = 0b00000010;
- const C = 0b00000100;
- #[doc = "foo"]
- const ABC = Flags::A.bits | Flags::B.bits | Flags::C.bits;
- }
-}
-
-#[test]
-fn basic() {
- assert_eq!(Flags::ABC, Flags::A | Flags::B | Flags::C);
-}
diff --git a/tests/compile-fail/.gitignore b/tests/compile-fail/.gitignore
deleted file mode 100644
index 4dd9abc..0000000
--- a/tests/compile-fail/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.stderr
diff --git a/tests/compile-fail/impls/copy.rs b/tests/compile-fail/impls/copy.rs
deleted file mode 100644
index 38f4822..0000000
--- a/tests/compile-fail/impls/copy.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-use bitflags::bitflags;
-
-bitflags! {
- #[derive(Clone, Copy)]
- struct Flags: u32 {
- const A = 0b00000001;
- }
-}
-
-fn main() {}
diff --git a/tests/compile-fail/impls/copy.stderr.beta b/tests/compile-fail/impls/copy.stderr.beta
deleted file mode 100644
index 0c13aa5..0000000
--- a/tests/compile-fail/impls/copy.stderr.beta
+++ /dev/null
@@ -1,27 +0,0 @@
-error[E0119]: conflicting implementations of trait `std::clone::Clone` for type `Flags`
- --> $DIR/copy.rs:3:1
- |
-3 | / bitflags! {
-4 | | #[derive(Clone, Copy)]
- | | ----- first implementation here
-5 | | struct Flags: u32 {
-6 | | const A = 0b00000001;
-7 | | }
-8 | | }
- | |_^ conflicting implementation for `Flags`
- |
- = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `Flags`
- --> $DIR/copy.rs:3:1
- |
-3 | / bitflags! {
-4 | | #[derive(Clone, Copy)]
- | | ---- first implementation here
-5 | | struct Flags: u32 {
-6 | | const A = 0b00000001;
-7 | | }
-8 | | }
- | |_^ conflicting implementation for `Flags`
- |
- = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/compile-fail/impls/eq.rs b/tests/compile-fail/impls/eq.rs
deleted file mode 100644
index 4abbd63..0000000
--- a/tests/compile-fail/impls/eq.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-use bitflags::bitflags;
-
-bitflags! {
- #[derive(PartialEq, Eq)]
- struct Flags: u32 {
- const A = 0b00000001;
- }
-}
-
-fn main() {}
diff --git a/tests/compile-fail/impls/eq.stderr.beta b/tests/compile-fail/impls/eq.stderr.beta
deleted file mode 100644
index 8a1a3b4..0000000
--- a/tests/compile-fail/impls/eq.stderr.beta
+++ /dev/null
@@ -1,55 +0,0 @@
-error[E0119]: conflicting implementations of trait `std::cmp::PartialEq` for type `Flags`
- --> $DIR/eq.rs:3:1
- |
-3 | / bitflags! {
-4 | | #[derive(PartialEq, Eq)]
- | | --------- first implementation here
-5 | | struct Flags: u32 {
-6 | | const A = 0b00000001;
-7 | | }
-8 | | }
- | |_^ conflicting implementation for `Flags`
- |
- = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0119]: conflicting implementations of trait `std::cmp::Eq` for type `Flags`
- --> $DIR/eq.rs:3:1
- |
-3 | / bitflags! {
-4 | | #[derive(PartialEq, Eq)]
- | | -- first implementation here
-5 | | struct Flags: u32 {
-6 | | const A = 0b00000001;
-7 | | }
-8 | | }
- | |_^ conflicting implementation for `Flags`
- |
- = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0119]: conflicting implementations of trait `std::marker::StructuralPartialEq` for type `Flags`
- --> $DIR/eq.rs:3:1
- |
-3 | / bitflags! {
-4 | | #[derive(PartialEq, Eq)]
- | | --------- first implementation here
-5 | | struct Flags: u32 {
-6 | | const A = 0b00000001;
-7 | | }
-8 | | }
- | |_^ conflicting implementation for `Flags`
- |
- = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0119]: conflicting implementations of trait `std::marker::StructuralEq` for type `Flags`
- --> $DIR/eq.rs:3:1
- |
-3 | / bitflags! {
-4 | | #[derive(PartialEq, Eq)]
- | | -- first implementation here
-5 | | struct Flags: u32 {
-6 | | const A = 0b00000001;
-7 | | }
-8 | | }
- | |_^ conflicting implementation for `Flags`
- |
- = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/compile-fail/non_integer_base/all_defined.rs b/tests/compile-fail/non_integer_base/all_defined.rs
deleted file mode 100644
index c2856b1..0000000
--- a/tests/compile-fail/non_integer_base/all_defined.rs
+++ /dev/null
@@ -1,123 +0,0 @@
-use std::{
- fmt::{
- self,
- Debug,
- Display,
- LowerHex,
- UpperHex,
- Octal,
- Binary,
- },
- ops::{
- BitAnd,
- BitOr,
- BitXor,
- BitAndAssign,
- BitOrAssign,
- BitXorAssign,
- Not,
- },
-};
-
-use bitflags::bitflags;
-
-// Ideally we'd actually want this to work, but currently need something like `num`'s `Zero`
-// With some design work it could be made possible
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-struct MyInt(u8);
-
-impl BitAnd for MyInt {
- type Output = Self;
-
- fn bitand(self, other: Self) -> Self {
- MyInt(self.0 & other.0)
- }
-}
-
-impl BitOr for MyInt {
- type Output = Self;
-
- fn bitor(self, other: Self) -> Self {
- MyInt(self.0 | other.0)
- }
-}
-
-impl BitXor for MyInt {
- type Output = Self;
-
- fn bitxor(self, other: Self) -> Self {
- MyInt(self.0 ^ other.0)
- }
-}
-
-impl BitAndAssign for MyInt {
- fn bitand_assign(&mut self, other: Self) {
- self.0 &= other.0
- }
-}
-
-impl BitOrAssign for MyInt {
- fn bitor_assign(&mut self, other: Self) {
- self.0 |= other.0
- }
-}
-
-impl BitXorAssign for MyInt {
- fn bitxor_assign(&mut self, other: Self) {
- self.0 ^= other.0
- }
-}
-
-impl Debug for MyInt {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- Debug::fmt(&self.0, f)
- }
-}
-
-impl Display for MyInt {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- Display::fmt(&self.0, f)
- }
-}
-
-impl LowerHex for MyInt {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- LowerHex::fmt(&self.0, f)
- }
-}
-
-impl UpperHex for MyInt {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- UpperHex::fmt(&self.0, f)
- }
-}
-
-impl Octal for MyInt {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- Octal::fmt(&self.0, f)
- }
-}
-
-impl Binary for MyInt {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- Binary::fmt(&self.0, f)
- }
-}
-
-impl Not for MyInt {
- type Output = MyInt;
-
- fn not(self) -> Self {
- MyInt(!self.0)
- }
-}
-
-bitflags! {
- struct Flags128: MyInt {
- const A = MyInt(0b0000_0001u8);
- const B = MyInt(0b0000_0010u8);
- const C = MyInt(0b0000_0100u8);
- }
-}
-
-fn main() {}
diff --git a/tests/compile-fail/non_integer_base/all_defined.stderr.beta b/tests/compile-fail/non_integer_base/all_defined.stderr.beta
deleted file mode 100644
index 1f0fb5c..0000000
--- a/tests/compile-fail/non_integer_base/all_defined.stderr.beta
+++ /dev/null
@@ -1,27 +0,0 @@
-error[E0308]: mismatched types
- --> $DIR/all_defined.rs:115:1
- |
-115 | / bitflags! {
-116 | | struct Flags128: MyInt {
-117 | | const A = MyInt(0b0000_0001u8);
-118 | | const B = MyInt(0b0000_0010u8);
-119 | | const C = MyInt(0b0000_0100u8);
-120 | | }
-121 | | }
- | |_^ expected struct `MyInt`, found integer
- |
- = note: this error originates in the macro `__impl_all_bitflags` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0308]: mismatched types
- --> $DIR/all_defined.rs:115:1
- |
-115 | / bitflags! {
-116 | | struct Flags128: MyInt {
-117 | | const A = MyInt(0b0000_0001u8);
-118 | | const B = MyInt(0b0000_0010u8);
-119 | | const C = MyInt(0b0000_0100u8);
-120 | | }
-121 | | }
- | |_^ expected struct `MyInt`, found integer
- |
- = note: this error originates in the macro `__impl_bitflags` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/compile-fail/non_integer_base/all_missing.rs b/tests/compile-fail/non_integer_base/all_missing.rs
deleted file mode 100644
index fff6b2c..0000000
--- a/tests/compile-fail/non_integer_base/all_missing.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-use bitflags::bitflags;
-
-struct MyInt(u8);
-
-bitflags! {
- struct Flags128: MyInt {
- const A = MyInt(0b0000_0001);
- const B = MyInt(0b0000_0010);
- const C = MyInt(0b0000_0100);
- }
-}
-
-fn main() {}
diff --git a/tests/compile-fail/non_integer_base/all_missing.stderr.beta b/tests/compile-fail/non_integer_base/all_missing.stderr.beta
deleted file mode 100644
index ee95f83..0000000
--- a/tests/compile-fail/non_integer_base/all_missing.stderr.beta
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0204]: the trait `Copy` may not be implemented for this type
- --> $DIR/all_missing.rs:5:1
- |
-5 | / bitflags! {
-6 | | struct Flags128: MyInt {
-7 | | const A = MyInt(0b0000_0001);
-8 | | const B = MyInt(0b0000_0010);
-9 | | const C = MyInt(0b0000_0100);
-10 | | }
-11 | | }
- | |_^ this field does not implement `Copy`
- |
- = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/compile-fail/visibility/private_field.rs b/tests/compile-fail/visibility/private_field.rs
deleted file mode 100644
index a6a3912..0000000
--- a/tests/compile-fail/visibility/private_field.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-mod example {
- use bitflags::bitflags;
-
- bitflags! {
- pub struct Flags1: u32 {
- const FLAG_A = 0b00000001;
- }
- }
-}
-
-fn main() {
- let flag1 = example::Flags1::FLAG_A.bits;
-}
diff --git a/tests/compile-fail/visibility/private_field.stderr.beta b/tests/compile-fail/visibility/private_field.stderr.beta
deleted file mode 100644
index 58a0466..0000000
--- a/tests/compile-fail/visibility/private_field.stderr.beta
+++ /dev/null
@@ -1,10 +0,0 @@
-error[E0616]: field `bits` of struct `Flags1` is private
- --> $DIR/private_field.rs:12:41
- |
-12 | let flag1 = example::Flags1::FLAG_A.bits;
- | ^^^^ private field
- |
-help: a method `bits` also exists, call it with parentheses
- |
-12 | let flag1 = example::Flags1::FLAG_A.bits();
- | ^^
diff --git a/tests/compile-fail/visibility/private_flags.rs b/tests/compile-fail/visibility/private_flags.rs
deleted file mode 100644
index 85a5b18..0000000
--- a/tests/compile-fail/visibility/private_flags.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-mod example {
- use bitflags::bitflags;
-
- bitflags! {
- pub struct Flags1: u32 {
- const FLAG_A = 0b00000001;
- }
-
- struct Flags2: u32 {
- const FLAG_B = 0b00000010;
- }
- }
-}
-
-fn main() {
- let flag1 = example::Flags1::FLAG_A;
- let flag2 = example::Flags2::FLAG_B;
-}
diff --git a/tests/compile-fail/visibility/private_flags.stderr.beta b/tests/compile-fail/visibility/private_flags.stderr.beta
deleted file mode 100644
index d23f832..0000000
--- a/tests/compile-fail/visibility/private_flags.stderr.beta
+++ /dev/null
@@ -1,18 +0,0 @@
-error[E0603]: struct `Flags2` is private
- --> $DIR/private_flags.rs:17:26
- |
-17 | let flag2 = example::Flags2::FLAG_B;
- | ^^^^^^ private struct
- |
-note: the struct `Flags2` is defined here
- --> $DIR/private_flags.rs:4:5
- |
-4 | / bitflags! {
-5 | | pub struct Flags1: u32 {
-6 | | const FLAG_A = 0b00000001;
-7 | | }
-... |
-11 | | }
-12 | | }
- | |_____^
- = note: this error originates in the macro `bitflags` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/compile-fail/visibility/pub_const.rs b/tests/compile-fail/visibility/pub_const.rs
deleted file mode 100644
index b90f0ce..0000000
--- a/tests/compile-fail/visibility/pub_const.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-use bitflags::bitflags;
-
-bitflags! {
- pub struct Flags1: u32 {
- pub const FLAG_A = 0b00000001;
- }
-}
-
-fn main() {}
diff --git a/tests/compile-fail/visibility/pub_const.stderr.beta b/tests/compile-fail/visibility/pub_const.stderr.beta
deleted file mode 100644
index b01122c..0000000
--- a/tests/compile-fail/visibility/pub_const.stderr.beta
+++ /dev/null
@@ -1,5 +0,0 @@
-error: no rules expected the token `pub`
- --> $DIR/pub_const.rs:5:9
- |
-5 | pub const FLAG_A = 0b00000001;
- | ^^^ no rules expected this token in macro call
diff --git a/tests/compile-pass/impls/convert.rs b/tests/compile-pass/impls/convert.rs
deleted file mode 100644
index 1f02982..0000000
--- a/tests/compile-pass/impls/convert.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-use bitflags::bitflags;
-
-bitflags! {
- struct Flags: u32 {
- const A = 0b00000001;
- }
-}
-
-impl From<u32> for Flags {
- fn from(v: u32) -> Flags {
- Flags::from_bits_truncate(v)
- }
-}
-
-fn main() {
-
-}
diff --git a/tests/compile-pass/impls/default.rs b/tests/compile-pass/impls/default.rs
deleted file mode 100644
index a97b653..0000000
--- a/tests/compile-pass/impls/default.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-use bitflags::bitflags;
-
-bitflags! {
- #[derive(Default)]
- struct Flags: u32 {
- const A = 0b00000001;
- }
-}
-
-fn main() {}
diff --git a/tests/compile-pass/impls/inherent_methods.rs b/tests/compile-pass/impls/inherent_methods.rs
deleted file mode 100644
index 3052c46..0000000
--- a/tests/compile-pass/impls/inherent_methods.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-use bitflags::bitflags;
-
-bitflags! {
- struct Flags: u32 {
- const A = 0b00000001;
- }
-}
-
-impl Flags {
- pub fn new() -> Flags {
- Flags::A
- }
-}
-
-fn main() {}
diff --git a/tests/compile-pass/redefinition/core.rs b/tests/compile-pass/redefinition/core.rs
deleted file mode 100644
index 4754921..0000000
--- a/tests/compile-pass/redefinition/core.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-use bitflags::bitflags;
-
-// Checks for possible errors caused by overriding names used by `bitflags!` internally.
-
-mod core {}
-mod _core {}
-
-bitflags! {
- struct Test: u8 {
- const A = 1;
- }
-}
-
-fn main() {}
diff --git a/tests/compile-pass/redefinition/stringify.rs b/tests/compile-pass/redefinition/stringify.rs
deleted file mode 100644
index b04f2f6..0000000
--- a/tests/compile-pass/redefinition/stringify.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-use bitflags::bitflags;
-
-// Checks for possible errors caused by overriding names used by `bitflags!` internally.
-
-#[allow(unused_macros)]
-macro_rules! stringify {
- ($($t:tt)*) => { "..." };
-}
-
-bitflags! {
- struct Test: u8 {
- const A = 1;
- }
-}
-
-fn main() {
- // Just make sure we don't call the redefined `stringify` macro
- assert_eq!(format!("{:?}", Test::A), "A");
-}
diff --git a/tests/compile-pass/repr/c.rs b/tests/compile-pass/repr/c.rs
deleted file mode 100644
index 6feba36..0000000
--- a/tests/compile-pass/repr/c.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-use bitflags::bitflags;
-
-bitflags! {
- #[repr(C)]
- struct Flags: u32 {
- const A = 0b00000001;
- }
-}
-
-fn main() {}
diff --git a/tests/compile-pass/repr/transparent.rs b/tests/compile-pass/repr/transparent.rs
deleted file mode 100644
index e38db4d..0000000
--- a/tests/compile-pass/repr/transparent.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-use bitflags::bitflags;
-
-bitflags! {
- #[repr(transparent)]
- struct Flags: u32 {
- const A = 0b00000001;
- }
-}
-
-fn main() {}
diff --git a/tests/compile-pass/visibility/bits_field.rs b/tests/compile-pass/visibility/bits_field.rs
deleted file mode 100644
index 33a7967..0000000
--- a/tests/compile-pass/visibility/bits_field.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-use bitflags::bitflags;
-
-bitflags! {
- pub struct Flags1: u32 {
- const FLAG_A = 0b00000001;
- }
-}
-
-fn main() {
- assert_eq!(0b00000001, Flags1::FLAG_A.bits);
-}
diff --git a/tests/compile-pass/visibility/pub_in.rs b/tests/compile-pass/visibility/pub_in.rs
deleted file mode 100644
index c11050e..0000000
--- a/tests/compile-pass/visibility/pub_in.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-mod a {
- mod b {
- use bitflags::bitflags;
-
- bitflags! {
- pub(in crate::a) struct Flags: u32 {
- const FLAG_A = 0b00000001;
- }
- }
- }
-
- pub fn flags() -> u32 {
- b::Flags::FLAG_A.bits()
- }
-}
-
-fn main() {
- assert_eq!(0b00000001, a::flags());
-}
diff --git a/tests/compile.rs b/tests/compile.rs
deleted file mode 100644
index ed02d01..0000000
--- a/tests/compile.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-use std::{
- fs,
- ffi::OsStr,
- io,
- path::Path,
-};
-
-use walkdir::WalkDir;
-
-#[test]
-fn fail() {
- prepare_stderr_files("tests/compile-fail").unwrap();
-
- let t = trybuild::TestCases::new();
- t.compile_fail("tests/compile-fail/**/*.rs");
-}
-
-#[test]
-fn pass() {
- let t = trybuild::TestCases::new();
- t.pass("tests/compile-pass/**/*.rs");
-}
-
-// Compiler messages may change between versions
-// We don't want to have to track these too closely for `bitflags`, but
-// having some message to check makes sure user-facing errors are sensical.
-//
-// The approach we use is to run the test on all compilers, but only check stderr
-// output on beta (which is the next stable release). We do this by default ignoring
-// any `.stderr` files in the `compile-fail` directory, and copying `.stderr.beta` files
-// when we happen to be running on a beta compiler.
-fn prepare_stderr_files(path: impl AsRef<Path>) -> io::Result<()> {
- for entry in WalkDir::new(path) {
- let entry = entry?;
-
- if entry.path().extension().and_then(OsStr::to_str) == Some("beta") {
- let renamed = entry.path().with_extension("");
-
- // Unconditionally remove a corresponding `.stderr` file for a `.stderr.beta`
- // file if it exists. On `beta` compilers, we'll recreate it. On other compilers,
- // we don't want to end up checking it anyways.
- if renamed.exists() {
- fs::remove_file(&renamed)?;
- }
-
- rename_beta_stderr(entry.path(), renamed)?;
- }
- }
-
- Ok(())
-}
-
-#[rustversion::beta]
-fn rename_beta_stderr(from: impl AsRef<Path>, to: impl AsRef<Path>) -> io::Result<()> {
- fs::copy(from, to)?;
-
- Ok(())
-}
-
-#[rustversion::not(beta)]
-fn rename_beta_stderr(_: impl AsRef<Path>, _: impl AsRef<Path>) -> io::Result<()> {
- Ok(())
-}