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