diff options
author | Andrew Walbran <qwandor@google.com> | 2023-06-14 16:37:52 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2023-06-14 16:37:52 +0000 |
commit | c4af5ed2fa5e1b7ed989a39a6b1e3dfa8a8b19b4 (patch) | |
tree | 680ec0b7c7385389bf019efd940a1690c6aac350 | |
parent | 45a157cc95331987bfbd03b856007a470eeda21b (diff) | |
parent | 976ee2c4aca4f6a98daa9d5ff32d1950c1fad9fa (diff) | |
download | bitflags-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>
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 @@ -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 @@ -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"] } @@ -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 } } @@ -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 + } +} @@ -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(()) -} |