From 8621e103832221aff0491f11d598a872f1411684 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Wed, 25 May 2022 14:08:02 +1000 Subject: [PATCH 01/12] split generated code into two types --- .github/workflows/rust.yml | 1 + Cargo.toml | 2 +- src/bitflags_trait.rs | 19 +- src/lib.rs | 724 ++++++++++++++++++++--------------- tests/smoke-test/Cargo.toml | 8 + tests/smoke-test/src/main.rs | 15 + 6 files changed, 459 insertions(+), 310 deletions(-) create mode 100644 tests/smoke-test/Cargo.toml create mode 100644 tests/smoke-test/src/main.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index b7b2486e..f8c67c7c 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -48,6 +48,7 @@ jobs: - name: Tests run: cargo test --features example_generated + run: cargo run --manifest-path tests/smoke-test/Cargo.toml embedded: name: Build (embedded) diff --git a/Cargo.toml b/Cargo.toml index 9c7c7aa7..ade15fbc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ categories = ["no-std"] description = """ A macro to generate structures which behave like bitflags. """ -exclude = ["bors.toml"] +exclude = ["tests", ".github"] [dependencies] core = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-core' } diff --git a/src/bitflags_trait.rs b/src/bitflags_trait.rs index 440d5274..7cafb564 100644 --- a/src/bitflags_trait.rs +++ b/src/bitflags_trait.rs @@ -25,16 +25,7 @@ pub trait BitFlags: ImplementedByBitFlagsMacro { fn from_bits_truncate(bits: Self::Bits) -> Self; /// Convert from underlying bit representation, preserving all /// bits (even those not corresponding to a defined flag). - /// - /// # Safety - /// - /// The caller of the `bitflags!` macro can chose to allow or - /// disallow extra bits for their bitflags type. - /// - /// The caller of `from_bits_unchecked()` has to ensure that - /// all bits correspond to a defined flag or that extra bits - /// are valid for this bitflags type. - unsafe fn from_bits_unchecked(bits: Self::Bits) -> Self; + fn from_bits_retain(bits: Self::Bits) -> Self; /// Returns `true` if no flags are currently stored. fn is_empty(&self) -> bool; /// Returns `true` if all flags are currently set. @@ -107,3 +98,11 @@ impl_bits! { u64, i64, u128, i128, } + +pub trait PublicFlags { + type InternalFlags; +} + +pub trait InternalFlags { + type PublicFlags; +} diff --git a/src/lib.rs b/src/lib.rs index 979ff918..b466f9f8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -285,10 +285,59 @@ mod bitflags_trait; #[doc(hidden)] pub mod __private { - pub use crate::bitflags_trait::{Bits, ImplementedByBitFlagsMacro}; + pub use crate::bitflags_trait::{Bits, ImplementedByBitFlagsMacro, InternalFlags, PublicFlags}; pub use core; } +/* +How does the bitflags crate work? + +This library generates `struct`s in the end-user's crate with a bunch of constants on it that represent flags. +The difference between `bitflags` and a lot of other libraries is that we don't actually control the generated `struct` in the end. +It's part of the end-user's crate, so it belongs to them. That makes it difficult to extend `bitflags` with new functionality +because we could end up breaking valid code that was already written. + +Our solution is to split the type we generate into two: the public struct owned by the end-user, and an internal struct owned by `bitflags` (us). +To give you an example, let's say we had a crate that called `bitflags!`: + +```rust +bitflags! { + pub struct MyFlags: u32 { + const A = 1; + const B = 2; + } +} +``` + +What they'd end up with looks something like this: + +```rust +pub struct MyFlags(::InternalFlags); + +const _: () { + #[repr(transparent)] + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct MyInternalFlags { + bits: u32, + } + + impl PublicFlags for MyFlags { + type InternalFlags = InternalFlags; + } + + impl InternalFlags for MyInternalFlags { + type PublicFlags = MyFlags; + } +}; +``` + +If we want to expose something like a new trait impl for generated flags types, we add it to our generated `MyInternalFlags`, +and let `#[derive]` on `MyFlags` pick up that implementation, if an end-user chooses to add one. + +The public API is generated in the `__impl_bitflags_public!` macro, and the internal API is generated in +the `__impl_bitflags_internal!` macro. +*/ + /// The macro used to generate the flag structure. /// /// See the [crate level docs](../bitflags/index.html) for complete documentation. @@ -368,12 +417,10 @@ macro_rules! bitflags { $($t:tt)* ) => { $(#[$outer])* - #[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)] - $vis struct $BitFlags { - bits: $T, - } + #[derive(Clone, Copy)] + $vis struct $BitFlags(<$BitFlags as $crate::__private::PublicFlags>::InternalFlags); - __impl_bitflags! { + __impl_public_bitflags! { $BitFlags: $T { $( $(#[$inner $($args)*])* @@ -382,6 +429,31 @@ macro_rules! bitflags { } } + const _: () = { + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + #[repr(transparent)] + pub struct InternalFlags { + bits: $T, + } + + __impl_internal_bitflags! { + InternalFlags: $T { + $( + $(#[$inner $($args)*])* + $Flag; + )* + } + } + + impl $crate::__private::InternalFlags for InternalFlags { + type PublicFlags = $BitFlags; + } + + impl $crate::__private::PublicFlags for $BitFlags { + type InternalFlags = InternalFlags; + } + }; + bitflags! { $($t)* } @@ -389,70 +461,42 @@ macro_rules! bitflags { () => {}; } +/// 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_bitflags { +macro_rules! __impl_public_bitflags { ( - $BitFlags:ident: $T:ty { + $PublicBitFlags:ident: $T:ty { $( $(#[$attr:ident $($args:tt)*])* $Flag:ident = $value:expr; )* } ) => { - impl $crate::__private::core::fmt::Debug for $BitFlags { + impl $crate::__private::core::fmt::Binary for $PublicBitFlags { fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result { - // Iterate over the valid flags - let mut first = true; - for (name, _) in self.iter() { - if !first { - f.write_str(" | ")?; - } - - first = false; - f.write_str(name)?; - } - - // Append any extra bits that correspond to flags to the end of the format - let extra_bits = self.bits & !Self::all().bits(); - - if extra_bits != <$T as $crate::__private::Bits>::EMPTY { - if !first { - f.write_str(" | ")?; - } - first = false; - $crate::__private::core::write!(f, "{:#x}", extra_bits)?; - } - - if first { - f.write_str("(empty)")?; - } - - $crate::__private::core::fmt::Result::Ok(()) + $crate::__private::core::fmt::Binary::fmt(&self.0, f) } } - impl $crate::__private::core::fmt::Binary for $BitFlags { + 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::Binary::fmt(&self.bits, f) + $crate::__private::core::fmt::Octal::fmt(&self.0, f) } } - impl $crate::__private::core::fmt::Octal for $BitFlags { + 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::Octal::fmt(&self.bits, f) + $crate::__private::core::fmt::LowerHex::fmt(&self.0, f) } } - impl $crate::__private::core::fmt::LowerHex for $BitFlags { + 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::LowerHex::fmt(&self.bits, f) - } - } - - impl $crate::__private::core::fmt::UpperHex for $BitFlags { - fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result { - $crate::__private::core::fmt::UpperHex::fmt(&self.bits, f) + $crate::__private::core::fmt::UpperHex::fmt(&self.0, f) } } @@ -464,40 +508,37 @@ macro_rules! __impl_bitflags { unused_mut, non_upper_case_globals )] - impl $BitFlags { + impl $PublicBitFlags { $( $(#[$attr $($args)*])* - pub const $Flag: Self = Self { bits: $value }; + pub const $Flag: Self = Self::from_bits_retain($value); )* /// Returns an empty set of flags. #[inline] pub const fn empty() -> Self { - Self { bits: <$T as $crate::__private::Bits>::EMPTY } + Self(<$PublicBitFlags as $crate::__private::PublicFlags>::InternalFlags::empty()) } /// Returns the set containing all flags. #[inline] pub const fn all() -> Self { - Self::from_bits_truncate(<$T as $crate::__private::Bits>::ALL) + Self(<$PublicBitFlags as $crate::__private::PublicFlags>::InternalFlags::all()) } /// Returns the raw value of the flags currently stored. #[inline] pub const fn bits(&self) -> $T { - self.bits + self.0.bits() } /// Convert from underlying bit representation, unless that /// representation contains bits that do not correspond to a flag. #[inline] pub const fn from_bits(bits: $T) -> $crate::__private::core::option::Option { - 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 + match <$PublicBitFlags as $crate::__private::PublicFlags>::InternalFlags::from_bits(bits) { + Some(bits) => Some(Self(bits)), + None => None, } } @@ -505,20 +546,7 @@ macro_rules! __impl_bitflags { /// that do not correspond to flags. #[inline] pub const fn from_bits_truncate(bits: $T) -> Self { - if bits == <$T as $crate::__private::Bits>::EMPTY { - return Self { bits } - } - - let mut truncated = <$T as $crate::__private::Bits>::EMPTY; - - $( - $(#[$attr $($args)*])* - if bits & Self::$Flag.bits == Self::$Flag.bits { - truncated |= Self::$Flag.bits - } - )* - - Self { bits: truncated } + Self(<$PublicBitFlags as $crate::__private::PublicFlags>::InternalFlags::from_bits_truncate(bits)) } /// Convert from underlying bit representation, preserving all @@ -529,64 +557,60 @@ macro_rules! __impl_bitflags { /// The caller of the `bitflags!` macro can choose to allow or /// disallow extra bits for their bitflags type. /// - /// The caller of `from_bits_unchecked()` has to ensure that + /// The caller of `from_bits_retain()` has to ensure that /// all bits correspond to a defined flag or that extra bits /// are valid for this bitflags type. #[inline] - pub const unsafe fn from_bits_unchecked(bits: $T) -> Self { - Self { bits } + pub const fn from_bits_retain(bits: $T) -> Self { + Self(<$PublicBitFlags as $crate::__private::PublicFlags>::InternalFlags::from_bits_retain(bits)) } /// Returns `true` if no flags are currently stored. #[inline] pub const fn is_empty(&self) -> bool { - self.bits() == Self::empty().bits() + self.0.is_empty() } /// Returns `true` if all flags are currently set. #[inline] pub const fn is_all(&self) -> bool { - Self::all().bits | self.bits == self.bits + self.0.is_all() } /// Returns `true` if there are flags common to both `self` and `other`. #[inline] pub const fn intersects(&self, other: Self) -> bool { - !(Self { bits: self.bits & other.bits}).is_empty() + self.0.intersects(other.0) } /// Returns `true` if all of the flags in `other` are contained within `self`. #[inline] pub const fn contains(&self, other: Self) -> bool { - (self.bits & other.bits) == other.bits + self.0.contains(other.0) } /// Inserts the specified flags in-place. #[inline] pub fn insert(&mut self, other: Self) { - self.bits |= other.bits; + self.0.insert(other.0) } /// Removes the specified flags in-place. #[inline] pub fn remove(&mut self, other: Self) { - self.bits &= !other.bits; + self.0.remove(other.0) } /// Toggles the specified flags in-place. #[inline] pub fn toggle(&mut self, other: Self) { - self.bits ^= other.bits; + self.0.toggle(other.0) } /// Inserts or removes the specified flags depending on the passed value. #[inline] pub fn set(&mut self, other: Self, value: bool) { - if value { - self.insert(other); - } else { - self.remove(other); - } + self.0.set(other.0, value) } /// Returns the intersection between the flags in `self` and @@ -602,7 +626,7 @@ macro_rules! __impl_bitflags { #[inline] #[must_use] pub const fn intersection(self, other: Self) -> Self { - Self { bits: self.bits & other.bits } + Self(self.0.intersection(other.0)) } /// Returns the union of between the flags in `self` and `other`. @@ -619,7 +643,7 @@ macro_rules! __impl_bitflags { #[inline] #[must_use] pub const fn union(self, other: Self) -> Self { - Self { bits: self.bits | other.bits } + Self(self.0.union(other.0)) } /// Returns the difference between the flags in `self` and `other`. @@ -637,7 +661,7 @@ macro_rules! __impl_bitflags { #[inline] #[must_use] pub const fn difference(self, other: Self) -> Self { - Self { bits: self.bits & !other.bits } + Self(self.0.difference(other.0)) } /// Returns the [symmetric difference][sym-diff] between the flags @@ -656,7 +680,7 @@ macro_rules! __impl_bitflags { #[inline] #[must_use] pub const fn symmetric_difference(self, other: Self) -> Self { - Self { bits: self.bits ^ other.bits } + Self(self.0.symmetric_difference(other.0)) } /// Returns the complement of this set of flags. @@ -675,159 +699,99 @@ macro_rules! __impl_bitflags { #[inline] #[must_use] pub const fn complement(self) -> Self { - Self::from_bits_truncate(!self.bits) + Self(self.0.complement()) } /// Returns an iterator over set flags and their names. pub fn iter(self) -> impl $crate::__private::core::iter::Iterator { - use $crate::__private::core::iter::Iterator as _; - - const NUM_FLAGS: usize = { - let mut num_flags = 0; - - $( - $(#[$attr $($args)*])* - { - num_flags += 1; - } - )* - - num_flags - }; - - const OPTIONS: [$BitFlags; NUM_FLAGS] = [ - $( - $(#[$attr $($args)*])* - $BitFlags::$Flag, - )* - ]; - - const OPTIONS_NAMES: [&'static str; NUM_FLAGS] = [ - $( - $(#[$attr $($args)*])* - $crate::__private::core::stringify!($Flag), - )* - ]; - - let mut start = 0; - let mut state = self; - - $crate::__private::core::iter::from_fn(move || { - if state.is_empty() || NUM_FLAGS == 0 { - $crate::__private::core::option::Option::None - } else { - for (flag, flag_name) in OPTIONS[start..NUM_FLAGS].iter().copied() - .zip(OPTIONS_NAMES[start..NUM_FLAGS].iter().copied()) - { - start += 1; - - // NOTE: We check whether the flag exists in self, but remove it from - // a different value. This ensure that overlapping flags are handled - // properly. Take the following example: - // - // const A: 0b00000001; - // const B: 0b00000101; - // - // Given the bits 0b00000101, both A and B are set. But if we removed A - // as we encountered it we'd be left with 0b00000100, which doesn't - // correspond to a valid flag on its own. - if self.contains(flag) { - state.remove(flag); - - return $crate::__private::core::option::Option::Some((flag_name, flag)) - } - } - - $crate::__private::core::option::Option::None - } - }) + self.0.iter().map(|(name, bits)| (name, Self::from_bits_retain(bits))) } } - impl $crate::__private::core::ops::BitOr for $BitFlags { + impl $crate::__private::core::ops::BitOr for $PublicBitFlags { type Output = Self; /// Returns the union of the two sets of flags. #[inline] - fn bitor(self, other: $BitFlags) -> Self { - Self { bits: self.bits | other.bits } + fn bitor(self, other: $PublicBitFlags) -> Self { + self.union(other) } } - impl $crate::__private::core::ops::BitOrAssign for $BitFlags { + impl $crate::__private::core::ops::BitOrAssign for $PublicBitFlags { /// Adds the set of flags. #[inline] fn bitor_assign(&mut self, other: Self) { - self.bits |= other.bits; + self.0 = self.0.union(other.0); } } - impl $crate::__private::core::ops::BitXor for $BitFlags { + impl $crate::__private::core::ops::BitXor for $PublicBitFlags { type Output = Self; /// Returns the left flags, but with all the right flags toggled. #[inline] fn bitxor(self, other: Self) -> Self { - Self { bits: self.bits ^ other.bits } + self.symmetric_difference(other) } } - impl $crate::__private::core::ops::BitXorAssign for $BitFlags { + impl $crate::__private::core::ops::BitXorAssign for $PublicBitFlags { /// Toggles the set of flags. #[inline] fn bitxor_assign(&mut self, other: Self) { - self.bits ^= other.bits; + self.0 = self.0.symmetric_difference(other.0); } } - impl $crate::__private::core::ops::BitAnd for $BitFlags { + impl $crate::__private::core::ops::BitAnd for $PublicBitFlags { type Output = Self; /// Returns the intersection between the two sets of flags. #[inline] fn bitand(self, other: Self) -> Self { - Self { bits: self.bits & other.bits } + self.intersection(other) } } - impl $crate::__private::core::ops::BitAndAssign for $BitFlags { + impl $crate::__private::core::ops::BitAndAssign for $PublicBitFlags { /// Disables all flags disabled in the set. #[inline] fn bitand_assign(&mut self, other: Self) { - self.bits &= other.bits; + self.0 = self.0.intersection(other.0); } } - impl $crate::__private::core::ops::Sub for $BitFlags { + impl $crate::__private::core::ops::Sub for $PublicBitFlags { type Output = Self; /// Returns the set difference of the two sets of flags. #[inline] fn sub(self, other: Self) -> Self { - Self { bits: self.bits & !other.bits } + self.difference(other) } } - impl $crate::__private::core::ops::SubAssign for $BitFlags { + impl $crate::__private::core::ops::SubAssign for $PublicBitFlags { /// Disables all flags enabled in the set. #[inline] fn sub_assign(&mut self, other: Self) { - self.bits &= !other.bits; + self.0 = self.0.difference(other.0); } } - impl $crate::__private::core::ops::Not for $BitFlags { + impl $crate::__private::core::ops::Not for $PublicBitFlags { type Output = Self; /// Returns the complement of this set of flags. #[inline] fn not(self) -> Self { - Self { bits: !self.bits } & Self::all() + self.complement() } } - impl $crate::__private::core::iter::Extend<$BitFlags> for $BitFlags { + impl $crate::__private::core::iter::Extend<$PublicBitFlags> for $PublicBitFlags { fn extend>(&mut self, iterator: T) { for item in iterator { self.insert(item) @@ -835,7 +799,7 @@ macro_rules! __impl_bitflags { } } - impl $crate::__private::core::iter::FromIterator<$BitFlags> for $BitFlags { + impl $crate::__private::core::iter::FromIterator<$PublicBitFlags> for $PublicBitFlags { fn from_iter>(iterator: T) -> Self { use $crate::__private::core::iter::Extend; @@ -845,175 +809,337 @@ macro_rules! __impl_bitflags { } } - impl $crate::BitFlags for $BitFlags { + impl $crate::BitFlags for $PublicBitFlags { type Bits = $T; fn empty() -> Self { - $BitFlags::empty() + $PublicBitFlags::empty() } fn all() -> Self { - $BitFlags::all() + $PublicBitFlags::all() } fn bits(&self) -> $T { - $BitFlags::bits(self) + $PublicBitFlags::bits(self) } - fn from_bits(bits: $T) -> $crate::__private::core::option::Option<$BitFlags> { - $BitFlags::from_bits(bits) + fn from_bits(bits: $T) -> $crate::__private::core::option::Option<$PublicBitFlags> { + $PublicBitFlags::from_bits(bits) } - fn from_bits_truncate(bits: $T) -> $BitFlags { - $BitFlags::from_bits_truncate(bits) + fn from_bits_truncate(bits: $T) -> $PublicBitFlags { + $PublicBitFlags::from_bits_truncate(bits) } - unsafe fn from_bits_unchecked(bits: $T) -> $BitFlags { - $BitFlags::from_bits_unchecked(bits) + fn from_bits_retain(bits: $T) -> $PublicBitFlags { + $PublicBitFlags::from_bits_retain(bits) } fn is_empty(&self) -> bool { - $BitFlags::is_empty(self) + $PublicBitFlags::is_empty(self) } fn is_all(&self) -> bool { - $BitFlags::is_all(self) + $PublicBitFlags::is_all(self) } - fn intersects(&self, other: $BitFlags) -> bool { - $BitFlags::intersects(self, other) + fn intersects(&self, other: $PublicBitFlags) -> bool { + $PublicBitFlags::intersects(self, other) } - fn contains(&self, other: $BitFlags) -> bool { - $BitFlags::contains(self, other) + fn contains(&self, other: $PublicBitFlags) -> bool { + $PublicBitFlags::contains(self, other) } - fn insert(&mut self, other: $BitFlags) { - $BitFlags::insert(self, other) + fn insert(&mut self, other: $PublicBitFlags) { + $PublicBitFlags::insert(self, other) } - fn remove(&mut self, other: $BitFlags) { - $BitFlags::remove(self, other) + fn remove(&mut self, other: $PublicBitFlags) { + $PublicBitFlags::remove(self, other) } - fn toggle(&mut self, other: $BitFlags) { - $BitFlags::toggle(self, other) + fn toggle(&mut self, other: $PublicBitFlags) { + $PublicBitFlags::toggle(self, other) } - fn set(&mut self, other: $BitFlags, value: bool) { - $BitFlags::set(self, other, value) + fn set(&mut self, other: $PublicBitFlags, value: bool) { + $PublicBitFlags::set(self, other, value) } } - impl $crate::__private::ImplementedByBitFlagsMacro for $BitFlags {} + impl $crate::__private::ImplementedByBitFlagsMacro for $PublicBitFlags {} }; +} - // Every attribute that the user writes on a const is applied to the - // corresponding const that we generate, but within the implementation of - // Debug and all() we want to ignore everything but #[cfg] attributes. In - // particular, including a #[deprecated] attribute on those items would fail - // to compile. - // https://github.com/bitflags/bitflags/issues/109 - // - // Input: - // - // ? #[cfg(feature = "advanced")] - // ? #[deprecated(note = "Use something else.")] - // ? #[doc = r"High quality documentation."] - // fn f() -> i32 { /* ... */ } - // - // Output: - // - // #[cfg(feature = "advanced")] - // fn f() -> i32 { /* ... */ } +/// Implement functions on the private (bitflags-facing) bitflags type. +/// +/// Methods and trait implementations can be freely added here without breaking end-users. +/// If we want to expose new functionality to `#[derive]`, this is the place to do it. +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __impl_internal_bitflags { ( - $(#[$filtered:meta])* - ? #[cfg $($cfgargs:tt)*] - $(? #[$rest:ident $($restargs:tt)*])* - fn $($item:tt)* - ) => { - __impl_bitflags! { - $(#[$filtered])* - #[cfg $($cfgargs)*] - $(? #[$rest $($restargs)*])* - fn $($item)* + $InternalBitFlags:ident: $T:ty { + $( + $(#[$attr:ident $($args:tt)*])* + $Flag:ident; + )* } - }; - ( - $(#[$filtered:meta])* - // $next != `cfg` - ? #[$next:ident $($nextargs:tt)*] - $(? #[$rest:ident $($restargs:tt)*])* - fn $($item:tt)* ) => { - __impl_bitflags! { - $(#[$filtered])* - // $next filtered out - $(? #[$rest $($restargs)*])* - fn $($item)* + impl $crate::__private::core::fmt::Debug for $InternalBitFlags { + fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result { + // Iterate over the valid flags + let mut first = true; + for (name, _) in self.iter() { + if !first { + f.write_str(" | ")?; + } + + first = false; + f.write_str(name)?; + } + + // Append any extra bits that correspond to flags to the end of the format + let extra_bits = self.bits & !Self::all().bits; + + if extra_bits != <$T as $crate::__private::Bits>::EMPTY { + if !first { + f.write_str(" | ")?; + } + first = false; + $crate::__private::core::write!(f, "{:#x}", extra_bits)?; + } + + if first { + f.write_str("(empty)")?; + } + + $crate::__private::core::fmt::Result::Ok(()) + } } - }; - ( - $(#[$filtered:meta])* - fn $($item:tt)* - ) => { - $(#[$filtered])* - fn $($item)* - }; - // Every attribute that the user writes on a const is applied to the - // corresponding const that we generate, but within the implementation of - // Debug and all() we want to ignore everything but #[cfg] attributes. In - // particular, including a #[deprecated] attribute on those items would fail - // to compile. - // https://github.com/bitflags/bitflags/issues/109 - // - // const version - // - // Input: - // - // ? #[cfg(feature = "advanced")] - // ? #[deprecated(note = "Use something else.")] - // ? #[doc = r"High quality documentation."] - // const f: i32 { /* ... */ } - // - // Output: - // - // #[cfg(feature = "advanced")] - // const f: i32 { /* ... */ } - ( - $(#[$filtered:meta])* - ? #[cfg $($cfgargs:tt)*] - $(? #[$rest:ident $($restargs:tt)*])* - const $($item:tt)* - ) => { - __impl_bitflags! { - $(#[$filtered])* - #[cfg $($cfgargs)*] - $(? #[$rest $($restargs)*])* - const $($item)* + 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) + } } - }; - ( - $(#[$filtered:meta])* - // $next != `cfg` - ? #[$next:ident $($nextargs:tt)*] - $(? #[$rest:ident $($restargs:tt)*])* - const $($item:tt)* - ) => { - __impl_bitflags! { - $(#[$filtered])* - // $next filtered out - $(? #[$rest $($restargs)*])* - const $($item)* + + 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) + } + } + + #[allow( + dead_code, + deprecated, + unused_doc_comments, + unused_attributes, + unused_mut, + non_upper_case_globals + )] + 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 const fn from_bits(bits: $T) -> $crate::__private::core::option::Option { + let truncated = Self::from_bits_truncate(bits).bits; + + if truncated == bits { + $crate::__private::core::option::Option::Some(Self { bits }) + } else { + $crate::__private::core::option::Option::None + } + } + + #[inline] + pub const fn from_bits_truncate(bits: $T) -> Self { + if bits == <$T as $crate::__private::Bits>::EMPTY { + return Self { bits } + } + + let mut truncated = <$T as $crate::__private::Bits>::EMPTY; + + $( + $(#[$attr $($args)*])* + if bits & <$InternalBitFlags as $crate::__private::InternalFlags>::PublicFlags::$Flag.bits() == <$InternalBitFlags as $crate::__private::InternalFlags>::PublicFlags::$Flag.bits() { + truncated |= <$InternalBitFlags as $crate::__private::InternalFlags>::PublicFlags::$Flag.bits() + } + )* + + Self { bits: truncated } + } + + #[inline] + pub const fn from_bits_retain(bits: $T) -> Self { + Self { bits } + } + + #[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) + } + + pub fn iter(self) -> impl $crate::__private::core::iter::Iterator { + use $crate::__private::core::iter::Iterator as _; + + const NUM_FLAGS: usize = { + let mut num_flags = 0; + + $( + $(#[$attr $($args)*])* + { + num_flags += 1; + } + )* + + num_flags + }; + + const OPTIONS: [$T; NUM_FLAGS] = [ + $( + $(#[$attr $($args)*])* + <$InternalBitFlags as $crate::__private::InternalFlags>::PublicFlags::$Flag.bits(), + )* + ]; + + const OPTIONS_NAMES: [&'static str; NUM_FLAGS] = [ + $( + $(#[$attr $($args)*])* + $crate::__private::core::stringify!($Flag), + )* + ]; + + let mut start = 0; + let mut state = self; + + $crate::__private::core::iter::from_fn(move || { + if state.is_empty() || NUM_FLAGS == 0 { + $crate::__private::core::option::Option::None + } else { + for (flag, flag_name) in OPTIONS[start..NUM_FLAGS].iter().copied() + .zip(OPTIONS_NAMES[start..NUM_FLAGS].iter().copied()) + { + start += 1; + + // NOTE: We check whether the flag exists in self, but remove it from + // a different value. This ensure that overlapping flags are handled + // properly. Take the following example: + // + // const A: 0b00000001; + // const B: 0b00000101; + // + // Given the bits 0b00000101, both A and B are set. But if we removed A + // as we encountered it we'd be left with 0b00000100, which doesn't + // correspond to a valid flag on its own. + if self.contains(Self { bits: flag }) { + state.remove(Self { bits: flag }); + + return $crate::__private::core::option::Option::Some((flag_name, flag)) + } + } + + $crate::__private::core::option::Option::None + } + }) + } } - }; - ( - $(#[$filtered:meta])* - const $($item:tt)* - ) => { - $(#[$filtered])* - const $($item)* }; } diff --git a/tests/smoke-test/Cargo.toml b/tests/smoke-test/Cargo.toml new file mode 100644 index 00000000..f7265667 --- /dev/null +++ b/tests/smoke-test/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "bitflags-smoke-test" +version = "0.0.0" +edition = "2021" +publish = false + +[dependencies.bitflags] +path = "../../" diff --git a/tests/smoke-test/src/main.rs b/tests/smoke-test/src/main.rs new file mode 100644 index 00000000..9ff4305d --- /dev/null +++ b/tests/smoke-test/src/main.rs @@ -0,0 +1,15 @@ +use bitflags::bitflags; + +bitflags! { + #[derive(Debug)] + pub struct Flags: u32 { + const A = 0b00000001; + const B = 0b00000010; + const C = 0b00000100; + const ABC = Flags::A.bits() | Flags::B.bits() | Flags::C.bits(); + } +} + +fn main() { + println!("{:?}", Flags::ABC); +} From 8b4ab429219456a6642ff58c4d263e08f85d0c5d Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Wed, 1 Jun 2022 09:47:47 +1000 Subject: [PATCH 02/12] fix up actions --- .github/workflows/rust.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index f8c67c7c..5f3a4894 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -47,8 +47,7 @@ jobs: toolchain: ${{ matrix.channel }}-${{ matrix.rust_target }} - name: Tests - run: cargo test --features example_generated - run: cargo run --manifest-path tests/smoke-test/Cargo.toml + run: cargo test --features example_generated; cargo run --manifest-path tests/smoke-test/Cargo.toml embedded: name: Build (embedded) From b6ecc4b4e6829e8c3c57b94c787e0d7b731cc9f1 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Wed, 1 Jun 2022 10:34:25 +1000 Subject: [PATCH 03/12] get basic tests to pass again --- Cargo.toml | 6 +- src/lib.rs | 280 +++++++++++++++++++++++++++++++------------------ tests/basic.rs | 3 +- 3 files changed, 182 insertions(+), 107 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ade15fbc..0ff60e1d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,13 +19,13 @@ A macro to generate structures which behave like bitflags. exclude = ["tests", ".github"] [dependencies] -core = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-core' } -compiler_builtins = { version = '0.1.2', optional = true } +serde = { version = "1.0", optional = true } +core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" } +compiler_builtins = { version = "0.1.2", optional = true } [dev-dependencies] trybuild = "1.0" rustversion = "1.0" -serde = "1.0" serde_derive = "1.0" serde_json = "1.0" diff --git a/src/lib.rs b/src/lib.rs index b466f9f8..de8a3f40 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,7 @@ //! const A = 0b00000001; //! const B = 0b00000010; //! const C = 0b00000100; -//! const ABC = Self::A.bits | Self::B.bits | Self::C.bits; +//! const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits(); //! } //! } //! @@ -167,7 +167,7 @@ //! defined flag //! - `from_bits_truncate`: convert from underlying bit representation, dropping //! any bits that do not correspond to defined flags -//! - `from_bits_unchecked`: convert from underlying bit representation, keeping +//! - `from_bits_retain`: convert from underlying bit representation, keeping //! all bits (even those not corresponding to defined //! flags) //! - `is_empty`: `true` if no flags are currently stored @@ -352,7 +352,7 @@ the `__impl_bitflags_internal!` macro. /// const A = 0b00000001; /// const B = 0b00000010; /// const C = 0b00000100; -/// const ABC = Self::A.bits | Self::B.bits | Self::C.bits; +/// const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits(); /// } /// } /// @@ -432,7 +432,7 @@ macro_rules! bitflags { const _: () = { #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] - pub struct InternalFlags { + $vis struct InternalFlags { bits: $T, } @@ -888,6 +888,13 @@ macro_rules! __impl_internal_bitflags { )* } ) => { + impl $crate::__private::core::default::Default for $InternalBitFlags { + #[inline] + fn default() -> Self { + $InternalBitFlags::empty() + } + } + impl $crate::__private::core::fmt::Debug for $InternalBitFlags { fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result { // Iterate over the valid flags @@ -913,7 +920,7 @@ macro_rules! __impl_internal_bitflags { } if first { - f.write_str("(empty)")?; + f.write_str("empty")?; } $crate::__private::core::fmt::Result::Ok(()) @@ -1143,6 +1150,57 @@ macro_rules! __impl_internal_bitflags { }; } +// Optional features +// +// These macros implement additional library traits for the internal bitflags type so that +// the end-user can either implement or derive those same traits based on the implementation +// we provide in `bitflags`. +// +// These macros all follow a similar pattern. If an optional feature of `bitflags` is enabled +// they'll expand to some impl blocks based on a re-export of the library. If the optional feature +// is not enabled then they expand to a no-op. + +/// Implement `Serialize` and `Deserialize` for the internal bitflags type. +#[macro_export(local_inner_macros)] +#[doc(hidden)] +#[cfg(feature = "serde")] +macro_rules! __impl_internal_bitflags_serde { + ( + $InternalBitFlags:ident: $T:ty { + $( + $(#[$attr:ident $($args:tt)*])* + $Flag:ident; + )* + } + ) => { + impl $crate::__private::serde::Serialize for $InternalBitflags { + fn serialize(&self, serializer: S) -> $crate::__private::Result { + todo!() + } + } + + impl<'de> $crate::__private::serde::Deserialize<'de> for $InternalBitFlags { + fn deserialize>(&self, deserializer: D) -> $crate::__private::Result { + todo!() + } + } + } +} + +#[macro_export(local_inner_macros)] +#[doc(hidden)] +#[cfg(not(feature = "serde"))] +macro_rules! __impl_internal_bitflags_serde { + ( + $InternalBitFlags:ident: $T:ty { + $( + $(#[$attr:ident $($args:tt)*])* + $Flag:ident; + )* + } + ) => { } +} + #[cfg(feature = "example_generated")] pub mod example_generated; @@ -1156,7 +1214,7 @@ mod tests { #[doc = "> you are the easiest person to fool."] #[doc = "> "] #[doc = "> - Richard Feynman"] - #[derive(Default)] + #[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] struct Flags: u32 { const A = 0b00000001; #[doc = " macros are way better at generating code than trans is"] @@ -1165,28 +1223,32 @@ mod tests { #[doc = "* cmr bed"] #[doc = "* strcat table"] #[doc = " wait what?"] - const ABC = Self::A.bits | Self::B.bits | Self::C.bits; + const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits(); } + #[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] struct _CfgFlags: u32 { #[cfg(unix)] const _CFG_A = 0b01; #[cfg(windows)] const _CFG_B = 0b01; #[cfg(unix)] - const _CFG_C = Self::_CFG_A.bits | 0b10; + const _CFG_C = Self::_CFG_A.bits() | 0b10; } + #[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] struct AnotherSetOfFlags: i8 { const ANOTHER_FLAG = -1_i8; } + #[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] struct LongFlags: u32 { const LONG_A = 0b1111111111111111; } } bitflags! { + #[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] struct EmptyFlags: u32 { } } @@ -1239,28 +1301,28 @@ mod tests { } #[test] - fn test_from_bits_unchecked() { - let extra = unsafe { Flags::from_bits_unchecked(0b1000) }; - assert_eq!(unsafe { Flags::from_bits_unchecked(0) }, Flags::empty()); - assert_eq!(unsafe { Flags::from_bits_unchecked(0b1) }, Flags::A); - assert_eq!(unsafe { Flags::from_bits_unchecked(0b10) }, Flags::B); + fn test_from_bits_retain() { + let extra = Flags::from_bits_retain(0b1000); + assert_eq!(Flags::from_bits_retain(0), Flags::empty()); + assert_eq!(Flags::from_bits_retain(0b1), Flags::A); + assert_eq!(Flags::from_bits_retain(0b10), Flags::B); assert_eq!( - unsafe { Flags::from_bits_unchecked(0b11) }, + Flags::from_bits_retain(0b11), (Flags::A | Flags::B) ); assert_eq!( - unsafe { Flags::from_bits_unchecked(0b1000) }, + Flags::from_bits_retain(0b1000), (extra | Flags::empty()) ); assert_eq!( - unsafe { Flags::from_bits_unchecked(0b1001) }, + Flags::from_bits_retain(0b1001), (extra | Flags::A) ); - let extra = unsafe { EmptyFlags::from_bits_unchecked(0b1000) }; + let extra = EmptyFlags::from_bits_retain(0b1000); assert_eq!( - unsafe { EmptyFlags::from_bits_unchecked(0b1000) }, + EmptyFlags::from_bits_retain(0b1000), (extra | EmptyFlags::empty()) ); } @@ -1283,7 +1345,7 @@ mod tests { assert!(!Flags::A.is_all()); assert!(Flags::ABC.is_all()); - let extra = unsafe { Flags::from_bits_unchecked(0b1000) }; + let extra = Flags::from_bits_retain(0b1000); assert!(!extra.is_all()); assert!(!(Flags::A | extra).is_all()); assert!((Flags::ABC | extra).is_all()); @@ -1381,7 +1443,7 @@ mod tests { #[test] fn test_operators_unchecked() { - let extra = unsafe { Flags::from_bits_unchecked(0b1000) }; + let extra = Flags::from_bits_retain(0b1000); let e1 = Flags::A | Flags::C | extra; let e2 = Flags::B | Flags::C; assert_eq!((e1 | e2), (Flags::ABC | extra)); // union @@ -1400,9 +1462,9 @@ mod tests { let ab = Flags::A.union(Flags::B); let ac = Flags::A.union(Flags::C); let bc = Flags::B.union(Flags::C); - assert_eq!(ab.bits, 0b011); - assert_eq!(bc.bits, 0b110); - assert_eq!(ac.bits, 0b101); + assert_eq!(ab.bits(), 0b011); + assert_eq!(bc.bits(), 0b110); + assert_eq!(ac.bits(), 0b101); assert_eq!(ab, Flags::B.union(Flags::A)); assert_eq!(ac, Flags::C.union(Flags::A)); @@ -1455,10 +1517,10 @@ mod tests { #[test] fn test_set_ops_unchecked() { - let extra = unsafe { Flags::from_bits_unchecked(0b1000) }; + let extra = Flags::from_bits_retain(0b1000); let e1 = Flags::A.union(Flags::C).union(extra); let e2 = Flags::B.union(Flags::C); - assert_eq!(e1.bits, 0b1101); + assert_eq!(e1.bits(), 0b1101); assert_eq!(e1.union(e2), (Flags::ABC | extra)); assert_eq!(e1.intersection(e2), Flags::C); assert_eq!(e1.difference(e2), Flags::A | extra); @@ -1472,11 +1534,12 @@ mod tests { fn test_set_ops_exhaustive() { // Define a flag that contains gaps to help exercise edge-cases, // especially around "unknown" flags (e.g. ones outside of `all()` - // `from_bits_unchecked`). + // `from_bits_retain`). // - when lhs and rhs both have different sets of unknown flags. // - unknown flags at both ends, and in the middle // - cases with "gaps". bitflags! { + #[derive(Debug, PartialEq, Eq)] struct Test: u16 { // Intentionally no `A` const B = 0b000000010; @@ -1490,12 +1553,12 @@ mod tests { } } let iter_test_flags = - || (0..=0b111_1111_1111).map(|bits| unsafe { Test::from_bits_unchecked(bits) }); + || (0..=0b111_1111_1111).map(|bits| Test::from_bits_retain(bits)); for a in iter_test_flags() { assert_eq!( a.complement(), - Test::from_bits_truncate(!a.bits), + Test::from_bits_truncate(!a.bits()), "wrong result: !({:?})", a, ); @@ -1504,37 +1567,37 @@ mod tests { // Check that the named operations produce the expected bitwise // values. assert_eq!( - a.union(b).bits, - a.bits | b.bits, + a.union(b).bits(), + a.bits() | b.bits(), "wrong result: `{:?}` | `{:?}`", a, b, ); assert_eq!( - a.intersection(b).bits, - a.bits & b.bits, + a.intersection(b).bits(), + a.bits() & b.bits(), "wrong result: `{:?}` & `{:?}`", a, b, ); assert_eq!( - a.symmetric_difference(b).bits, - a.bits ^ b.bits, + a.symmetric_difference(b).bits(), + a.bits() ^ b.bits(), "wrong result: `{:?}` ^ `{:?}`", a, b, ); assert_eq!( - a.difference(b).bits, - a.bits & !b.bits, + a.difference(b).bits(), + a.bits() & !b.bits(), "wrong result: `{:?}` - `{:?}`", a, b, ); // Note: Difference is checked as both `a - b` and `b - a` assert_eq!( - b.difference(a).bits, - b.bits & !a.bits, + b.difference(a).bits(), + b.bits() & !a.bits(), "wrong result: `{:?}` - `{:?}`", b, a, @@ -1703,28 +1766,28 @@ mod tests { #[test] fn test_debug() { - assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); - assert_eq!(format!("{:?}", Flags::empty()), "(empty)"); - assert_eq!(format!("{:?}", Flags::ABC), "A | B | C"); + assert_eq!(format!("{:?}", Flags::A | Flags::B), "Flags(A | B)"); + assert_eq!(format!("{:?}", Flags::empty()), "Flags(empty)"); + assert_eq!(format!("{:?}", Flags::ABC), "Flags(A | B | C)"); - let extra = unsafe { Flags::from_bits_unchecked(0xb8) }; + let extra = Flags::from_bits_retain(0xb8); - assert_eq!(format!("{:?}", extra), "0xb8"); - assert_eq!(format!("{:?}", Flags::A | extra), "A | 0xb8"); + assert_eq!(format!("{:?}", extra), "Flags(0xb8)"); + assert_eq!(format!("{:?}", Flags::A | extra), "Flags(A | 0xb8)"); assert_eq!( format!("{:?}", Flags::ABC | extra), - "A | B | C | ABC | 0xb8" + "Flags(A | B | C | ABC | 0xb8)" ); - assert_eq!(format!("{:?}", EmptyFlags::empty()), "(empty)"); + assert_eq!(format!("{:?}", EmptyFlags::empty()), "EmptyFlags(empty)"); } #[test] fn test_binary() { assert_eq!(format!("{:b}", Flags::ABC), "111"); assert_eq!(format!("{:#b}", Flags::ABC), "0b111"); - let extra = unsafe { Flags::from_bits_unchecked(0b1010000) }; + let extra = Flags::from_bits_retain(0b1010000); assert_eq!(format!("{:b}", Flags::ABC | extra), "1010111"); assert_eq!(format!("{:#b}", Flags::ABC | extra), "0b1010111"); } @@ -1733,7 +1796,7 @@ mod tests { fn test_octal() { assert_eq!(format!("{:o}", LongFlags::LONG_A), "177777"); assert_eq!(format!("{:#o}", LongFlags::LONG_A), "0o177777"); - let extra = unsafe { LongFlags::from_bits_unchecked(0o5000000) }; + let extra = LongFlags::from_bits_retain(0o5000000); assert_eq!(format!("{:o}", LongFlags::LONG_A | extra), "5177777"); assert_eq!(format!("{:#o}", LongFlags::LONG_A | extra), "0o5177777"); } @@ -1742,7 +1805,7 @@ mod tests { fn test_lowerhex() { assert_eq!(format!("{:x}", LongFlags::LONG_A), "ffff"); assert_eq!(format!("{:#x}", LongFlags::LONG_A), "0xffff"); - let extra = unsafe { LongFlags::from_bits_unchecked(0xe00000) }; + let extra = LongFlags::from_bits_retain(0xe00000); assert_eq!(format!("{:x}", LongFlags::LONG_A | extra), "e0ffff"); assert_eq!(format!("{:#x}", LongFlags::LONG_A | extra), "0xe0ffff"); } @@ -1751,7 +1814,7 @@ mod tests { fn test_upperhex() { assert_eq!(format!("{:X}", LongFlags::LONG_A), "FFFF"); assert_eq!(format!("{:#X}", LongFlags::LONG_A), "0xFFFF"); - let extra = unsafe { LongFlags::from_bits_unchecked(0xe00000) }; + let extra = LongFlags::from_bits_retain(0xe00000); assert_eq!(format!("{:X}", LongFlags::LONG_A | extra), "E0FFFF"); assert_eq!(format!("{:#X}", LongFlags::LONG_A | extra), "0xE0FFFF"); } @@ -1798,14 +1861,15 @@ mod tests { #[test] fn test_in_function() { bitflags! { - struct Flags: u8 { + #[derive(Debug, PartialEq, Eq)] + struct Flags: u8 { const A = 1; #[cfg(any())] // false const B = 2; } } assert_eq!(Flags::all(), Flags::A); - assert_eq!(format!("{:?}", Flags::A), "A"); + assert_eq!(format!("{:?}", Flags::A), "Flags(A)"); } #[test] @@ -1863,6 +1927,7 @@ mod tests { #[test] fn test_zero_value_flags() { bitflags! { + #[derive(Debug, PartialEq, Eq)] struct Flags: u32 { const NONE = 0b0; const SOME = 0b1; @@ -1873,8 +1938,8 @@ mod tests { assert!(Flags::SOME.contains(Flags::NONE)); assert!(Flags::NONE.is_empty()); - assert_eq!(format!("{:?}", Flags::empty()), "(empty)"); - assert_eq!(format!("{:?}", Flags::SOME), "NONE | SOME"); + assert_eq!(format!("{:?}", Flags::empty()), "Flags(empty)"); + assert_eq!(format!("{:?}", Flags::SOME), "Flags(NONE | SOME)"); } #[test] @@ -1885,69 +1950,33 @@ mod tests { #[test] fn test_u128_bitflags() { bitflags! { - struct Flags128: u128 { + #[derive(Debug, PartialEq, Eq)] + struct Flags: u128 { const A = 0x0000_0000_0000_0000_0000_0000_0000_0001; const B = 0x0000_0000_0000_1000_0000_0000_0000_0000; const C = 0x8000_0000_0000_0000_0000_0000_0000_0000; - const ABC = Self::A.bits | Self::B.bits | Self::C.bits; + const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits(); } } - assert_eq!(Flags128::ABC, Flags128::A | Flags128::B | Flags128::C); - assert_eq!(Flags128::A.bits, 0x0000_0000_0000_0000_0000_0000_0000_0001); - assert_eq!(Flags128::B.bits, 0x0000_0000_0000_1000_0000_0000_0000_0000); - assert_eq!(Flags128::C.bits, 0x8000_0000_0000_0000_0000_0000_0000_0000); + assert_eq!(Flags::ABC, Flags::A | Flags::B | Flags::C); + assert_eq!(Flags::A.bits(), 0x0000_0000_0000_0000_0000_0000_0000_0001); + assert_eq!(Flags::B.bits(), 0x0000_0000_0000_1000_0000_0000_0000_0000); + assert_eq!(Flags::C.bits(), 0x8000_0000_0000_0000_0000_0000_0000_0000); assert_eq!( - Flags128::ABC.bits, + Flags::ABC.bits(), 0x8000_0000_0000_1000_0000_0000_0000_0001 ); - assert_eq!(format!("{:?}", Flags128::A), "A"); - assert_eq!(format!("{:?}", Flags128::B), "B"); - assert_eq!(format!("{:?}", Flags128::C), "C"); - assert_eq!(format!("{:?}", Flags128::ABC), "A | B | C"); - } - - #[test] - fn test_serde_bitflags_serialize() { - let flags = SerdeFlags::A | SerdeFlags::B; - - let serialized = serde_json::to_string(&flags).unwrap(); - - assert_eq!(serialized, r#"{"bits":3}"#); - } - - #[test] - fn test_serde_bitflags_deserialize() { - let deserialized: SerdeFlags = serde_json::from_str(r#"{"bits":12}"#).unwrap(); - - let expected = SerdeFlags::C | SerdeFlags::D; - - assert_eq!(deserialized.bits, expected.bits); - } - - #[test] - fn test_serde_bitflags_roundtrip() { - let flags = SerdeFlags::A | SerdeFlags::B; - - let deserialized: SerdeFlags = - serde_json::from_str(&serde_json::to_string(&flags).unwrap()).unwrap(); - - assert_eq!(deserialized.bits, flags.bits); - } - - bitflags! { - #[derive(serde_derive::Serialize, serde_derive::Deserialize)] - struct SerdeFlags: u32 { - const A = 1; - const B = 2; - const C = 4; - const D = 8; - } + assert_eq!(format!("{:?}", Flags::A), "Flags(A)"); + assert_eq!(format!("{:?}", Flags::B), "Flags(B)"); + assert_eq!(format!("{:?}", Flags::C), "Flags(C)"); + assert_eq!(format!("{:?}", Flags::ABC), "Flags(A | B | C)"); } #[test] fn test_from_bits_edge_cases() { bitflags! { + #[derive(Debug, PartialEq, Eq)] struct Flags: u8 { const A = 0b00000001; const BC = 0b00000110; @@ -1963,6 +1992,7 @@ mod tests { #[test] fn test_from_bits_truncate_edge_cases() { bitflags! { + #[derive(Debug, PartialEq, Eq)] struct Flags: u8 { const A = 0b00000001; const BC = 0b00000110; @@ -1978,6 +2008,7 @@ mod tests { #[test] fn test_iter() { bitflags! { + #[derive(Debug, PartialEq, Eq)] struct Flags: u32 { const ONE = 0b001; const TWO = 0b010; @@ -2040,4 +2071,47 @@ mod tests { assert_eq!(iter.next().unwrap(), ("THREE", Flags::THREE)); assert_eq!(iter.next(), None); } + + #[cfg(feature = "serde")] + mod serde_support { + use super::*; + + bitflags! { + #[derive(serde_derive::Serialize, serde_derive::Deserialize)] + struct SerdeFlags: u32 { + const A = 1; + const B = 2; + const C = 4; + const D = 8; + } + } + + #[test] + fn test_serde_bitflags_serialize() { + let flags = SerdeFlags::A | SerdeFlags::B; + + let serialized = serde_json::to_string(&flags).unwrap(); + + assert_eq!(serialized, r#"{"bits":3}"#); + } + + #[test] + fn test_serde_bitflags_deserialize() { + let deserialized: SerdeFlags = serde_json::from_str(r#"{"bits":12}"#).unwrap(); + + let expected = SerdeFlags::C | SerdeFlags::D; + + assert_eq!(deserialized.bits(), expected.bits()); + } + + #[test] + fn test_serde_bitflags_roundtrip() { + let flags = SerdeFlags::A | SerdeFlags::B; + + let deserialized: SerdeFlags = + serde_json::from_str(&serde_json::to_string(&flags).unwrap()).unwrap(); + + assert_eq!(deserialized.bits(), flags.bits()); + } + } } diff --git a/tests/basic.rs b/tests/basic.rs index 73a52bec..790ec41c 100644 --- a/tests/basic.rs +++ b/tests/basic.rs @@ -4,13 +4,14 @@ use bitflags::bitflags; bitflags! { /// baz + #[derive(Debug, PartialEq, Eq)] 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; + const ABC = Flags::A.bits() | Flags::B.bits() | Flags::C.bits(); } } From 937bc44a7a0c52730c978edba03011e840f105ff Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Wed, 1 Jun 2022 10:45:02 +1000 Subject: [PATCH 04/12] test optional features --- .github/workflows/rust.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 5f3a4894..f00ed6c2 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -46,8 +46,17 @@ jobs: profile: minimal toolchain: ${{ matrix.channel }}-${{ matrix.rust_target }} - - name: Tests - run: cargo test --features example_generated; cargo run --manifest-path tests/smoke-test/Cargo.toml + - name: Install cargo-hack + run: cargo install cargo-hack + + - name: Powerset + run: cargo hack test --feature-powerset --lib --optional-deps "serde" --depth 3 --skip rustc-dep-of-std + + - name: Docs + run: cargo doc --features example_generated + + - name: Smoke test + run: cargo run --manifest-path tests/smoke-test/Cargo.toml embedded: name: Build (embedded) From 014a469a9f284838c450842b6a8cd4947f86f51b Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Wed, 1 Jun 2022 12:14:23 +1000 Subject: [PATCH 05/12] add serde support --- src/lib.rs | 70 ++++++++++++------------------------ src/serde_support.rs | 84 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 48 deletions(-) create mode 100644 src/serde_support.rs diff --git a/src/lib.rs b/src/lib.rs index de8a3f40..15766d8b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -287,6 +287,9 @@ mod bitflags_trait; pub mod __private { pub use crate::bitflags_trait::{Bits, ImplementedByBitFlagsMacro, InternalFlags, PublicFlags}; pub use core; + + #[cfg(feature = "serde")] + pub use serde; } /* @@ -445,6 +448,15 @@ macro_rules! bitflags { } } + __impl_internal_bitflags_serde! { + InternalFlags: $T { + $( + $(#[$inner $($args)*])* + $Flag; + )* + } + } + impl $crate::__private::InternalFlags for InternalFlags { type PublicFlags = $BitFlags; } @@ -1173,15 +1185,17 @@ macro_rules! __impl_internal_bitflags_serde { )* } ) => { - impl $crate::__private::serde::Serialize for $InternalBitflags { - fn serialize(&self, serializer: S) -> $crate::__private::Result { - todo!() + impl $crate::__private::serde::Serialize for $InternalBitFlags { + fn serialize(&self, serializer: S) -> $crate::__private::core::result::Result { + $crate::serde_support::serialize_bits_default($crate::__private::core::stringify!($InternalBitFlags), &self.bits, serializer) } } impl<'de> $crate::__private::serde::Deserialize<'de> for $InternalBitFlags { - fn deserialize>(&self, deserializer: D) -> $crate::__private::Result { - todo!() + fn deserialize>(deserializer: D) -> $crate::__private::core::result::Result { + let bits = $crate::serde_support::deserialize_bits_default($crate::__private::core::stringify!($InternalBitFlags), deserializer)?; + + $crate::__private::result::Result::Ok($InternalBitFlags::from_bits_retain(bits)) } } } @@ -1204,6 +1218,9 @@ macro_rules! __impl_internal_bitflags_serde { #[cfg(feature = "example_generated")] pub mod example_generated; +#[cfg(feature = "serde")] +pub mod serde_support; + #[cfg(test)] mod tests { use std::collections::hash_map::DefaultHasher; @@ -2071,47 +2088,4 @@ mod tests { assert_eq!(iter.next().unwrap(), ("THREE", Flags::THREE)); assert_eq!(iter.next(), None); } - - #[cfg(feature = "serde")] - mod serde_support { - use super::*; - - bitflags! { - #[derive(serde_derive::Serialize, serde_derive::Deserialize)] - struct SerdeFlags: u32 { - const A = 1; - const B = 2; - const C = 4; - const D = 8; - } - } - - #[test] - fn test_serde_bitflags_serialize() { - let flags = SerdeFlags::A | SerdeFlags::B; - - let serialized = serde_json::to_string(&flags).unwrap(); - - assert_eq!(serialized, r#"{"bits":3}"#); - } - - #[test] - fn test_serde_bitflags_deserialize() { - let deserialized: SerdeFlags = serde_json::from_str(r#"{"bits":12}"#).unwrap(); - - let expected = SerdeFlags::C | SerdeFlags::D; - - assert_eq!(deserialized.bits(), expected.bits()); - } - - #[test] - fn test_serde_bitflags_roundtrip() { - let flags = SerdeFlags::A | SerdeFlags::B; - - let deserialized: SerdeFlags = - serde_json::from_str(&serde_json::to_string(&flags).unwrap()).unwrap(); - - assert_eq!(deserialized.bits(), flags.bits()); - } - } } diff --git a/src/serde_support.rs b/src/serde_support.rs new file mode 100644 index 00000000..41cf1128 --- /dev/null +++ b/src/serde_support.rs @@ -0,0 +1,84 @@ +use core::fmt; +use serde::{Serializer, Deserializer, Serialize, Deserialize, ser::SerializeStruct, de::{Error, MapAccess, Visitor}}; + +// These methods are compatible with the result of `#[derive(Serialize, Deserialize)]` on bitflags `1.0` types + +pub fn serialize_bits_default(name: &'static str, bits: &B, serializer: S) -> Result { + let mut serialize_struct = serializer.serialize_struct(name, 1)?; + serialize_struct.serialize_field("bits", bits)?; + serialize_struct.end() +} + +pub fn deserialize_bits_default<'de, B: Deserialize<'de>, D: Deserializer<'de>>(name: &'static str, deserializer: D) -> Result { + struct BitsVisitor(core::marker::PhantomData); + + impl<'de, T: Deserialize<'de>> Visitor<'de> for BitsVisitor { + type Value = T; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a primitive bitflags value wrapped in a struct") + } + + fn visit_map>(self, mut map: A) -> Result { + let mut bits = None; + + while let Some(key) = map.next_key()? { + match key { + "bits" => { + if bits.is_some() { + return Err(Error::duplicate_field("bits")); + } + + bits = Some(map.next_value()?); + } + v => return Err(Error::unknown_field(v, &["bits"])) + } + } + + bits.ok_or_else(|| Error::missing_field("bits")) + } + } + + deserializer.deserialize_struct(name, &["bits"], BitsVisitor(Default::default())) +} + +#[cfg(test)] +mod tests { + bitflags! { + #[derive(serde_derive::Serialize, serde_derive::Deserialize)] + struct SerdeFlags: u32 { + const A = 1; + const B = 2; + const C = 4; + const D = 8; + } + } + + #[test] + fn test_serde_bitflags_default_serialize() { + let flags = SerdeFlags::A | SerdeFlags::B; + + let serialized = serde_json::to_string(&flags).unwrap(); + + assert_eq!(serialized, r#"{"bits":3}"#); + } + + #[test] + fn test_serde_bitflags_default_deserialize() { + let deserialized: SerdeFlags = serde_json::from_str(r#"{"bits":12}"#).unwrap(); + + let expected = SerdeFlags::C | SerdeFlags::D; + + assert_eq!(deserialized.bits(), expected.bits()); + } + + #[test] + fn test_serde_bitflags_default_roundtrip() { + let flags = SerdeFlags::A | SerdeFlags::B; + + let deserialized: SerdeFlags = + serde_json::from_str(&serde_json::to_string(&flags).unwrap()).unwrap(); + + assert_eq!(deserialized.bits(), flags.bits()); + } +} \ No newline at end of file From 02af3a1b254b3df314034e488981e19e81e3a9a8 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Thu, 28 Jul 2022 10:21:44 +1000 Subject: [PATCH 06/12] Update src/lib.rs Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com> --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 15766d8b..5ddd63d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -317,7 +317,7 @@ What they'd end up with looks something like this: ```rust pub struct MyFlags(::InternalFlags); -const _: () { +const _: () = { #[repr(transparent)] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct MyInternalFlags { From b16c0de364a7f525c4ff30f271e121850f8a9fe6 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Thu, 11 Aug 2022 11:24:16 +1000 Subject: [PATCH 07/12] work on fixing up compile-pass tests --- src/lib.rs | 6 ++- tests/compile-fail/redefined.rs | 14 +++++ tests/compile-fail/syntax/missing_type.rs | 8 +++ tests/compile-fail/syntax/missing_value.rs | 8 +++ tests/compile-fail/visibility/bits_field.rs | 12 +++++ .../compile-fail/visibility/private_field.rs | 2 +- .../visibility/private_field.stderr | 8 +-- .../compile-fail/visibility/private_flags.rs | 4 +- tests/compile-pass/impls/fmt.rs | 7 +-- tests/compile-pass/item_positions.rs | 52 +++++++++++++++++++ tests/compile-pass/no_prelude.rs | 2 +- tests/compile-pass/redefinition/macros.rs | 3 +- tests/compile-pass/visibility/bits_field.rs | 2 +- 13 files changed, 113 insertions(+), 15 deletions(-) create mode 100644 tests/compile-fail/redefined.rs create mode 100644 tests/compile-fail/syntax/missing_type.rs create mode 100644 tests/compile-fail/syntax/missing_value.rs create mode 100644 tests/compile-fail/visibility/bits_field.rs create mode 100644 tests/compile-pass/item_positions.rs diff --git a/src/lib.rs b/src/lib.rs index 5ddd63d9..583d80fd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -549,8 +549,8 @@ macro_rules! __impl_public_bitflags { #[inline] pub const fn from_bits(bits: $T) -> $crate::__private::core::option::Option { match <$PublicBitFlags as $crate::__private::PublicFlags>::InternalFlags::from_bits(bits) { - Some(bits) => Some(Self(bits)), - None => None, + $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, } } @@ -716,6 +716,8 @@ macro_rules! __impl_public_bitflags { /// Returns an iterator over set flags and their names. pub fn iter(self) -> impl $crate::__private::core::iter::Iterator { + use $crate::__private::core::iter::Iterator as _; + self.0.iter().map(|(name, bits)| (name, Self::from_bits_retain(bits))) } diff --git a/tests/compile-fail/redefined.rs b/tests/compile-fail/redefined.rs new file mode 100644 index 00000000..6d194d6c --- /dev/null +++ b/tests/compile-fail/redefined.rs @@ -0,0 +1,14 @@ +#[macro_use] +extern crate bitflags; + +bitflags! { + pub struct Flags1 { + const A = 1; + } +} + +bitflags! { + pub struct Flags1 { + const A = 1; + } +} diff --git a/tests/compile-fail/syntax/missing_type.rs b/tests/compile-fail/syntax/missing_type.rs new file mode 100644 index 00000000..323b8583 --- /dev/null +++ b/tests/compile-fail/syntax/missing_type.rs @@ -0,0 +1,8 @@ +#[macro_use] +extern crate bitflags; + +bitflags! { + pub struct Flags1 { + const A = 1; + } +} diff --git a/tests/compile-fail/syntax/missing_value.rs b/tests/compile-fail/syntax/missing_value.rs new file mode 100644 index 00000000..c1221035 --- /dev/null +++ b/tests/compile-fail/syntax/missing_value.rs @@ -0,0 +1,8 @@ +#[macro_use] +extern crate bitflags; + +bitflags! { + pub struct Flags1 { + const A; + } +} diff --git a/tests/compile-fail/visibility/bits_field.rs b/tests/compile-fail/visibility/bits_field.rs new file mode 100644 index 00000000..2e0d5c52 --- /dev/null +++ b/tests/compile-fail/visibility/bits_field.rs @@ -0,0 +1,12 @@ +#[macro_use] +extern crate bitflags; + +bitflags! { + pub struct Flags1: u32 { + const A = 1; + } +} + +fn main() { + let _ = Flags1::A.0.bits; +} diff --git a/tests/compile-fail/visibility/private_field.rs b/tests/compile-fail/visibility/private_field.rs index a6a3912a..b1d95b18 100644 --- a/tests/compile-fail/visibility/private_field.rs +++ b/tests/compile-fail/visibility/private_field.rs @@ -9,5 +9,5 @@ mod example { } fn main() { - let flag1 = example::Flags1::FLAG_A.bits; + let _ = example::Flags1::FLAG_A.bits; } diff --git a/tests/compile-fail/visibility/private_field.stderr b/tests/compile-fail/visibility/private_field.stderr index e1146989..18c0cdd1 100644 --- a/tests/compile-fail/visibility/private_field.stderr +++ b/tests/compile-fail/visibility/private_field.stderr @@ -1,10 +1,10 @@ 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 +12 | let _ = 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(); - | ++ +12 | let _ = example::Flags1::FLAG_A.bits(); + | ++ diff --git a/tests/compile-fail/visibility/private_flags.rs b/tests/compile-fail/visibility/private_flags.rs index 85a5b186..a132d2f9 100644 --- a/tests/compile-fail/visibility/private_flags.rs +++ b/tests/compile-fail/visibility/private_flags.rs @@ -13,6 +13,6 @@ mod example { } fn main() { - let flag1 = example::Flags1::FLAG_A; - let flag2 = example::Flags2::FLAG_B; + let _ = example::Flags1::FLAG_A; + let _ = example::Flags2::FLAG_B; } diff --git a/tests/compile-pass/impls/fmt.rs b/tests/compile-pass/impls/fmt.rs index 567fd448..93dbf1b1 100644 --- a/tests/compile-pass/impls/fmt.rs +++ b/tests/compile-pass/impls/fmt.rs @@ -1,6 +1,7 @@ use bitflags::bitflags; bitflags! { + #[derive(Debug)] struct Flags: u8 { const TWO = 0x2; } @@ -8,7 +9,7 @@ bitflags! { fn main() { // bug #267 (https://github.com/bitflags/bitflags/issues/267) - let flags = unsafe { Flags::from_bits_unchecked(0b11) }; - assert_eq!(format!("{:?}", flags), "TWO | 0x1"); - assert_eq!(format!("{:#?}", flags), "TWO | 0x1"); + let flags = Flags::from_bits_retain(0b11); + assert_eq!(format!("{:?}", flags), "Flags(TWO | 0x1)"); + assert_eq!(format!("{:#?}", flags), "Flags(\n TWO | 0x1,\n)"); } diff --git a/tests/compile-pass/item_positions.rs b/tests/compile-pass/item_positions.rs new file mode 100644 index 00000000..def7bbe3 --- /dev/null +++ b/tests/compile-pass/item_positions.rs @@ -0,0 +1,52 @@ +#[macro_use] +extern crate bitflags; + +bitflags! { + pub struct Flags1: u32 { + const A = 1; + } +} + +bitflags! { + pub struct Flags2: u32 { + const A = 1; + } +} + +pub mod nested { + bitflags! { + pub struct Flags1: u32 { + const A = 1; + } + } + + bitflags! { + pub struct Flags2: u32 { + const A = 1; + } + } +} + +pub const _: () = { + bitflags! { + pub struct Flags1: u32 { + const A = 1; + } + } +}; + +fn main() { + bitflags! { + pub struct Flags1: u32 { + const A = 1; + } + } + + let _ = { + bitflags! { + pub struct Flags2: u32 { + const A = 1; + } + } + }; +} diff --git a/tests/compile-pass/no_prelude.rs b/tests/compile-pass/no_prelude.rs index c54b7a31..b1c57dac 100644 --- a/tests/compile-pass/no_prelude.rs +++ b/tests/compile-pass/no_prelude.rs @@ -7,7 +7,7 @@ bitflags::bitflags! { const A = 0b00000001; const B = 0b00000010; const C = 0b00000100; - const ABC = Flags::A.bits | Flags::B.bits | Flags::C.bits; + const ABC = Flags::A.bits() | Flags::B.bits() | Flags::C.bits(); } } diff --git a/tests/compile-pass/redefinition/macros.rs b/tests/compile-pass/redefinition/macros.rs index a9835124..cfff19ab 100644 --- a/tests/compile-pass/redefinition/macros.rs +++ b/tests/compile-pass/redefinition/macros.rs @@ -13,6 +13,7 @@ macro_rules! write { } bitflags! { + #[derive(Debug)] struct Test: u8 { const A = 1; } @@ -20,5 +21,5 @@ bitflags! { fn main() { // Just make sure we don't call the redefined `stringify` or `write` macro - assert_eq!(format!("{:?}", unsafe { Test::from_bits_unchecked(0b11) }), "A | 0x2"); + assert_eq!(format!("{:?}", Test::from_bits_retain(0b11)), "Test(A | 0x2)"); } diff --git a/tests/compile-pass/visibility/bits_field.rs b/tests/compile-pass/visibility/bits_field.rs index 33a7967e..5b0c6e43 100644 --- a/tests/compile-pass/visibility/bits_field.rs +++ b/tests/compile-pass/visibility/bits_field.rs @@ -7,5 +7,5 @@ bitflags! { } fn main() { - assert_eq!(0b00000001, Flags1::FLAG_A.bits); + assert_eq!(0b00000001, Flags1::FLAG_A.bits()); } From 00d7482d896ab1828d7681d9acdf2085225376ee Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Thu, 11 Aug 2022 14:09:13 +1000 Subject: [PATCH 08/12] fix up more tests --- src/lib.rs | 42 ++-- tests/compile-fail/impls/copy.stderr | 16 +- tests/compile-fail/impls/eq.stderr | 55 ---- .../non_integer_base/all_defined.stderr | 238 +++++++++++++++++- .../non_integer_base/all_missing.stderr | 4 +- tests/compile-fail/redefined.stderr | 17 ++ tests/compile-fail/syntax/missing_type.stderr | 11 + .../compile-fail/syntax/missing_value.stderr | 11 + tests/compile-fail/trait/custom_impl.rs | 2 +- tests/compile-fail/visibility/bits_field.rs | 12 - .../compile-fail/visibility/private_field.rs | 13 - .../visibility/private_field.stderr | 10 - .../visibility/private_flags.stderr | 8 +- .../impls/eq.rs | 0 tests/smoke-test/out.rs | Bin 0 -> 56456 bytes 15 files changed, 305 insertions(+), 134 deletions(-) delete mode 100644 tests/compile-fail/impls/eq.stderr create mode 100644 tests/compile-fail/redefined.stderr create mode 100644 tests/compile-fail/syntax/missing_type.stderr create mode 100644 tests/compile-fail/syntax/missing_value.stderr delete mode 100644 tests/compile-fail/visibility/bits_field.rs delete mode 100644 tests/compile-fail/visibility/private_field.rs delete mode 100644 tests/compile-fail/visibility/private_field.stderr rename tests/{compile-fail => compile-pass}/impls/eq.rs (100%) create mode 100644 tests/smoke-test/out.rs diff --git a/src/lib.rs b/src/lib.rs index 583d80fd..4d868448 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,6 +21,7 @@ //! use bitflags::bitflags; //! //! bitflags! { +//! #[derive(Debug, PartialEq, Eq, Hash)] //! struct Flags: u32 { //! const A = 0b00000001; //! const B = 0b00000010; @@ -51,6 +52,7 @@ //! use bitflags::bitflags; //! //! bitflags! { +//! #[derive(Debug, PartialEq, Eq, Hash)] //! struct Flags: u32 { //! const A = 0b00000001; //! const B = 0b00000010; @@ -59,14 +61,7 @@ //! //! impl Flags { //! pub fn clear(&mut self) { -//! self.bits = 0; // The `bits` field can be accessed from within the -//! // same module where the `bitflags!` macro was invoked. -//! } -//! } -//! -//! impl fmt::Display for Flags { -//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { -//! write!(f, "hi!") +//! *self = Self::from_bits_retain(0); //! } //! } //! @@ -74,9 +69,8 @@ //! let mut flags = Flags::A | Flags::B; //! flags.clear(); //! assert!(flags.is_empty()); -//! assert_eq!(format!("{}", flags), "hi!"); -//! assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); -//! assert_eq!(format!("{:?}", Flags::B), "B"); +//! assert_eq!(format!("{:?}", Flags::A | Flags::B), "Flags(A | B)"); +//! assert_eq!(format!("{:?}", Flags::B), "Flags(B)"); //! } //! ``` //! @@ -91,10 +85,12 @@ //! use bitflags::bitflags; //! //! bitflags! { +//! #[derive(Debug, PartialEq, Eq, Hash)] //! pub struct Flags1: u32 { //! const A = 0b00000001; //! } //! +//! #[derive(Debug, PartialEq, Eq, Hash)] //! # pub //! struct Flags2: u32 { //! const B = 0b00000010; @@ -123,6 +119,7 @@ //! //! bitflags! { //! #[repr(transparent)] +//! #[derive(Debug, PartialEq, Eq, Hash)] //! struct Flags: u32 { //! const A = 0b00000001; //! const B = 0b00000010; @@ -133,8 +130,7 @@ //! //! # Trait implementations //! -//! The `Copy`, `Clone`, `PartialEq`, `Eq`, `PartialOrd`, `Ord` and `Hash` -//! traits are automatically derived for the `struct`s using the `derive` attribute. +//! The `Copy` and `Clone` traits are automatically derived for the `struct`s using the `derive` attribute. //! Additional traits can be derived by providing an explicit `derive` //! attribute on `struct`. //! @@ -204,7 +200,7 @@ //! //! bitflags! { //! // Results in default value with bits: 0 -//! #[derive(Default)] +//! #[derive(Default, Debug, PartialEq, Eq, Hash)] //! struct Flags: u32 { //! const A = 0b00000001; //! const B = 0b00000010; @@ -224,6 +220,7 @@ //! use bitflags::bitflags; //! //! bitflags! { +//! #[derive(Debug, PartialEq, Eq, Hash)] //! struct Flags: u32 { //! const A = 0b00000001; //! const B = 0b00000010; @@ -252,6 +249,7 @@ //! use bitflags::bitflags; //! //! bitflags! { +//! #[derive(Debug, PartialEq, Eq, Hash)] //! struct Flags: u32 { //! const NONE = 0b00000000; //! const SOME = 0b00000001; @@ -351,6 +349,7 @@ the `__impl_bitflags_internal!` macro. /// use bitflags::bitflags; /// /// bitflags! { +/// #[derive(Debug, PartialEq, Eq, Hash)] /// struct Flags: u32 { /// const A = 0b00000001; /// const B = 0b00000010; @@ -378,6 +377,7 @@ the `__impl_bitflags_internal!` macro. /// use bitflags::bitflags; /// /// bitflags! { +/// #[derive(Debug, PartialEq, Eq, Hash)] /// struct Flags: u32 { /// const A = 0b00000001; /// const B = 0b00000010; @@ -386,14 +386,7 @@ the `__impl_bitflags_internal!` macro. /// /// impl Flags { /// pub fn clear(&mut self) { -/// self.bits = 0; // The `bits` field can be accessed from within the -/// // same module where the `bitflags!` macro was invoked. -/// } -/// } -/// -/// impl fmt::Display for Flags { -/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { -/// write!(f, "hi!") +/// *self = Self::from_bits_retain(0); /// } /// } /// @@ -401,9 +394,8 @@ the `__impl_bitflags_internal!` macro. /// let mut flags = Flags::A | Flags::B; /// flags.clear(); /// assert!(flags.is_empty()); -/// assert_eq!(format!("{}", flags), "hi!"); -/// assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); -/// assert_eq!(format!("{:?}", Flags::B), "B"); +/// assert_eq!(format!("{:?}", Flags::A | Flags::B), "Flags(A | B)"); +/// assert_eq!(format!("{:?}", Flags::B), "Flags(B)"); /// } /// ``` #[macro_export(local_inner_macros)] diff --git a/tests/compile-fail/impls/copy.stderr b/tests/compile-fail/impls/copy.stderr index 966f3c9a..3dc50060 100644 --- a/tests/compile-fail/impls/copy.stderr +++ b/tests/compile-fail/impls/copy.stderr @@ -1,27 +1,27 @@ -error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `Flags` - --> $DIR/copy.rs:3:1 +error[E0119]: conflicting implementations of trait `std::clone::Clone` for type `Flags` + --> tests/compile-fail/impls/copy.rs:3:1 | 3 | / bitflags! { 4 | | #[derive(Clone, Copy)] - | | ---- first implementation here + | | ----- 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) + = note: this error originates in the derive macro `Clone` which comes from the expansion of the macro `bitflags` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0119]: conflicting implementations of trait `std::clone::Clone` for type `Flags` - --> $DIR/copy.rs:3:1 +error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `Flags` + --> tests/compile-fail/impls/copy.rs:3:1 | 3 | / bitflags! { 4 | | #[derive(Clone, Copy)] - | | ----- first implementation here + | | ---- 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) + = note: this error originates in the derive macro `Copy` which comes from the expansion of the macro `bitflags` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/compile-fail/impls/eq.stderr b/tests/compile-fail/impls/eq.stderr deleted file mode 100644 index cb1d6a08..00000000 --- a/tests/compile-fail/impls/eq.stderr +++ /dev/null @@ -1,55 +0,0 @@ -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::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::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) - -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) diff --git a/tests/compile-fail/non_integer_base/all_defined.stderr b/tests/compile-fail/non_integer_base/all_defined.stderr index 69d89dc5..e477281c 100644 --- a/tests/compile-fail/non_integer_base/all_defined.stderr +++ b/tests/compile-fail/non_integer_base/all_defined.stderr @@ -4,6 +4,16 @@ error[E0277]: the trait bound `MyInt: Bits` is not satisfied 116 | struct Flags128: MyInt { | ^^^^^ the trait `Bits` is not implemented for `MyInt` | + = help: the following other types implement trait `Bits`: + i128 + i16 + i32 + i64 + i8 + u128 + u16 + u32 + and 2 others note: required by a bound in `bitflags::BitFlags::Bits` --> src/bitflags_trait.rs | @@ -22,7 +32,17 @@ error[E0277]: the trait bound `MyInt: Bits` is not satisfied 121 | | } | |_^ the trait `Bits` is not implemented for `MyInt` | - = note: this error originates in the macro `__impl_bitflags` (in Nightly builds, run with -Z macro-backtrace for more info) + = help: the following other types implement trait `Bits`: + i128 + i16 + i32 + i64 + i8 + u128 + u16 + u32 + and 2 others + = note: this error originates in the macro `__impl_internal_bitflags` which comes from the expansion of the macro `bitflags` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `MyInt: Bits` is not satisfied --> tests/compile-fail/non_integer_base/all_defined.rs:115:1 @@ -36,7 +56,17 @@ error[E0277]: the trait bound `MyInt: Bits` is not satisfied 121 | | } | |_^ the trait `Bits` is not implemented for `MyInt` | - = note: this error originates in the macro `__impl_bitflags` (in Nightly builds, run with -Z macro-backtrace for more info) + = help: the following other types implement trait `Bits`: + i128 + i16 + i32 + i64 + i8 + u128 + u16 + u32 + and 2 others + = note: this error originates in the macro `__impl_internal_bitflags` which comes from the expansion of the macro `bitflags` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `MyInt: Bits` is not satisfied --> tests/compile-fail/non_integer_base/all_defined.rs:115:1 @@ -50,7 +80,69 @@ error[E0277]: the trait bound `MyInt: Bits` is not satisfied 121 | | } | |_^ the trait `Bits` is not implemented for `MyInt` | - = note: this error originates in the macro `__impl_bitflags` (in Nightly builds, run with -Z macro-backtrace for more info) + = help: the following other types implement trait `Bits`: + i128 + i16 + i32 + i64 + i8 + u128 + u16 + u32 + and 2 others + = note: this error originates in the macro `__impl_internal_bitflags` which comes from the expansion of the macro `bitflags` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: can't compare `MyInt` with `_` in const contexts + --> tests/compile-fail/non_integer_base/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 | | } + | |_^ no implementation for `MyInt == _` + | + = help: the trait `~const PartialEq<_>` is not implemented for `MyInt` +note: the trait `PartialEq<_>` is implemented for `MyInt`, but that implementation is not `const` + --> tests/compile-fail/non_integer_base/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 | | } + | |_^ + = note: this error originates in the macro `__impl_internal_bitflags` which comes from the expansion of the macro `bitflags` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: can't compare `MyInt` with `_` in const contexts + --> tests/compile-fail/non_integer_base/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 | | } + | |_^ no implementation for `MyInt == _` + | + = help: the trait `~const PartialEq<_>` is not implemented for `MyInt` +note: the trait `PartialEq<_>` is implemented for `MyInt`, but that implementation is not `const` + --> tests/compile-fail/non_integer_base/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 | | } + | |_^ + = note: this error originates in the macro `__impl_internal_bitflags` which comes from the expansion of the macro `bitflags` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `MyInt: Bits` is not satisfied --> tests/compile-fail/non_integer_base/all_defined.rs:115:1 @@ -64,4 +156,142 @@ error[E0277]: the trait bound `MyInt: Bits` is not satisfied 121 | | } | |_^ the trait `Bits` is not implemented for `MyInt` | - = note: this error originates in the macro `__impl_bitflags` (in Nightly builds, run with -Z macro-backtrace for more info) + = help: the following other types implement trait `Bits`: + i128 + i16 + i32 + i64 + i8 + u128 + u16 + u32 + and 2 others + = note: this error originates in the macro `__impl_internal_bitflags` which comes from the expansion of the macro `bitflags` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `MyInt: Bits` is not satisfied + --> tests/compile-fail/non_integer_base/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 | | } + | |_^ the trait `Bits` is not implemented for `MyInt` + | + = help: the following other types implement trait `Bits`: + i128 + i16 + i32 + i64 + i8 + u128 + u16 + u32 + and 2 others + = note: this error originates in the macro `__impl_internal_bitflags` which comes from the expansion of the macro `bitflags` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: can't compare `MyInt` with `_` in const contexts + --> tests/compile-fail/non_integer_base/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 | | } + | |_^ no implementation for `MyInt == _` + | + = help: the trait `~const PartialEq<_>` is not implemented for `MyInt` +note: the trait `PartialEq<_>` is implemented for `MyInt`, but that implementation is not `const` + --> tests/compile-fail/non_integer_base/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 | | } + | |_^ + = note: this error originates in the macro `__impl_internal_bitflags` which comes from the expansion of the macro `bitflags` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: can't compare `MyInt` with `_` in const contexts + --> tests/compile-fail/non_integer_base/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 | | } + | |_^ no implementation for `MyInt == _` + | + = help: the trait `~const PartialEq<_>` is not implemented for `MyInt` +note: the trait `PartialEq<_>` is implemented for `MyInt`, but that implementation is not `const` + --> tests/compile-fail/non_integer_base/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 | | } + | |_^ + = note: this error originates in the macro `__impl_internal_bitflags` which comes from the expansion of the macro `bitflags` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: can't compare `MyInt` with `_` in const contexts + --> tests/compile-fail/non_integer_base/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 | | } + | |_^ no implementation for `MyInt == _` + | + = help: the trait `~const PartialEq<_>` is not implemented for `MyInt` +note: the trait `PartialEq<_>` is implemented for `MyInt`, but that implementation is not `const` + --> tests/compile-fail/non_integer_base/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 | | } + | |_^ + = note: this error originates in the macro `__impl_internal_bitflags` which comes from the expansion of the macro `bitflags` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: can't compare `MyInt` with `_` in const contexts + --> tests/compile-fail/non_integer_base/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 | | } + | |_^ no implementation for `MyInt == _` + | + = help: the trait `~const PartialEq<_>` is not implemented for `MyInt` +note: the trait `PartialEq<_>` is implemented for `MyInt`, but that implementation is not `const` + --> tests/compile-fail/non_integer_base/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 | | } + | |_^ + = note: this error originates in the macro `__impl_internal_bitflags` which comes from the expansion of the macro `bitflags` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/compile-fail/non_integer_base/all_missing.stderr b/tests/compile-fail/non_integer_base/all_missing.stderr index ee95f836..7f047c68 100644 --- a/tests/compile-fail/non_integer_base/all_missing.stderr +++ b/tests/compile-fail/non_integer_base/all_missing.stderr @@ -1,5 +1,5 @@ error[E0204]: the trait `Copy` may not be implemented for this type - --> $DIR/all_missing.rs:5:1 + --> tests/compile-fail/non_integer_base/all_missing.rs:5:1 | 5 | / bitflags! { 6 | | struct Flags128: MyInt { @@ -10,4 +10,4 @@ error[E0204]: the trait `Copy` may not be implemented for this type 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) + = note: this error originates in the derive macro `Copy` which comes from the expansion of the macro `bitflags` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/compile-fail/redefined.stderr b/tests/compile-fail/redefined.stderr new file mode 100644 index 00000000..85bc7f10 --- /dev/null +++ b/tests/compile-fail/redefined.stderr @@ -0,0 +1,17 @@ +error: no rules expected the token `{` + --> tests/compile-fail/redefined.rs:5:23 + | +5 | pub struct Flags1 { + | ^ no rules expected this token in macro call + +error: no rules expected the token `{` + --> tests/compile-fail/redefined.rs:11:23 + | +11 | pub struct Flags1 { + | ^ no rules expected this token in macro call + +error[E0601]: `main` function not found in crate `$CRATE` + --> tests/compile-fail/redefined.rs:14:2 + | +14 | } + | ^ consider adding a `main` function to `$DIR/tests/compile-fail/redefined.rs` diff --git a/tests/compile-fail/syntax/missing_type.stderr b/tests/compile-fail/syntax/missing_type.stderr new file mode 100644 index 00000000..ed8c8ac4 --- /dev/null +++ b/tests/compile-fail/syntax/missing_type.stderr @@ -0,0 +1,11 @@ +error: no rules expected the token `{` + --> tests/compile-fail/syntax/missing_type.rs:5:23 + | +5 | pub struct Flags1 { + | ^ no rules expected this token in macro call + +error[E0601]: `main` function not found in crate `$CRATE` + --> tests/compile-fail/syntax/missing_type.rs:8:2 + | +8 | } + | ^ consider adding a `main` function to `$DIR/tests/compile-fail/syntax/missing_type.rs` diff --git a/tests/compile-fail/syntax/missing_value.stderr b/tests/compile-fail/syntax/missing_value.stderr new file mode 100644 index 00000000..6b1b46a1 --- /dev/null +++ b/tests/compile-fail/syntax/missing_value.stderr @@ -0,0 +1,11 @@ +error: no rules expected the token `{` + --> tests/compile-fail/syntax/missing_value.rs:5:23 + | +5 | pub struct Flags1 { + | ^ no rules expected this token in macro call + +error[E0601]: `main` function not found in crate `$CRATE` + --> tests/compile-fail/syntax/missing_value.rs:8:2 + | +8 | } + | ^ consider adding a `main` function to `$DIR/tests/compile-fail/syntax/missing_value.rs` diff --git a/tests/compile-fail/trait/custom_impl.rs b/tests/compile-fail/trait/custom_impl.rs index 80be2f91..55dd929d 100644 --- a/tests/compile-fail/trait/custom_impl.rs +++ b/tests/compile-fail/trait/custom_impl.rs @@ -25,7 +25,7 @@ impl BitFlags for BootlegFlags { unimplemented!() } - unsafe fn from_bits_unchecked(_: u32) -> BootlegFlags { + fn from_bits_retain(_: u32) -> BootlegFlags { unimplemented!() } diff --git a/tests/compile-fail/visibility/bits_field.rs b/tests/compile-fail/visibility/bits_field.rs deleted file mode 100644 index 2e0d5c52..00000000 --- a/tests/compile-fail/visibility/bits_field.rs +++ /dev/null @@ -1,12 +0,0 @@ -#[macro_use] -extern crate bitflags; - -bitflags! { - pub struct Flags1: u32 { - const A = 1; - } -} - -fn main() { - let _ = Flags1::A.0.bits; -} diff --git a/tests/compile-fail/visibility/private_field.rs b/tests/compile-fail/visibility/private_field.rs deleted file mode 100644 index b1d95b18..00000000 --- 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 _ = example::Flags1::FLAG_A.bits; -} diff --git a/tests/compile-fail/visibility/private_field.stderr b/tests/compile-fail/visibility/private_field.stderr deleted file mode 100644 index 18c0cdd1..00000000 --- a/tests/compile-fail/visibility/private_field.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error[E0616]: field `bits` of struct `Flags1` is private - --> $DIR/private_field.rs:12:41 - | -12 | let _ = example::Flags1::FLAG_A.bits; - | ^^^^ private field - | -help: a method `bits` also exists, call it with parentheses - | -12 | let _ = example::Flags1::FLAG_A.bits(); - | ++ diff --git a/tests/compile-fail/visibility/private_flags.stderr b/tests/compile-fail/visibility/private_flags.stderr index d23f8320..47a53c25 100644 --- a/tests/compile-fail/visibility/private_flags.stderr +++ b/tests/compile-fail/visibility/private_flags.stderr @@ -1,11 +1,11 @@ error[E0603]: struct `Flags2` is private - --> $DIR/private_flags.rs:17:26 + --> tests/compile-fail/visibility/private_flags.rs:17:22 | -17 | let flag2 = example::Flags2::FLAG_B; - | ^^^^^^ private struct +17 | let _ = example::Flags2::FLAG_B; + | ^^^^^^ private struct | note: the struct `Flags2` is defined here - --> $DIR/private_flags.rs:4:5 + --> tests/compile-fail/visibility/private_flags.rs:4:5 | 4 | / bitflags! { 5 | | pub struct Flags1: u32 { diff --git a/tests/compile-fail/impls/eq.rs b/tests/compile-pass/impls/eq.rs similarity index 100% rename from tests/compile-fail/impls/eq.rs rename to tests/compile-pass/impls/eq.rs diff --git a/tests/smoke-test/out.rs b/tests/smoke-test/out.rs new file mode 100644 index 0000000000000000000000000000000000000000..12b5cdc518c3c34b4cc95fd932b92dbae90eb679 GIT binary patch literal 56456 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 Date: Thu, 11 Aug 2022 15:48:39 +1000 Subject: [PATCH 09/12] fix up example generated module --- src/example_generated.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/example_generated.rs b/src/example_generated.rs index cf188d99..48c6a441 100644 --- a/src/example_generated.rs +++ b/src/example_generated.rs @@ -9,6 +9,6 @@ bitflags! { const A = 0b00000001; const B = 0b00000010; const C = 0b00000100; - const ABC = Self::A.bits | Self::B.bits | Self::C.bits; + const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits(); } } From eb1f340c368f2a6a6eb521a10ed027ea9658fbda Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Thu, 11 Aug 2022 16:13:02 +1000 Subject: [PATCH 10/12] require Clone and Copy derives --- src/bitflags_trait.rs | 16 +++- src/example_generated.rs | 29 +++++++ src/lib.rs | 87 ++++++++++--------- tests/compile-fail/impls/copy.stderr | 27 ------ .../impls/copy.rs | 0 5 files changed, 89 insertions(+), 70 deletions(-) delete mode 100644 tests/compile-fail/impls/copy.stderr rename tests/{compile-fail => compile-pass}/impls/copy.rs (100%) diff --git a/src/bitflags_trait.rs b/src/bitflags_trait.rs index 7cafb564..fd0a913a 100644 --- a/src/bitflags_trait.rs +++ b/src/bitflags_trait.rs @@ -1,8 +1,5 @@ use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not}; -#[doc(hidden)] -pub trait ImplementedByBitFlagsMacro {} - /// A trait that is automatically implemented for all bitflags. /// /// It should not be implemented manually. @@ -44,9 +41,22 @@ pub trait BitFlags: ImplementedByBitFlagsMacro { fn set(&mut self, other: Self, value: bool); } +/// 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 {} + // Not re-exported pub trait Sealed {} +// 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. + /// 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 diff --git a/src/example_generated.rs b/src/example_generated.rs index 48c6a441..18985c75 100644 --- a/src/example_generated.rs +++ b/src/example_generated.rs @@ -12,3 +12,32 @@ bitflags! { const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits(); } } + +/// This is the same internal field available as `self.0` on bitflags types. +/// These types aren't reachable by callers of `bitflags!`, they don't appear in the API of your +/// crate, but you can still interact with them through `self.0` in the module that defines the +/// bitflags type. +/// +/// You can use this example as a reference for what methods are available to all internal bitflags +/// fields if you want to add custom functionality to your bitflags types. +/// +/// Note that this struct is just for documentation purposes only, it must not be used outside +/// this crate. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(transparent)] +pub struct FlagsField { + bits: u32, +} + +__impl_internal_bitflags! { + FlagsField: u32 { + A; + B; + C; + ABC; + } +} + +impl crate::__private::InternalFlags for FlagsField { + type PublicFlags = Flags; +} diff --git a/src/lib.rs b/src/lib.rs index 4d868448..bd6beab5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,7 @@ //! use bitflags::bitflags; //! //! bitflags! { -//! #[derive(Debug, PartialEq, Eq, Hash)] +//! #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] //! struct Flags: u32 { //! const A = 0b00000001; //! const B = 0b00000010; @@ -52,7 +52,7 @@ //! use bitflags::bitflags; //! //! bitflags! { -//! #[derive(Debug, PartialEq, Eq, Hash)] +//! #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] //! struct Flags: u32 { //! const A = 0b00000001; //! const B = 0b00000010; @@ -61,7 +61,7 @@ //! //! impl Flags { //! pub fn clear(&mut self) { -//! *self = Self::from_bits_retain(0); +//! *self.0.bits_mut() = 0; //! } //! } //! @@ -85,12 +85,12 @@ //! use bitflags::bitflags; //! //! bitflags! { -//! #[derive(Debug, PartialEq, Eq, Hash)] +//! #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] //! pub struct Flags1: u32 { //! const A = 0b00000001; //! } //! -//! #[derive(Debug, PartialEq, Eq, Hash)] +//! #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] //! # pub //! struct Flags2: u32 { //! const B = 0b00000010; @@ -119,7 +119,7 @@ //! //! bitflags! { //! #[repr(transparent)] -//! #[derive(Debug, PartialEq, Eq, Hash)] +//! #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] //! struct Flags: u32 { //! const A = 0b00000001; //! const B = 0b00000010; @@ -130,12 +130,8 @@ //! //! # Trait implementations //! -//! The `Copy` and `Clone` traits are automatically derived for the `struct`s using the `derive` attribute. -//! Additional traits can be derived by providing an explicit `derive` -//! attribute on `struct`. -//! -//! The `Extend` and `FromIterator` traits are implemented for the `struct`s, -//! too: `Extend` adds the union of the instances of the `struct` iterated over, +//! The `Extend` and `FromIterator` traits are implemented for the `struct`s. +//! `Extend` adds the union of the instances of the `struct` iterated over, //! while `FromIterator` calculates the union. //! //! The `Binary`, `Debug`, `LowerHex`, `Octal` and `UpperHex` traits are also @@ -200,7 +196,7 @@ //! //! bitflags! { //! // Results in default value with bits: 0 -//! #[derive(Default, Debug, PartialEq, Eq, Hash)] +//! #[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash)] //! struct Flags: u32 { //! const A = 0b00000001; //! const B = 0b00000010; @@ -220,7 +216,7 @@ //! use bitflags::bitflags; //! //! bitflags! { -//! #[derive(Debug, PartialEq, Eq, Hash)] +//! #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] //! struct Flags: u32 { //! const A = 0b00000001; //! const B = 0b00000010; @@ -249,7 +245,7 @@ //! use bitflags::bitflags; //! //! bitflags! { -//! #[derive(Debug, PartialEq, Eq, Hash)] +//! #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] //! struct Flags: u32 { //! const NONE = 0b00000000; //! const SOME = 0b00000001; @@ -349,7 +345,7 @@ the `__impl_bitflags_internal!` macro. /// use bitflags::bitflags; /// /// bitflags! { -/// #[derive(Debug, PartialEq, Eq, Hash)] +/// #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] /// struct Flags: u32 { /// const A = 0b00000001; /// const B = 0b00000010; @@ -377,7 +373,7 @@ the `__impl_bitflags_internal!` macro. /// use bitflags::bitflags; /// /// bitflags! { -/// #[derive(Debug, PartialEq, Eq, Hash)] +/// #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] /// struct Flags: u32 { /// const A = 0b00000001; /// const B = 0b00000010; @@ -386,7 +382,7 @@ the `__impl_bitflags_internal!` macro. /// /// impl Flags { /// pub fn clear(&mut self) { -/// *self = Self::from_bits_retain(0); +/// *self.0.bits_mut() = 0; /// } /// } /// @@ -412,7 +408,6 @@ macro_rules! bitflags { $($t:tt)* ) => { $(#[$outer])* - #[derive(Clone, Copy)] $vis struct $BitFlags(<$BitFlags as $crate::__private::PublicFlags>::InternalFlags); __impl_public_bitflags! { @@ -440,15 +435,6 @@ macro_rules! bitflags { } } - __impl_internal_bitflags_serde! { - InternalFlags: $T { - $( - $(#[$inner $($args)*])* - $Flag; - )* - } - } - impl $crate::__private::InternalFlags for InternalFlags { type PublicFlags = $BitFlags; } @@ -894,6 +880,16 @@ macro_rules! __impl_internal_bitflags { )* } ) => { + // Any new library traits impls should be added here + __impl_internal_bitflags_serde! { + $InternalBitFlags: $T { + $( + $(#[$attr $($args)*])* + $Flag; + )* + } + } + impl $crate::__private::core::default::Default for $InternalBitFlags { #[inline] fn default() -> Self { @@ -981,6 +977,11 @@ macro_rules! __impl_internal_bitflags { self.bits } + #[inline] + pub fn bits_mut(&mut self) -> &mut $T { + &mut self.bits + } + #[inline] pub const fn from_bits(bits: $T) -> $crate::__private::core::option::Option { let truncated = Self::from_bits_truncate(bits).bits; @@ -1225,7 +1226,7 @@ mod tests { #[doc = "> you are the easiest person to fool."] #[doc = "> "] #[doc = "> - Richard Feynman"] - #[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] + #[derive(Clone, Copy, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] struct Flags: u32 { const A = 0b00000001; #[doc = " macros are way better at generating code than trans is"] @@ -1237,7 +1238,7 @@ mod tests { const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits(); } - #[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] + #[derive(Clone, Copy, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] struct _CfgFlags: u32 { #[cfg(unix)] const _CFG_A = 0b01; @@ -1247,19 +1248,19 @@ mod tests { const _CFG_C = Self::_CFG_A.bits() | 0b10; } - #[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] + #[derive(Clone, Copy, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] struct AnotherSetOfFlags: i8 { const ANOTHER_FLAG = -1_i8; } - #[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] + #[derive(Clone, Copy, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] struct LongFlags: u32 { const LONG_A = 0b1111111111111111; } } bitflags! { - #[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] + #[derive(Clone, Copy, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] struct EmptyFlags: u32 { } } @@ -1550,7 +1551,7 @@ mod tests { // - unknown flags at both ends, and in the middle // - cases with "gaps". bitflags! { - #[derive(Debug, PartialEq, Eq)] + #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct Test: u16 { // Intentionally no `A` const B = 0b000000010; @@ -1832,10 +1833,12 @@ mod tests { mod submodule { bitflags! { + #[derive(Clone, Copy)] pub struct PublicFlags: i8 { const X = 0; } + #[derive(Clone, Copy)] struct PrivateFlags: i8 { const Y = 0; } @@ -1859,6 +1862,7 @@ mod tests { bitflags! { /// baz + #[derive(Clone, Copy)] struct Flags: foo::Bar { const A = 0b00000001; #[cfg(foo)] @@ -1872,7 +1876,7 @@ mod tests { #[test] fn test_in_function() { bitflags! { - #[derive(Debug, PartialEq, Eq)] + #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct Flags: u8 { const A = 1; #[cfg(any())] // false @@ -1886,6 +1890,7 @@ mod tests { #[test] fn test_deprecated() { bitflags! { + #[derive(Clone, Copy)] pub struct TestFlags: u32 { #[deprecated(note = "Use something else.")] const ONE = 1; @@ -1897,6 +1902,7 @@ mod tests { fn test_pub_crate() { mod module { bitflags! { + #[derive(Clone, Copy)] pub (crate) struct Test: u8 { const FOO = 1; } @@ -1913,6 +1919,7 @@ mod tests { bitflags! { // `pub (in super)` means only the module `module` will // be able to access this. + #[derive(Clone, Copy)] pub (in super) struct Test: u8 { const FOO = 1; } @@ -1938,7 +1945,7 @@ mod tests { #[test] fn test_zero_value_flags() { bitflags! { - #[derive(Debug, PartialEq, Eq)] + #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct Flags: u32 { const NONE = 0b0; const SOME = 0b1; @@ -1961,7 +1968,7 @@ mod tests { #[test] fn test_u128_bitflags() { bitflags! { - #[derive(Debug, PartialEq, Eq)] + #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct Flags: u128 { const A = 0x0000_0000_0000_0000_0000_0000_0000_0001; const B = 0x0000_0000_0000_1000_0000_0000_0000_0000; @@ -1987,7 +1994,7 @@ mod tests { #[test] fn test_from_bits_edge_cases() { bitflags! { - #[derive(Debug, PartialEq, Eq)] + #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct Flags: u8 { const A = 0b00000001; const BC = 0b00000110; @@ -2003,7 +2010,7 @@ mod tests { #[test] fn test_from_bits_truncate_edge_cases() { bitflags! { - #[derive(Debug, PartialEq, Eq)] + #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct Flags: u8 { const A = 0b00000001; const BC = 0b00000110; @@ -2019,7 +2026,7 @@ mod tests { #[test] fn test_iter() { bitflags! { - #[derive(Debug, PartialEq, Eq)] + #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct Flags: u32 { const ONE = 0b001; const TWO = 0b010; diff --git a/tests/compile-fail/impls/copy.stderr b/tests/compile-fail/impls/copy.stderr deleted file mode 100644 index 3dc50060..00000000 --- a/tests/compile-fail/impls/copy.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error[E0119]: conflicting implementations of trait `std::clone::Clone` for type `Flags` - --> tests/compile-fail/impls/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` which comes from the expansion of the macro `bitflags` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `Flags` - --> tests/compile-fail/impls/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` which comes from the expansion of the macro `bitflags` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/compile-fail/impls/copy.rs b/tests/compile-pass/impls/copy.rs similarity index 100% rename from tests/compile-fail/impls/copy.rs rename to tests/compile-pass/impls/copy.rs From b34c71207ad773d00f5e5a0b4d9eb1b0b629ab92 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Thu, 11 Aug 2022 16:18:35 +1000 Subject: [PATCH 11/12] fix up serde --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index bd6beab5..fefac414 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1190,7 +1190,7 @@ macro_rules! __impl_internal_bitflags_serde { fn deserialize>(deserializer: D) -> $crate::__private::core::result::Result { let bits = $crate::serde_support::deserialize_bits_default($crate::__private::core::stringify!($InternalBitFlags), deserializer)?; - $crate::__private::result::Result::Ok($InternalBitFlags::from_bits_retain(bits)) + $crate::__private::core::result::Result::Ok($InternalBitFlags::from_bits_retain(bits)) } } } From c5b2ff07498aebb70548ce868ec285a81bbef4bb Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Thu, 11 Aug 2022 17:33:32 +1000 Subject: [PATCH 12/12] remove temporary expansion fil --- tests/smoke-test/out.rs | Bin 56456 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tests/smoke-test/out.rs diff --git a/tests/smoke-test/out.rs b/tests/smoke-test/out.rs deleted file mode 100644 index 12b5cdc518c3c34b4cc95fd932b92dbae90eb679..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56456 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