Skip to content

Commit cb439e1

Browse files
chitoyuumeithecatte
authored andcommitted
Add method to extract single flags
Added the `BitFlags::to_flag` method that converts `BitFlags<T>` to `T` if there is exactly one flag that is set. This is semantically equivalent to `flags.iter().exactly_one()` with `itertools`, but without the dependency and faster.
1 parent 624b1cf commit cb439e1

File tree

2 files changed

+23
-1
lines changed

2 files changed

+23
-1
lines changed

src/lib.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,10 +230,16 @@ pub mod _internal {
230230
+ Copy
231231
+ Clone
232232
{
233+
#[doc(hidden)]
234+
fn is_power_of_two(self) -> bool;
233235
}
234236

235237
for_each_uint! { $ty $hide_docs =>
236-
impl BitFlagNum for $ty {}
238+
impl BitFlagNum for $ty {
239+
fn is_power_of_two(self) -> bool {
240+
<$ty>::is_power_of_two(self)
241+
}
242+
}
237243
}
238244

239245
// Re-export libcore so the macro doesn't inject "extern crate" downstream.
@@ -268,6 +274,8 @@ pub mod _internal {
268274
}
269275
}
270276

277+
use _internal::BitFlagNum;
278+
271279
// Internal debug formatting implementations
272280
mod formatting;
273281

@@ -555,6 +563,16 @@ where
555563
self.val == T::EMPTY
556564
}
557565

566+
/// Returns the flag that is set if there is exactly one.
567+
#[inline(always)]
568+
pub fn to_flag(self) -> Option<T> {
569+
if self.val.is_power_of_two() {
570+
Some(unsafe { core::mem::transmute_copy(&self.val) })
571+
} else {
572+
None
573+
}
574+
}
575+
558576
/// Returns the underlying bitwise value.
559577
///
560578
/// ```

test_suite/common.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ fn test_foo() {
7272
assert_eq!((Test::A ^ Test::B), Test::A | Test::B);
7373

7474
assert_eq!(BitFlags::<Default6>::default(), Default6::B | Default6::C);
75+
76+
assert_eq!(BitFlags::<Test>::empty().to_flag(), None);
77+
assert_eq!(BitFlags::<Test>::from(Test::B).to_flag(), Some(Test::B));
78+
assert_eq!((Test::A | Test::C).to_flag(), None);
7579
}
7680

7781
#[test]

0 commit comments

Comments
 (0)