3 use ops::{self, Add, Sub, Try};
6 use super::{FusedIterator, TrustedLen};
8 /// Objects that can be stepped over in both directions.
10 /// The `steps_between` function provides a way to efficiently compare
11 /// two `Step` objects.
12 #[unstable(feature = "step_trait",
13 reason = "likely to be replaced by finer-grained traits",
15 pub trait Step: Clone + PartialOrd + Sized {
16 /// Returns the number of steps between two step objects. The count is
17 /// inclusive of `start` and exclusive of `end`.
19 /// Returns `None` if it is not possible to calculate `steps_between`
21 fn steps_between(start: &Self, end: &Self) -> Option<usize>;
23 /// Replaces this step with `1`, returning itself.
24 fn replace_one(&mut self) -> Self;
26 /// Replaces this step with `0`, returning itself.
27 fn replace_zero(&mut self) -> Self;
29 /// Adds one to this step, returning the result.
30 fn add_one(&self) -> Self;
32 /// Subtracts one to this step, returning the result.
33 fn sub_one(&self) -> Self;
35 /// Adds a `usize`, returning `None` on overflow.
36 fn add_usize(&self, n: usize) -> Option<Self>;
39 // These are still macro-generated because the integer literals resolve to different types.
40 macro_rules! step_identical_methods {
43 fn replace_one(&mut self) -> Self {
48 fn replace_zero(&mut self) -> Self {
53 fn add_one(&self) -> Self {
58 fn sub_one(&self) -> Self {
64 macro_rules! step_impl_unsigned {
66 #[unstable(feature = "step_trait",
67 reason = "likely to be replaced by finer-grained traits",
71 fn steps_between(start: &$t, end: &$t) -> Option<usize> {
73 usize::try_from(*end - *start).ok()
80 #[allow(unreachable_patterns)]
81 fn add_usize(&self, n: usize) -> Option<Self> {
82 match <$t>::try_from(n) {
83 Ok(n_as_t) => self.checked_add(n_as_t),
88 step_identical_methods!();
92 macro_rules! step_impl_signed {
93 ($( [$t:ty : $unsigned:ty] )*) => ($(
94 #[unstable(feature = "step_trait",
95 reason = "likely to be replaced by finer-grained traits",
99 fn steps_between(start: &$t, end: &$t) -> Option<usize> {
101 // Use .wrapping_sub and cast to unsigned to compute the
102 // difference that may not fit inside the range of $t.
103 usize::try_from(end.wrapping_sub(*start) as $unsigned).ok()
110 #[allow(unreachable_patterns)]
111 fn add_usize(&self, n: usize) -> Option<Self> {
112 match <$unsigned>::try_from(n) {
113 Ok(n_as_unsigned) => {
114 // Wrapping in unsigned space handles cases like
115 // `-120_i8.add_usize(200) == Some(80_i8)`,
116 // even though 200_usize is out of range for i8.
117 let wrapped = (*self as $unsigned).wrapping_add(n_as_unsigned) as $t;
118 if wrapped >= *self {
121 None // Addition overflowed
128 step_identical_methods!();
133 step_impl_unsigned!(usize u8 u16 u32 u64 u128);
134 step_impl_signed!([isize: usize] [i8: u8] [i16: u16]);
135 step_impl_signed!([i32: u32] [i64: u64] [i128: u128]);
137 macro_rules! range_exact_iter_impl {
139 #[stable(feature = "rust1", since = "1.0.0")]
140 impl ExactSizeIterator for ops::Range<$t> { }
144 macro_rules! range_incl_exact_iter_impl {
146 #[stable(feature = "inclusive_range", since = "1.26.0")]
147 impl ExactSizeIterator for ops::RangeInclusive<$t> { }
151 macro_rules! range_trusted_len_impl {
153 #[unstable(feature = "trusted_len", issue = "37572")]
154 unsafe impl TrustedLen for ops::Range<$t> { }
158 macro_rules! range_incl_trusted_len_impl {
160 #[unstable(feature = "trusted_len", issue = "37572")]
161 unsafe impl TrustedLen for ops::RangeInclusive<$t> { }
165 #[stable(feature = "rust1", since = "1.0.0")]
166 impl<A: Step> Iterator for ops::Range<A> {
170 fn next(&mut self) -> Option<A> {
171 if self.start < self.end {
172 // We check for overflow here, even though it can't actually
173 // happen. Adding this check does however help llvm vectorize loops
174 // for some ranges that don't get vectorized otherwise,
175 // and this won't actually result in an extra check in an optimized build.
176 if let Some(mut n) = self.start.add_usize(1) {
177 mem::swap(&mut n, &mut self.start);
188 fn size_hint(&self) -> (usize, Option<usize>) {
189 match Step::steps_between(&self.start, &self.end) {
190 Some(hint) => (hint, Some(hint)),
191 None => (usize::MAX, None)
196 fn nth(&mut self, n: usize) -> Option<A> {
197 if let Some(plus_n) = self.start.add_usize(n) {
198 if plus_n < self.end {
199 self.start = plus_n.add_one();
204 self.start = self.end.clone();
209 fn last(mut self) -> Option<A> {
214 fn min(mut self) -> Option<A> {
219 fn max(mut self) -> Option<A> {
224 // These macros generate `ExactSizeIterator` impls for various range types.
225 // Range<{u,i}64> and RangeInclusive<{u,i}{32,64,size}> are excluded
226 // because they cannot guarantee having a length <= usize::MAX, which is
227 // required by ExactSizeIterator.
228 range_exact_iter_impl!(usize u8 u16 u32 isize i8 i16 i32);
229 range_incl_exact_iter_impl!(u8 u16 i8 i16);
231 // These macros generate `TrustedLen` impls.
233 // They need to guarantee that .size_hint() is either exact, or that
234 // the upper bound is None when it does not fit the type limits.
235 range_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64);
236 range_incl_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64);
238 #[stable(feature = "rust1", since = "1.0.0")]
239 impl<A: Step> DoubleEndedIterator for ops::Range<A> {
241 fn next_back(&mut self) -> Option<A> {
242 if self.start < self.end {
243 self.end = self.end.sub_one();
244 Some(self.end.clone())
251 #[stable(feature = "fused", since = "1.26.0")]
252 impl<A: Step> FusedIterator for ops::Range<A> {}
254 #[stable(feature = "rust1", since = "1.0.0")]
255 impl<A: Step> Iterator for ops::RangeFrom<A> {
259 fn next(&mut self) -> Option<A> {
260 let mut n = self.start.add_one();
261 mem::swap(&mut n, &mut self.start);
266 fn size_hint(&self) -> (usize, Option<usize>) {
271 fn nth(&mut self, n: usize) -> Option<A> {
272 let plus_n = self.start.add_usize(n).expect("overflow in RangeFrom::nth");
273 self.start = plus_n.add_one();
278 #[stable(feature = "fused", since = "1.26.0")]
279 impl<A: Step> FusedIterator for ops::RangeFrom<A> {}
281 #[unstable(feature = "trusted_len", issue = "37572")]
282 unsafe impl<A: Step> TrustedLen for ops::RangeFrom<A> {}
284 #[stable(feature = "inclusive_range", since = "1.26.0")]
285 impl<A: Step> Iterator for ops::RangeInclusive<A> {
289 fn next(&mut self) -> Option<A> {
290 self.compute_is_empty();
291 if self.is_empty.unwrap_or_default() {
294 let is_iterating = self.start < self.end;
295 self.is_empty = Some(!is_iterating);
296 Some(if is_iterating {
297 let n = self.start.add_one();
298 mem::replace(&mut self.start, n)
305 fn size_hint(&self) -> (usize, Option<usize>) {
310 match Step::steps_between(&self.start, &self.end) {
311 Some(hint) => (hint.saturating_add(1), hint.checked_add(1)),
312 None => (usize::MAX, None),
317 fn nth(&mut self, n: usize) -> Option<A> {
318 self.compute_is_empty();
319 if self.is_empty.unwrap_or_default() {
323 if let Some(plus_n) = self.start.add_usize(n) {
324 use cmp::Ordering::*;
326 match plus_n.partial_cmp(&self.end) {
328 self.is_empty = Some(false);
329 self.start = plus_n.add_one();
333 self.is_empty = Some(true);
340 self.is_empty = Some(true);
345 fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
347 Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
349 self.compute_is_empty();
352 return Try::from_ok(init);
355 let mut accum = init;
357 while self.start < self.end {
358 let n = self.start.add_one();
359 let n = mem::replace(&mut self.start, n);
360 accum = f(accum, n)?;
363 self.is_empty = Some(true);
365 if self.start == self.end {
366 accum = f(accum, self.start.clone())?;
373 fn last(mut self) -> Option<A> {
378 fn min(mut self) -> Option<A> {
383 fn max(mut self) -> Option<A> {
388 #[stable(feature = "inclusive_range", since = "1.26.0")]
389 impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
391 fn next_back(&mut self) -> Option<A> {
392 self.compute_is_empty();
393 if self.is_empty.unwrap_or_default() {
396 let is_iterating = self.start < self.end;
397 self.is_empty = Some(!is_iterating);
398 Some(if is_iterating {
399 let n = self.end.sub_one();
400 mem::replace(&mut self.end, n)
407 fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R where
408 Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
410 self.compute_is_empty();
413 return Try::from_ok(init);
416 let mut accum = init;
418 while self.start < self.end {
419 let n = self.end.sub_one();
420 let n = mem::replace(&mut self.end, n);
421 accum = f(accum, n)?;
424 self.is_empty = Some(true);
426 if self.start == self.end {
427 accum = f(accum, self.start.clone())?;
434 #[stable(feature = "fused", since = "1.26.0")]
435 impl<A: Step> FusedIterator for ops::RangeInclusive<A> {}