bitflag_attr/iter.rs
1//! Yield the bits of a source flags value in a set of contained flags values.
2
3use core::iter::FusedIterator;
4
5use super::Flags;
6
7/// An iterator over flags values.
8///
9/// This iterator only yields flags values for contained, defined, named flags. Any remaining bits
10/// won't be yielded, but can be found with the [`#iter_name_ty::remaining`] method.
11pub struct IterNames<B: 'static> {
12 flags: &'static [(&'static str, B)],
13 index: usize,
14 source: B,
15 remaining: B,
16}
17
18impl<B: Flags> IterNames<B> {
19 #[inline]
20 pub(crate) fn new(flags: &B) -> Self {
21 Self {
22 flags: B::NAMED_FLAGS,
23 index: 0,
24 source: B::from_bits_retain(flags.bits()),
25 remaining: B::from_bits_retain(flags.bits()),
26 }
27 }
28}
29
30impl<B: 'static> IterNames<B> {
31 /// Get a flags value of any remaining bits that haven't been yielded yet.
32 ///
33 /// Once the iterator has finished, this method can be used to
34 /// check whether or not there are any bits that didn't correspond
35 /// to a contained, defined, named flag remaining.
36 #[inline]
37 pub const fn remaining(&self) -> &B {
38 &self.remaining
39 }
40
41 // Used by the `bitflag` macro
42 #[doc(hidden)]
43 #[inline]
44 pub const fn __private_const_new(
45 flags: &'static [(&'static str, B)],
46 source: B,
47 remaining: B,
48 ) -> Self {
49 IterNames {
50 flags,
51 index: 0,
52 remaining,
53 source,
54 }
55 }
56}
57
58impl<B: Flags> Iterator for IterNames<B> {
59 type Item = (&'static str, B);
60
61 fn next(&mut self) -> Option<Self::Item> {
62 while let Some((name, flag)) = self.flags.get(self.index) {
63 // Short-circuit if our state is empty
64 if self.remaining.is_empty() {
65 return None;
66 }
67
68 self.index += 1;
69
70 // If the flag is set in the original source _and_ it has bits that haven't
71 // been covered by a previous flag yet then yield it. These conditions cover
72 // two cases for multi-bit flags:
73 //
74 // 1. When flags partially overlap, such as `0b00000001` and `0b00000101`, we'll
75 // yield both flags.
76 // 2. When flags fully overlap, such as in convenience flags that are a shorthand for others,
77 // we won't yield both flags.
78 if self.source.contains(*flag) && self.remaining.intersects(*flag) {
79 self.remaining.unset(*flag);
80
81 return Some((name, B::from_bits_retain(flag.bits())));
82 }
83 }
84
85 None
86 }
87}
88
89impl<B: Flags> FusedIterator for IterNames<B> {}
90
91/// An iterator over flags values.
92///
93/// This iterator will yield flags values for contained, defined flags first, with any remaining bits yielded
94/// as a final flags value.
95pub struct Iter<B: 'static> {
96 inner: IterNames<B>,
97 done: bool,
98}
99
100impl<B: Flags> Iter<B> {
101 #[inline]
102 pub fn new(flags: &B) -> Self {
103 Self {
104 inner: IterNames::new(flags),
105 done: false,
106 }
107 }
108}
109
110impl<B: 'static> Iter<B> {
111 // Used by the `bitflag` macro
112 #[doc(hidden)]
113 #[inline]
114 pub const fn __private_const_new(
115 flags: &'static [(&'static str, B)],
116 source: B,
117 remaining: B,
118 ) -> Self {
119 Iter {
120 inner: IterNames::__private_const_new(flags, source, remaining),
121 done: false,
122 }
123 }
124}
125
126impl<B: Flags> Iterator for Iter<B> {
127 type Item = B;
128
129 fn next(&mut self) -> Option<Self::Item> {
130 match self.inner.next() {
131 Some((_, flag)) => Some(flag),
132 None if !self.done => {
133 self.done = true;
134
135 // After iterating through valid names, if there are any bits left over
136 // then return one final value that includes them. This makes `into_iter`
137 // and `from_iter` roundtrip
138 if !self.inner.remaining().is_empty() {
139 Some(self.inner.remaining)
140 } else {
141 None
142 }
143 }
144 None => None,
145 }
146 }
147}
148
149impl<B: Flags> FusedIterator for Iter<B> {}