Skip to content

Commit

Permalink
Merge pull request #287 from KodrAus/feat/from-names
Browse files Browse the repository at this point in the history
Support creating flags from their names
  • Loading branch information
KodrAus committed Oct 7, 2022
2 parents 87e859b + dd2b952 commit 128f3d9
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 40 deletions.
35 changes: 23 additions & 12 deletions src/internal.rs
Expand Up @@ -12,17 +12,17 @@ macro_rules! __declare_internal_bitflags {
(
$vis:vis struct $InternalBitFlags:ident: $T:ty;
$iter_vis:vis struct $Iter:ident;
$iter_raw_vis:vis struct $IterRaw:ident;
$iter_names_vis:vis struct $IterNames:ident;
) => {
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
$vis struct $InternalBitFlags {
bits: $T,
}

$iter_vis struct $Iter($IterRaw);
$iter_vis struct $Iter($IterNames);

$iter_raw_vis struct $IterRaw {
$iter_names_vis struct $IterNames {
idx: usize,
source: $InternalBitFlags,
state: $InternalBitFlags,
Expand All @@ -38,7 +38,7 @@ macro_rules! __declare_internal_bitflags {
#[doc(hidden)]
macro_rules! __impl_internal_bitflags {
(
$InternalBitFlags:ident: $T:ty, $BitFlags:ident, $Iter:ident, $IterRaw:ident {
$InternalBitFlags:ident: $T:ty, $BitFlags:ident, $Iter:ident, $IterNames:ident {
$(
$(#[$attr:ident $($args:tt)*])*
$Flag:ident;
Expand All @@ -60,7 +60,7 @@ macro_rules! __impl_internal_bitflags {
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_raw() {
for (name, _) in self.iter_names() {
if !first {
f.write_str(" | ")?;
}
Expand Down Expand Up @@ -167,14 +167,25 @@ macro_rules! __impl_internal_bitflags {
Self { bits }
}

#[inline]
pub fn from_name(name: &str) -> $crate::__private::core::option::Option<Self> {
match name {
$(
$(#[$attr $($args)*])*
$crate::__private::core::stringify!($Flag) => $crate::__private::core::option::Option::Some(Self { bits: $BitFlags::$Flag.bits() }),
)*
_ => $crate::__private::core::option::Option::None,
}
}

#[inline]
pub const fn iter(&self) -> $Iter {
$Iter(self.iter_raw())
$Iter(self.iter_names())
}

#[inline]
pub const fn iter_raw(&self) -> $IterRaw {
$IterRaw {
pub const fn iter_names(&self) -> $IterNames {
$IterNames {
idx: 0,
source: *self,
state: *self,
Expand Down Expand Up @@ -260,12 +271,12 @@ macro_rules! __impl_internal_bitflags {
type Item = $BitFlags;

fn next(&mut self) -> $crate::__private::core::option::Option<Self::Item> {
self.0.next().map(|(_, value)| $BitFlags::from_bits_retain(value))
self.0.next().map(|(_, value)| value)
}
}

impl $crate::__private::core::iter::Iterator for $IterRaw {
type Item = (&'static str, $T);
impl $crate::__private::core::iter::Iterator for $IterNames {
type Item = (&'static str, $BitFlags);

fn next(&mut self) -> $crate::__private::core::option::Option<Self::Item> {
const NUM_FLAGS: usize = {
Expand Down Expand Up @@ -316,7 +327,7 @@ macro_rules! __impl_internal_bitflags {
if self.source.contains($InternalBitFlags { bits: flag }) {
self.state.remove($InternalBitFlags { bits: flag });

return $crate::__private::core::option::Option::Some((flag_name, flag))
return $crate::__private::core::option::Option::Some((flag_name, $BitFlags::from_bits_retain(flag)))
}
}

Expand Down
35 changes: 25 additions & 10 deletions src/lib.rs
Expand Up @@ -1381,22 +1381,22 @@ mod tests {
assert!(flags.contains(flag));
}

let mut iter = flags.iter_raw();
let mut iter = flags.iter_names();

assert_eq!(iter.next().unwrap(), ("ONE", Flags::ONE.bits()));
assert_eq!(iter.next().unwrap(), ("TWO", Flags::TWO.bits()));
assert_eq!(iter.next().unwrap(), ("THREE", Flags::THREE.bits()));
assert_eq!(iter.next().unwrap(), ("ONE", Flags::ONE));
assert_eq!(iter.next().unwrap(), ("TWO", Flags::TWO));
assert_eq!(iter.next().unwrap(), ("THREE", Flags::THREE));

#[cfg(unix)]
{
assert_eq!(iter.next().unwrap(), ("FOUR_UNIX", Flags::FOUR_UNIX.bits()));
assert_eq!(iter.next().unwrap(), ("FOUR_UNIX", Flags::FOUR_UNIX));
}
#[cfg(windows)]
{
assert_eq!(iter.next().unwrap(), ("FOUR_WIN", Flags::FOUR_WIN.bits()));
assert_eq!(iter.next().unwrap(), ("FOUR_WIN", Flags::FOUR_WIN));
}

assert_eq!(iter.next().unwrap(), ("FIVE", Flags::FIVE.bits()));
assert_eq!(iter.next().unwrap(), ("FIVE", Flags::FIVE));

assert_eq!(iter.next(), None);

Expand All @@ -1406,10 +1406,25 @@ mod tests {
let flags = Flags::ONE | Flags::THREE;
assert_eq!(flags.into_iter().count(), 2);

let mut iter = flags.iter_raw();
let mut iter = flags.iter_names();

assert_eq!(iter.next().unwrap(), ("ONE", Flags::ONE.bits()));
assert_eq!(iter.next().unwrap(), ("THREE", Flags::THREE.bits()));
assert_eq!(iter.next().unwrap(), ("ONE", Flags::ONE));
assert_eq!(iter.next().unwrap(), ("THREE", Flags::THREE));
assert_eq!(iter.next(), None);
}

#[test]
fn test_from_name() {
let flags = Flags::all();

let mut rebuilt = Flags::empty();

for (name, value) in flags.iter_names() {
assert_eq!(value, Flags::from_name(name).unwrap());

rebuilt |= Flags::from_name(name).unwrap();
}

assert_eq!(flags, rebuilt);
}
}
39 changes: 23 additions & 16 deletions src/public.rs
Expand Up @@ -26,7 +26,7 @@ macro_rules! __declare_public_bitflags {
#[doc(hidden)]
macro_rules! __impl_public_bitflags {
(
$PublicBitFlags:ident: $T:ty, $InternalBitFlags:ident, $Iter:ident, $IterRaw:ident {
$PublicBitFlags:ident: $T:ty, $InternalBitFlags:ident, $Iter:ident, $IterNames:ident {
$(
$(#[$attr:ident $($args:tt)*])*
$Flag:ident = $value:expr;
Expand Down Expand Up @@ -100,30 +100,33 @@ macro_rules! __impl_public_bitflags {

/// Convert from underlying bit representation, preserving all
/// bits (even those not corresponding to a defined flag).
///
/// # Safety
///
/// The caller of the `bitflags!` macro can choose to allow or
/// disallow extra bits for their bitflags type.
///
/// 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 fn from_bits_retain(bits: $T) -> Self {
Self($InternalBitFlags::from_bits_retain(bits))
}

/// Get the value for a flag from its stringified name.
///
/// Names are _case-sensitive_, so must correspond exactly to
/// the identifier given to the flag.
#[inline]
pub fn from_name(name: &str) -> $crate::__private::core::option::Option<Self> {
match $InternalBitFlags::from_name(name) {
$crate::__private::core::option::Option::Some(bits) => $crate::__private::core::option::Option::Some(Self(bits)),
$crate::__private::core::option::Option::None => $crate::__private::core::option::Option::None,
}
}

/// Iterate over enabled flag values.
#[inline]
pub const fn iter(&self) -> $Iter {
self.0.iter()
}

/// Iterate over the raw names and bits for enabled flag values.
/// Iterate over enabled flag values with their stringified names.
#[inline]
pub const fn iter_raw(&self) -> $IterRaw {
self.0.iter_raw()
pub const fn iter_names(&self) -> $IterNames {
self.0.iter_names()
}

/// Returns `true` if no flags are currently stored.
Expand Down Expand Up @@ -377,7 +380,7 @@ macro_rules! __impl_public_bitflags {
type Bits = $T;

type Iter = $Iter;
type IterRaw = $IterRaw;
type IterNames = $IterNames;

fn empty() -> Self {
$PublicBitFlags::empty()
Expand All @@ -403,12 +406,16 @@ macro_rules! __impl_public_bitflags {
$PublicBitFlags::from_bits_retain(bits)
}

fn from_name(name: &str) -> $crate::__private::core::option::Option<$PublicBitFlags> {
$PublicBitFlags::from_name(name)
}

fn iter(&self) -> Self::Iter {
$PublicBitFlags::iter(self)
}

fn iter_raw(&self) -> Self::IterRaw {
$PublicBitFlags::iter_raw(self)
fn iter_names(&self) -> Self::IterNames {
$PublicBitFlags::iter_names(self)
}

fn is_empty(&self) -> bool {
Expand Down
9 changes: 7 additions & 2 deletions src/traits.rs
Expand Up @@ -11,7 +11,7 @@ pub trait BitFlags: ImplementedByBitFlagsMacro {
type Iter: Iterator<Item = Self>;

/// An iterator over the raw names and bits for enabled flags in an instance of the type.
type IterRaw: Iterator<Item = (&'static str, Self::Bits)>;
type IterNames: Iterator<Item = (&'static str, Self)>;

/// Returns an empty set of flags.
fn empty() -> Self;
Expand All @@ -36,11 +36,16 @@ pub trait BitFlags: ImplementedByBitFlagsMacro {
/// bits (even those not corresponding to a defined flag).
fn from_bits_retain(bits: Self::Bits) -> Self;

/// Get the flag for a particular name.
fn from_name(name: &str) -> Option<Self>
where
Self: Sized;

/// Iterate over enabled flag values.
fn iter(&self) -> Self::Iter;

/// Iterate over the raw names and bits for enabled flag values.
fn iter_raw(&self) -> Self::IterRaw;
fn iter_names(&self) -> Self::IterNames;

/// Returns `true` if no flags are currently stored.
fn is_empty(&self) -> bool;
Expand Down

0 comments on commit 128f3d9

Please sign in to comment.