From dd2b95254061f9b93828f85dcf4e1c8640e68060 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Fri, 7 Oct 2022 10:51:43 +1000 Subject: [PATCH] support creating flags from their names --- src/internal.rs | 35 +++++++++++++++++++++++------------ src/lib.rs | 35 +++++++++++++++++++++++++---------- src/public.rs | 39 +++++++++++++++++++++++---------------- src/traits.rs | 9 +++++++-- 4 files changed, 78 insertions(+), 40 deletions(-) diff --git a/src/internal.rs b/src/internal.rs index f78c89b4..fa63b8e1 100644 --- a/src/internal.rs +++ b/src/internal.rs @@ -12,7 +12,7 @@ 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)] @@ -20,9 +20,9 @@ macro_rules! __declare_internal_bitflags { 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, @@ -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; @@ -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(" | ")?; } @@ -167,14 +167,25 @@ macro_rules! __impl_internal_bitflags { Self { bits } } + #[inline] + pub fn from_name(name: &str) -> $crate::__private::core::option::Option { + 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, @@ -260,12 +271,12 @@ macro_rules! __impl_internal_bitflags { type Item = $BitFlags; fn next(&mut self) -> $crate::__private::core::option::Option { - 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 { const NUM_FLAGS: usize = { @@ -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))) } } diff --git a/src/lib.rs b/src/lib.rs index 251ab3f8..38db8865 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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); @@ -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); + } } diff --git a/src/public.rs b/src/public.rs index 65477ff0..ae960641 100644 --- a/src/public.rs +++ b/src/public.rs @@ -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; @@ -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 { + 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. @@ -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() @@ -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 { diff --git a/src/traits.rs b/src/traits.rs index 703526ae..5a082a1b 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -11,7 +11,7 @@ pub trait BitFlags: ImplementedByBitFlagsMacro { type Iter: Iterator; /// An iterator over the raw names and bits for enabled flags in an instance of the type. - type IterRaw: Iterator; + type IterNames: Iterator; /// Returns an empty set of flags. fn empty() -> Self; @@ -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 + 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;