Skip to content

Commit

Permalink
Merge pull request #276 from arturoc/fix_from_bits
Browse files Browse the repository at this point in the history
from_bits_(truncate) fail with composite flags
  • Loading branch information
KodrAus committed Apr 28, 2022
2 parents 0141a07 + 0ef1316 commit 31401a1
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 24 deletions.
73 changes: 51 additions & 22 deletions src/lib.rs
Expand Up @@ -559,18 +559,34 @@ macro_rules! __impl_bitflags {
/// representation contains bits that do not correspond to a flag.
#[inline]
pub const fn from_bits(bits: $T) -> $crate::_core::option::Option<Self> {
if (bits & !Self::all().bits()) == 0 {
$crate::_core::option::Option::Some(Self { bits })
let truncated = Self::from_bits_truncate(bits).bits;
if truncated == bits {
Some(Self{ bits })
} else {
$crate::_core::option::Option::None
None
}
}

/// Convert from underlying bit representation, dropping any bits
/// that do not correspond to flags.
#[inline]
pub const fn from_bits_truncate(bits: $T) -> Self {
Self { bits: bits & Self::all().bits }
if bits == 0 {
return Self{ bits }
}

#[allow(unused_mut)]
let mut truncated = 0;

$(
#[allow(unused_doc_comments, unused_attributes)]
$(#[$attr $($args)*])*
if bits & Self::$Flag.bits == Self::$Flag.bits {
truncated |= Self::$Flag.bits
}
)*

Self { bits: truncated }
}

/// Convert from underlying bit representation, preserving all
Expand Down Expand Up @@ -1891,6 +1907,37 @@ mod tests {
}
}

#[test]
fn test_from_bits_edge_cases() {
bitflags! {
struct Flags: u8 {
const A = 0b00000001;
const BC = 0b00000110;
}
}


let flags = Flags::from_bits(0b00000100);
assert_eq!(flags, None);
let flags = Flags::from_bits(0b00000101);
assert_eq!(flags, None);
}

#[test]
fn test_from_bits_truncate_edge_cases() {
bitflags! {
struct Flags: u8 {
const A = 0b00000001;
const BC = 0b00000110;
}
}

let flags = Flags::from_bits_truncate(0b00000100);
assert_eq!(flags, Flags::empty());
let flags = Flags::from_bits_truncate(0b00000101);
assert_eq!(flags, Flags::A);
}

#[test]
fn test_iter() {
bitflags! {
Expand Down Expand Up @@ -1924,22 +1971,4 @@ mod tests {
assert_eq!(iter.next().unwrap(), Flags::THREE);
assert_eq!(iter.next(), None);
}

#[test]
fn test_iter_edge_cases() {
bitflags! {
struct Flags: u8 {
const A = 0b00000001;
const BC = 0b00000110;
}
}


let flags = Flags::all();
assert_eq!(flags.iter().count(), 2);
let mut iter = flags.iter();
assert_eq!(iter.next().unwrap(), Flags::A);
assert_eq!(iter.next().unwrap(), Flags::BC);
assert_eq!(iter.next(), None);
}
}
37 changes: 35 additions & 2 deletions tests/compile-fail/non_integer_base/all_defined.stderr.beta
Expand Up @@ -49,8 +49,41 @@ error[E0308]: mismatched types
= note: this error originates in the macro `__impl_bitflags` (in Nightly builds, run with -Z macro-backtrace for more info)
help: try wrapping the expression in `MyInt`
|
562 | if (bits & !Self::all().bits()) == MyInt(0) {
| ++++++ +
574 | if bits == MyInt(0) {
| ++++++ +

error[E0277]: no implementation for `{integer} |= MyInt`
--> $DIR/all_defined.rs:115:1
|
115 | / bitflags! {
116 | | struct Flags128: MyInt {
117 | | const A = MyInt(0b0000_0001u8);
118 | | const B = MyInt(0b0000_0010u8);
119 | | const C = MyInt(0b0000_0100u8);
120 | | }
121 | | }
| |_^ no implementation for `{integer} |= MyInt`
|
= help: the trait `BitOrAssign<MyInt>` is not implemented for `{integer}`
= note: this error originates in the macro `__impl_bitflags` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0308]: mismatched types
--> $DIR/all_defined.rs:115:1
|
115 | / bitflags! {
116 | | struct Flags128: MyInt {
117 | | const A = MyInt(0b0000_0001u8);
118 | | const B = MyInt(0b0000_0010u8);
119 | | const C = MyInt(0b0000_0100u8);
120 | | }
121 | | }
| |_^ expected struct `MyInt`, found integer
|
= note: this error originates in the macro `__impl_bitflags` (in Nightly builds, run with -Z macro-backtrace for more info)
help: try wrapping the expression in `MyInt`
|
589 | Self { bits: MyInt(truncated) }
| ++++++ +

error[E0308]: mismatched types
--> $DIR/all_defined.rs:115:1
Expand Down

0 comments on commit 31401a1

Please sign in to comment.