@@ -16,6 +16,12 @@ use crate::{
16
16
#[ stable( feature = "iterator_step_by" , since = "1.28.0" ) ]
17
17
#[ derive( Clone , Debug ) ]
18
18
pub struct StepBy < I > {
19
+ /// This field is guaranteed to be preprocessed by the specialized `SpecRangeSetup::setup`
20
+ /// in the constructor.
21
+ /// For most iterators that processing is a no-op, but for Range<{integer}> types it is lossy
22
+ /// which means the inner iterator cannot be returned to user code.
23
+ /// Additionally this type-dependent preprocessing means specialized implementations
24
+ /// cannot be used interchangeably.
19
25
iter : I ,
20
26
step : usize ,
21
27
first_take : bool ,
@@ -133,6 +139,16 @@ impl<T> SpecRangeSetup<T> for T {
133
139
}
134
140
}
135
141
142
+ /// Specialization trait to optimize `StepBy<Range<{integer}>>` iteration.
143
+ ///
144
+ /// # Correctness
145
+ ///
146
+ /// Technically this is safe to implement (look ma, no unsafe!), but in reality
147
+ /// a lot of unsafe code relies on ranges over integers being correct.
148
+ ///
149
+ /// For correctness *all* public StepBy methods must be specialized
150
+ /// because `setup` drastically alters the meaning of the struct fields so that mixing
151
+ /// different implementations would lead to incorrect results.
136
152
trait StepByImpl < I > {
137
153
type Item ;
138
154
@@ -152,6 +168,16 @@ trait StepByImpl<I> {
152
168
F : FnMut ( Acc , Self :: Item ) -> Acc ;
153
169
}
154
170
171
+ /// Specialization trait for double-ended iteration.
172
+ ///
173
+ /// See also: `StepByImpl`
174
+ ///
175
+ /// # Correctness
176
+ ///
177
+ /// The specializations must be implemented together with `StepByImpl`
178
+ /// where applicable. I.e. if `StepBy` does support backwards iteration
179
+ /// for a given iterator and that is specialized for forward iteration then
180
+ /// it must also be specialized for backwards iteration.
155
181
trait StepByBackImpl < I > {
156
182
type Item ;
157
183
@@ -357,6 +383,21 @@ impl<I: DoubleEndedIterator + ExactSizeIterator> StepByBackImpl<I> for StepBy<I>
357
383
}
358
384
}
359
385
386
+ /// For these implementations, `SpecRangeSetup` calculates the number
387
+ /// of iterations that will be needed and stores that in `iter.end`.
388
+ ///
389
+ /// The various iterator implementations then rely on that to not need
390
+ /// overflow checking, letting loops just be counted instead.
391
+ ///
392
+ /// These only work for unsigned types, and will need to be reworked
393
+ /// if you want to use it to specialize on signed types.
394
+ ///
395
+ /// Currently these are only implemented for integers up to usize due to
396
+ /// correctness issues around ExactSizeIterator impls on 16bit platforms.
397
+ /// And since ExactSizeIterator is a prerequisite for backwards iteration
398
+ /// and we must consistently specialize backwards and forwards iteration
399
+ /// that makes the situation complicated enough that it's not covered
400
+ /// for now.
360
401
macro_rules! spec_int_ranges {
361
402
( $( $t: ty) * ) => ( $(
362
403
0 commit comments