Skip to content

Commit 39bd761

Browse files
committed
rename all_named_flags to iter_named
and add a test case test_iter_named
1 parent 3e52578 commit 39bd761

File tree

4 files changed

+248
-8
lines changed

4 files changed

+248
-8
lines changed

src/iter.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,40 @@ impl<B: Flags> Iterator for IterNames<B> {
143143
None
144144
}
145145
}
146+
147+
/**
148+
An iterator over all named flags.
149+
150+
This iterator will yield flags values for all defined named flags, regardless of
151+
whether they are contained in a particular flags value.
152+
*/
153+
pub struct IterNamed<B: 'static> {
154+
flags: &'static [Flag<B>],
155+
idx: usize,
156+
}
157+
158+
impl<B: Flags> IterNamed<B> {
159+
pub(crate) fn new() -> Self {
160+
IterNamed {
161+
flags: B::FLAGS,
162+
idx: 0,
163+
}
164+
}
165+
}
166+
167+
impl<B: Flags> Iterator for IterNamed<B> {
168+
type Item = B;
169+
170+
fn next(&mut self) -> Option<Self::Item> {
171+
while let Some(flag) = self.flags.get(self.idx) {
172+
self.idx += 1;
173+
174+
// Only yield named flags
175+
if flag.is_named() {
176+
return Some(B::from_bits_retain(flag.value().bits()));
177+
}
178+
}
179+
180+
None
181+
}
182+
}

src/tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ mod intersects;
2020
mod is_all;
2121
mod is_empty;
2222
mod iter;
23+
mod iter_named;
2324
mod parser;
2425
mod remove;
2526
mod symmetric_difference;

