Skip to main content

bitflags_lite/
iter.rs

1use core::any::type_name;
2use core::fmt;
3use core::iter::FusedIterator;
4use core::ops::{BitAndAssign, Not};
5
6use crate::{BitFlag, BitFlags, util};
7
8/// An iterator over the individual bits set in a [`BitFlags`] value.
9///
10/// Each item is a [`BitFlag`] value containing exactly one set bit.
11/// The iterator yields bits from the least significant bit to the most
12/// significant bit, and also supports double-ended iteration.
13///
14/// The iterator yields all set bits, including invalid bits if the source
15/// [`BitFlags`] was created with [`BitFlags::from_bits_retain`] or otherwise
16/// contains invalid bits.
17///
18/// This type is created by the [`IntoIterator`] implementation for
19/// [`BitFlags`].
20pub struct BitFlagsIter<T, U>(BitFlags<T, U>)
21where
22    U: ?Sized;
23
24impl<T, U> BitFlagsIter<T, U>
25where
26    T: Copy + Not<Output = T> + BitAndAssign<T> + util::IntOpsExt,
27    U: ?Sized,
28{
29    /// Creates an iterator over the set bits in `flags`.
30    #[inline]
31    #[must_use]
32    pub const fn new(flags: BitFlags<T, U>) -> Self {
33        Self(flags)
34    }
35}
36
37// The iterators should not implement `Copy`.
38impl<T, U> Clone for BitFlagsIter<T, U>
39where
40    T: Clone,
41    U: ?Sized,
42{
43    #[inline]
44    fn clone(&self) -> Self {
45        Self(self.0.clone())
46    }
47}
48
49impl<T, U> Default for BitFlagsIter<T, U>
50where
51    T: Default,
52    U: ?Sized,
53{
54    #[inline]
55    fn default() -> Self {
56        Self(BitFlags::default())
57    }
58}
59
60impl<T, U> fmt::Debug for BitFlagsIter<T, U>
61where
62    T: fmt::LowerHex,
63    U: ?Sized,
64{
65    #[inline]
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        f.debug_tuple("BitFlagsIter").field(&self.0).finish()
68    }
69}
70
71impl<T, U> Iterator for BitFlagsIter<T, U>
72where
73    T: Copy + Not<Output = T> + BitAndAssign<T> + util::IntOpsExt,
74    U: ?Sized,
75{
76    type Item = BitFlag<T, U>;
77
78    #[inline]
79    fn next(&mut self) -> Option<Self::Item> {
80        let lowest = self.0.bits().lowest_one()?;
81
82        #[expect(clippy::panic, reason = "enabled only for `debug_assertions`")]
83        let Some(mask) = T::ONE.checked_shl(lowest) else {
84            #[cfg(debug_assertions)]
85            panic!(
86                "invalid implementation of `{}`, checked_shl failed with bit from lowest_one",
87                type_name::<T>()
88            );
89            #[cfg(not(debug_assertions))]
90            return None;
91        };
92        *self.0.bits_mut() &= !mask;
93
94        #[expect(
95            clippy::as_conversions,
96            clippy::cast_possible_truncation,
97            reason = "types longer than 256 bits are not supported"
98        )]
99        Some(BitFlag::from_bit_retain(lowest as u8))
100    }
101
102    #[expect(clippy::as_conversions, reason = "T::count_ones never exceeds `usize`")]
103    #[inline]
104    fn size_hint(&self) -> (usize, Option<usize>) {
105        let len = self.0.bits().count_ones() as usize;
106        (len, Some(len))
107    }
108}
109
110impl<T, U> DoubleEndedIterator for BitFlagsIter<T, U>
111where
112    T: Copy + Not<Output = T> + BitAndAssign<T> + util::IntOpsExt,
113    U: ?Sized,
114{
115    #[inline]
116    fn next_back(&mut self) -> Option<Self::Item> {
117        let lowest = self.0.bits().highest_one()?;
118
119        #[expect(clippy::panic, reason = "enabled only for `debug_assertions`")]
120        let Some(mask) = T::ONE.checked_shl(lowest) else {
121            #[cfg(debug_assertions)]
122            panic!(
123                "invalid implementation of `{}`, checked_shl failed with bit from lowest_one",
124                type_name::<T>()
125            );
126            #[cfg(not(debug_assertions))]
127            return None;
128        };
129        *self.0.bits_mut() &= !mask;
130
131        #[expect(
132            clippy::as_conversions,
133            clippy::cast_possible_truncation,
134            reason = "types longer than 256 bits are not supported"
135        )]
136        Some(BitFlag::from_bit_retain(lowest as u8))
137    }
138}
139
140impl<T, U> ExactSizeIterator for BitFlagsIter<T, U>
141where
142    T: Copy + Not<Output = T> + BitAndAssign<T> + util::IntOpsExt,
143    U: ?Sized,
144{
145    #[expect(clippy::as_conversions, reason = "T::count_ones never exceeds `usize`")]
146    #[inline]
147    fn len(&self) -> usize {
148        self.0.bits().count_ones() as usize
149    }
150}
151
152impl<T, U> FusedIterator for BitFlagsIter<T, U>
153where
154    T: Copy + Not<Output = T> + BitAndAssign<T> + util::IntOpsExt,
155    U: ?Sized,
156{
157}