145 lines
4.1 KiB
Rust
145 lines
4.1 KiB
Rust
/*!
|
|
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
|
|
}
|
|
}
|