src/tests/iter_named.rs

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
use crate::Flags;
2+
3+
#[test]
4+
fn test_iter_named() {
5+
bitflags! {
6+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
7+
struct TestFlags: u32 {
8+
const A = 0b00000001;
9+
const ZERO = 0;
10+
const B = 0b00000010;
11+
const C = 0b00000100;
12+
const CC = Self::C.bits();
13+
const D = 0b10000100;
14+
const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits();
15+
const AB = Self::A.bits() | Self::B.bits();
16+
const AC = Self::A.bits() | Self::C.bits();
17+
const CB = Self::B.bits() | Self::C.bits();
18+
}
19+
}
20+
21+
// Test all named flags produced by the iterator
22+
let all_named: Vec<TestFlags> = TestFlags::iter_named().collect();
23+
24+
// Verify all named flags are included
25+
let expected_flags = vec![
26+
TestFlags::A,
27+
TestFlags::ZERO,
28+
TestFlags::B,
29+
TestFlags::C,
30+
TestFlags::CC, // Note: CC and C have the same bit value, but both are named flags
31+
TestFlags::D,
32+
TestFlags::ABC,
33+
TestFlags::AB,
34+
TestFlags::AC,
35+
TestFlags::CB,
36+
];
37+
38+
assert_eq!(
39+
all_named.len(),
40+
expected_flags.len(),
41+
"Should have 10 named flags"
42+
);
43+
44+
// Verify each expected flag is in the result
45+
for expected_flag in &expected_flags {
46+
assert!(
47+
all_named.contains(expected_flag),
48+
"Missing flag: {:?}",
49+
expected_flag
50+
);
51+
}
52+
53+
// Test if iterator order is consistent with definition order
54+
let flags_in_order: Vec<TestFlags> = TestFlags::iter_named().collect();
55+
assert_eq!(
56+
flags_in_order, expected_flags,
57+
"Flag order should match definition order"
58+
);
59+
60+
// Test that iterator can be used multiple times
61+
let first_iteration: Vec<TestFlags> = TestFlags::iter_named().collect();
62+
let second_iteration: Vec<TestFlags> = TestFlags::iter_named().collect();
63+
assert_eq!(
64+
first_iteration, second_iteration,
65+
"Multiple iterations should produce the same result"
66+
);
67+
68+
// Test consistency with FLAGS constant
69+
let flags_from_iter: std::collections::HashSet<u32> =
70+
TestFlags::iter_named().map(|f| f.bits()).collect();
71+
72+
let flags_from_const: std::collections::HashSet<u32> = TestFlags::FLAGS
73+
.iter()
74+
.filter(|f| f.is_named())
75+
.map(|f| f.value().bits())
76+
.collect();
77+
78+
assert_eq!(
79+
flags_from_iter, flags_from_const,
80+
"iter_named() should be consistent with named flags in FLAGS"
81+
);
82+
83+
// Test flag bit values
84+
for flag in TestFlags::iter_named() {
85+
let bits = flag.bits();
86+
match bits {
87+
0b00000001 => {} // A
88+
0 => {} // ZERO
89+
0b00000010 => {} // B
90+
0b00000100 => {} // C or CC (they have the same bit value)
91+
0b10000100 => {} // D
92+
0b00000111 => {} // ABC
93+
0b00000011 => {} // AB
94+
0b00000101 => {} // AC
95+
0b00000110 => {} // CB
96+
_ => panic!("Unexpected bit value: {:08b} from flag: {:?}", bits, flag),
97+
}
98+
}
99+
100+
// Verify specific flag bit values
101+
assert_eq!(TestFlags::A.bits(), 0b00000001);
102+
assert_eq!(TestFlags::ZERO.bits(), 0);
103+
assert_eq!(TestFlags::B.bits(), 0b00000010);
104+
assert_eq!(TestFlags::C.bits(), 0b00000100);
105+
assert_eq!(TestFlags::CC.bits(), 0b00000100); // Same as C
106+
assert_eq!(TestFlags::D.bits(), 0b10000100);
107+
assert_eq!(TestFlags::ABC.bits(), 0b00000111);
108+
assert_eq!(TestFlags::AB.bits(), 0b00000011);
109+
assert_eq!(TestFlags::AC.bits(), 0b00000101);
110+
assert_eq!(TestFlags::CB.bits(), 0b00000110);
111+
112+
// Test iterator usage with other iterator methods
113+
let non_zero_flags: Vec<TestFlags> =
114+
TestFlags::iter_named().filter(|f| !f.is_empty()).collect();
115+
assert_eq!(non_zero_flags.len(), 9, "Should have 9 non-zero flags");
116+
117+
let single_bit_flags: Vec<TestFlags> = TestFlags::iter_named()
118+
.filter(|f| f.bits().count_ones() == 1)
119+
.collect();
120+
// A, B, C, CC are all single-bit flags (CC and C have same bit value but both are enumerated)
121+
assert_eq!(
122+
single_bit_flags.len(),
123+
4,
124+
"Should have 4 single-bit flags (A, B, C, CC)"
125+
);
126+
127+
// Test composite flags (multiple bits set)
128+
let composite_flags: Vec<TestFlags> = TestFlags::iter_named()
129+
.filter(|f| f.bits().count_ones() > 1)
130+
.collect();
131+
assert_eq!(
132+
composite_flags.len(),
133+
5,
134+
"Should have 5 composite flags (D, ABC, AB, AC, CB)"
135+
);
136+
137+
println!("All iter_named() tests passed!");
138+
139+
// Optional: print all flags for debugging
140+
for flag in TestFlags::iter_named() {
141+
println!(
142+
"Flag: {:?}, bit value: {:08b} ({})",
143+
flag,
144+
flag.bits(),
145+
flag.bits()
146+
);
147+
}
148+
149+
// Additional edge case tests
150+
151+
// Test if iterator implements the Iterator trait correctly
152+
let mut iter = TestFlags::iter_named();
153+
let first = iter.next();
154+
assert!(
155+
first.is_some(),
156+
"Iterator should produce at least one element"
157+
);
158+
159+
// Test size_hint (if implemented)
160+
let iter = TestFlags::iter_named();
161+
let (lower, upper) = iter.size_hint();
162+
println!("Iterator size_hint: lower={}, upper={:?}", lower, upper);
163+
164+
// Test usage with collect
165+
let collected: std::collections::BTreeSet<u32> =
166+
TestFlags::iter_named().map(|f| f.bits()).collect();
167+
println!("Deduplicated bit value set: {:?}", collected);
168+
169+
// Test fold and reduce operations
170+
let all_bits_or = TestFlags::iter_named().fold(TestFlags::empty(), |acc, flag| acc.union(flag));
171+
println!(
172+
"Union of all flags: {:?} (bit value: {:08b})",
173+
all_bits_or,
174+
all_bits_or.bits()
175+
);
176+
177+
// Test usage with enumerate
178+
for (index, flag) in TestFlags::iter_named().enumerate() {
179+
println!("Flag #{}: {:?}", index, flag);
180+
if index >= 2 {
181+
// Only print first few to avoid excessive output
182+
println!("... (more flags)");
183+
break;
184+
}
185+
}
186+
187+
// Test handling of empty flags
188+
let zero_flags: Vec<TestFlags> = TestFlags::iter_named().filter(|f| f.is_empty()).collect();
189+
assert_eq!(
190+
zero_flags.len(),
191+
1,
192+
"Should have only one empty flag (ZERO)"
193+
);
194+
assert_eq!(zero_flags[0], TestFlags::ZERO);
195+
196+
// Test flags with duplicate bit values (C and CC)
197+
let c_value_flags: Vec<TestFlags> = TestFlags::iter_named()
198+
.filter(|f| f.bits() == 0b00000100)
199+
.collect();
200+
assert_eq!(
201+
c_value_flags.len(),
202+
2,
203+
"Should have two flags with the same bit value 0b00000100"
204+
);
205+
}

src/traits.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -152,14 +152,6 @@ pub trait Flags: Sized + 'static {
152152
Self::from_bits_retain(truncated)
153153
}
154154

155-
/// This method will return an iterator over all named flags (including combinations).
156-
fn all_named_flags() -> impl Iterator<Item = Self> {
157-
Self::FLAGS
158-
.iter()
159-
.filter(|f| f.is_named())
160-
.map(|f| Self::from_bits_retain(f.value().bits()))
161-
}
162-
163155
/// This method will return `true` if any unknown bits are set.
164156
fn contains_unknown_bits(&self) -> bool {
165157
Self::all().bits() & self.bits() != self.bits()
@@ -218,6 +210,11 @@ pub trait Flags: Sized + 'static {
218210
iter::Iter::new(self)
219211
}
220212

213+
/// This method will return an iterator over all named flags (including combinations).
214+
fn iter_named() -> iter::IterNamed<Self> {
215+
iter::IterNamed::new()
216+
}
217+
221218
/// Yield a set of contained named flags values.
222219
///
223220
/// This method is like [`Flags::iter`], except only yields bits in contained named flags.

0 commit comments

Comments
 (0)