bitflag_attr/
iter.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
//! Yield the bits of a source flags value in a set of contained flags values.

use core::iter::FusedIterator;

use super::Flags;

/// 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 [`#iter_name_ty::remaining`] method.
pub struct IterNames<B: 'static> {
    flags: &'static [(&'static str, B)],
    index: usize,
    source: B,
    remaining: B,
}

impl<B: Flags> IterNames<B> {
    pub(crate) fn new(flags: &B) -> Self {
        Self {
            flags: B::KNOWN_FLAGS,
            index: 0,
            source: B::from_bits_retain(flags.bits()),
            remaining: B::from_bits_retain(flags.bits()),
        }
    }
}

impl<B: 'static> IterNames<B> {
    /// 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 const fn remaining(&self) -> &B {
        &self.remaining
    }

    #[doc(hidden)]
    pub const fn __private_const_new(
        flags: &'static [(&'static str, B)],
        source: B,
        remaining: B,
    ) -> Self {
        IterNames {
            flags,
            index: 0,
            remaining,
            source,
        }
    }
}

impl<B: Flags> Iterator for IterNames<B> {
    type Item = (&'static str, B);

    fn next(&mut self) -> Option<Self::Item> {
        while let Some((name, flag)) = self.flags.get(self.index) {
            // Short-circuit if our state is empty
            if self.remaining.is_empty() {
                return None;
            }

            self.index += 1;

            // 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(*flag) && self.remaining.intersects(*flag) {
                self.remaining.unset(*flag);

                return Some((name, B::from_bits_retain(flag.bits())));
            }
        }

        None
    }
}

impl<B: Flags> FusedIterator for IterNames<B> {}

/// 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 fn new(flags: &B) -> Self {
        Self {
            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 [(&'static str, 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(self.inner.remaining)
                } else {
                    None
                }
            }
            None => None,
        }
    }
}

impl<B: Flags> FusedIterator for Iter<B> {}