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> {}