Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support creating flags from their names #287

Merged
merged 1 commit into from Oct 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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