@@ -16,6 +16,12 @@ use crate::{
1616#[ stable( feature = "iterator_step_by" , since = "1.28.0" ) ]
1717#[ derive( Clone , Debug ) ]
1818pub 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.
1925 iter : I ,
2026 step : usize ,
2127 first_take : bool ,
@@ -133,6 +139,16 @@ impl<T> SpecRangeSetup<T> for T {
133139 }
134140}
135141
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.
136152trait StepByImpl < I > {
137153 type Item ;
138154
@@ -152,6 +168,16 @@ trait StepByImpl<I> {
152168 F : FnMut ( Acc , Self :: Item ) -> Acc ;
153169}
154170
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.
155181trait StepByBackImpl < I > {
156182 type Item ;
157183
@@ -357,6 +383,21 @@ impl<I: DoubleEndedIterator + ExactSizeIterator> StepByBackImpl<I> for StepBy<I>
357383 }
358384}
359385
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.
360401macro_rules! spec_int_ranges {
361402 ( $( $t: ty) * ) => ( $(
362403
0 commit comments