1use core::fmt;
2use core::iter::FusedIterator;
3use core::ops::{BitAndAssign, Not};
4
5use crate::{BitFlag, BitFlags, util};
6
7pub 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 #[inline]
30 #[must_use]
31 pub const fn new(flags: BitFlags<T, U>) -> Self {
32 Self(flags)
33 }
34}
35
36impl<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}