Skip to main content

bitflags_lite/
iter.rs

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