aboutsummaryrefslogtreecommitdiff
path: root/vendor/bitflags/src/iter.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/bitflags/src/iter.rs')
-rw-r--r--vendor/bitflags/src/iter.rs145
1 files changed, 145 insertions, 0 deletions
diff --git a/vendor/bitflags/src/iter.rs b/vendor/bitflags/src/iter.rs
new file mode 100644
index 0000000..7f7ce55
--- /dev/null
+++ b/vendor/bitflags/src/iter.rs
@@ -0,0 +1,145 @@
+/*!
+Yield the bits of a source flags value in a set of contained flags values.
+*/
+
+use crate::{Flag, Flags};
+
+/**
+An iterator over flags values.
+
+This iterator will yield flags values for contained, defined flags first, with any remaining bits yielded
+as a final flags value.
+*/
+pub struct Iter<B: 'static> {
+ inner: IterNames<B>,
+ done: bool,
+}
+
+impl<B: Flags> Iter<B> {
+ pub(crate) fn new(flags: &B) -> Self {
+ Iter {
+ inner: IterNames::new(flags),
+ done: false,
+ }
+ }
+}
+
+impl<B: 'static> Iter<B> {
+ // Used by the `bitflags` macro
+ #[doc(hidden)]
+ pub const fn __private_const_new(flags: &'static [Flag<B>], source: B, remaining: B) -> Self {
+ Iter {
+ inner: IterNames::__private_const_new(flags, source, remaining),
+ done: false,
+ }
+ }
+}
+
+impl<B: Flags> Iterator for Iter<B> {
+ type Item = B;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ match self.inner.next() {
+ Some((_, flag)) => Some(flag),
+ None if !self.done => {
+ self.done = true;
+
+ // After iterating through valid names, if there are any bits left over
+ // then return one final value that includes them. This makes `into_iter`
+ // and `from_iter` roundtrip
+ if !self.inner.remaining().is_empty() {
+ Some(B::from_bits_retain(self.inner.remaining.bits()))
+ } else {
+ None
+ }
+ }
+ None => None,
+ }
+ }
+}
+
+/**
+An iterator over flags values.
+
+This iterator only yields flags values for contained, defined, named flags. Any remaining bits
+won't be yielded, but can be found with the [`IterNames::remaining`] method.
+*/
+pub struct IterNames<B: 'static> {
+ flags: &'static [Flag<B>],
+ idx: usize,
+ source: B,
+ remaining: B,
+}
+
+impl<B: Flags> IterNames<B> {
+ pub(crate) fn new(flags: &B) -> Self {
+ IterNames {
+ flags: B::FLAGS,
+ idx: 0,
+ remaining: B::from_bits_retain(flags.bits()),
+ source: B::from_bits_retain(flags.bits()),
+ }
+ }
+}
+
+impl<B: 'static> IterNames<B> {
+ // Used by the bitflags macro
+ #[doc(hidden)]
+ pub const fn __private_const_new(flags: &'static [Flag<B>], source: B, remaining: B) -> Self {
+ IterNames {
+ flags,
+ idx: 0,
+ remaining,
+ source,
+ }
+ }
+
+ /// Get a flags value of any remaining bits that haven't been yielded yet.
+ ///
+ /// Once the iterator has finished, this method can be used to
+ /// check whether or not there are any bits that didn't correspond
+ /// to a contained, defined, named flag remaining.
+ pub fn remaining(&self) -> &B {
+ &self.remaining
+ }
+}
+
+impl<B: Flags> Iterator for IterNames<B> {
+ type Item = (&'static str, B);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ while let Some(flag) = self.flags.get(self.idx) {
+ // Short-circuit if our state is empty
+ if self.remaining.is_empty() {
+ return None;
+ }
+
+ self.idx += 1;
+
+ // Skip unnamed flags
+ if flag.name().is_empty() {
+ continue;
+ }
+
+ let bits = flag.value().bits();
+
+ // If the flag is set in the original source _and_ it has bits that haven't
+ // been covered by a previous flag yet then yield it. These conditions cover
+ // two cases for multi-bit flags:
+ //
+ // 1. When flags partially overlap, such as `0b00000001` and `0b00000101`, we'll
+ // yield both flags.
+ // 2. When flags fully overlap, such as in convenience flags that are a shorthand for others,
+ // we won't yield both flags.
+ if self.source.contains(B::from_bits_retain(bits))
+ && self.remaining.intersects(B::from_bits_retain(bits))
+ {
+ self.remaining.remove(B::from_bits_retain(bits));
+
+ return Some((flag.name(), B::from_bits_retain(bits)));
+ }
+ }
+
+ None
+ }
+}