@@ -18,6 +18,9 @@ pub struct Chain<A, B> {
18
18
// adapter because its specialization for `FusedIterator` unconditionally descends into the
19
19
// iterator, and that could be expensive to keep revisiting stuff like nested chains. It also
20
20
// hurts compiler performance to add more iterator layers to `Chain`.
21
+ //
22
+ // Only the "first" iterator is actually set `None` when exhausted, depending on whether you
23
+ // iterate forward or backward. If you mix directions, then both sides may be `None`.
21
24
a : Option < A > ,
22
25
b : Option < B > ,
23
26
}
@@ -43,6 +46,17 @@ macro_rules! fuse {
43
46
} ;
44
47
}
45
48
49
+ /// Try an iterator method without fusing,
50
+ /// like an inline `.as_mut().and_then(...)`
51
+ macro_rules! maybe {
52
+ ( $self: ident . $iter: ident . $( $call: tt) +) => {
53
+ match $self. $iter {
54
+ Some ( ref mut iter) => iter. $( $call) +,
55
+ None => None ,
56
+ }
57
+ } ;
58
+ }
59
+
46
60
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
47
61
impl < A , B > Iterator for Chain < A , B >
48
62
where
54
68
#[ inline]
55
69
fn next ( & mut self ) -> Option < A :: Item > {
56
70
match fuse ! ( self . a. next( ) ) {
57
- None => fuse ! ( self . b. next( ) ) ,
71
+ None => maybe ! ( self . b. next( ) ) ,
58
72
item => item,
59
73
}
60
74
}
85
99
}
86
100
if let Some ( ref mut b) = self . b {
87
101
acc = b. try_fold ( acc, f) ?;
88
- self . b = None ;
102
+ // we don't fuse the second iterator
89
103
}
90
104
Try :: from_ok ( acc)
91
105
}
@@ -114,7 +128,7 @@ where
114
128
}
115
129
self . a = None ;
116
130
}
117
- fuse ! ( self . b. nth( n) )
131
+ maybe ! ( self . b. nth( n) )
118
132
}
119
133
120
134
#[ inline]
@@ -123,7 +137,7 @@ where
123
137
P : FnMut ( & Self :: Item ) -> bool ,
124
138
{
125
139
match fuse ! ( self . a. find( & mut predicate) ) {
126
- None => fuse ! ( self . b. find( predicate) ) ,
140
+ None => maybe ! ( self . b. find( predicate) ) ,
127
141
item => item,
128
142
}
129
143
}
@@ -174,7 +188,7 @@ where
174
188
#[ inline]
175
189
fn next_back ( & mut self ) -> Option < A :: Item > {
176
190
match fuse ! ( self . b. next_back( ) ) {
177
- None => fuse ! ( self . a. next_back( ) ) ,
191
+ None => maybe ! ( self . a. next_back( ) ) ,
178
192
item => item,
179
193
}
180
194
}
@@ -190,7 +204,7 @@ where
190
204
}
191
205
self . b = None ;
192
206
}
193
- fuse ! ( self . a. nth_back( n) )
207
+ maybe ! ( self . a. nth_back( n) )
194
208
}
195
209
196
210
#[ inline]
@@ -199,7 +213,7 @@ where
199
213
P : FnMut ( & Self :: Item ) -> bool ,
200
214
{
201
215
match fuse ! ( self . b. rfind( & mut predicate) ) {
202
- None => fuse ! ( self . a. rfind( predicate) ) ,
216
+ None => maybe ! ( self . a. rfind( predicate) ) ,
203
217
item => item,
204
218
}
205
219
}
@@ -216,7 +230,7 @@ where
216
230
}
217
231
if let Some ( ref mut a) = self . a {
218
232
acc = a. try_rfold ( acc, f) ?;
219
- self . a = None ;
233
+ // we don't fuse the second iterator
220
234
}
221
235
Try :: from_ok ( acc)
222
236
}
@@ -236,8 +250,6 @@ where
236
250
}
237
251
238
252
// Note: *both* must be fused to handle double-ended iterators.
239
- // Now that we "fuse" both sides, we *could* implement this unconditionally,
240
- // but we should be cautious about committing to that in the public API.
241
253
#[ stable( feature = "fused" , since = "1.26.0" ) ]
242
254
impl < A , B > FusedIterator for Chain < A , B >
243
255
where
0 commit comments