From 69db91b8b25de51633ac9f089cd7fb10a58c2b2a Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sun, 26 Dec 2021 03:21:54 +0100 Subject: [PATCH 1/4] Change advance(_back)_by to return `usize` instead of `Result<(), usize>` A successful advance is now signalled by returning `0` and other values now represent the remaining number of steps that couldn't be advanced as opposed to the amount of steps that have been advanced during a partial advance_by. This simplifies adapters a bit, replacing some `match`/`if` with arithmetic. Whether this is beneficial overall depends on whether `advance_by` is mostly used as a building-block for other iterator methods and adapters or whether we also see uses by users where `Result` might be more useful. --- .../src/collections/vec_deque/into_iter.rs | 12 ++--- .../alloc/src/collections/vec_deque/iter.rs | 25 +++++---- .../src/collections/vec_deque/iter_mut.rs | 25 +++++---- library/alloc/src/vec/into_iter.rs | 14 ++--- library/alloc/tests/vec.rs | 21 ++++---- library/core/src/array/iter.rs | 14 +++-- .../core/src/iter/adapters/by_ref_sized.rs | 4 +- library/core/src/iter/adapters/chain.rs | 54 ++++++++----------- library/core/src/iter/adapters/copied.rs | 4 +- library/core/src/iter/adapters/cycle.rs | 21 ++++---- library/core/src/iter/adapters/enumerate.rs | 17 ++---- library/core/src/iter/adapters/flatten.rs | 28 +++++----- library/core/src/iter/adapters/rev.rs | 4 +- library/core/src/iter/adapters/skip.rs | 49 +++++++---------- library/core/src/iter/adapters/take.rs | 29 ++++------ library/core/src/iter/range.rs | 24 ++++----- library/core/src/iter/sources/repeat.rs | 8 +-- library/core/src/iter/sources/repeat_n.rs | 8 +-- library/core/src/iter/traits/double_ended.rs | 28 +++++----- library/core/src/iter/traits/iterator.rs | 28 +++++----- library/core/src/ops/index_range.rs | 14 +++-- library/core/src/slice/iter/macros.rs | 8 +-- library/core/tests/array.rs | 34 ++++++------ library/core/tests/iter/adapters/chain.rs | 40 +++++++------- library/core/tests/iter/adapters/flatten.rs | 45 ++++++++-------- library/core/tests/iter/adapters/skip.rs | 17 +++--- library/core/tests/iter/adapters/take.rs | 22 ++++---- library/core/tests/iter/range.rs | 18 +++---- library/core/tests/iter/traits/iterator.rs | 32 +++++------ library/core/tests/slice.rs | 20 +++---- 30 files changed, 315 insertions(+), 352 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/into_iter.rs b/library/alloc/src/collections/vec_deque/into_iter.rs index 34bc0ce9177c4..8ba963b790d89 100644 --- a/library/alloc/src/collections/vec_deque/into_iter.rs +++ b/library/alloc/src/collections/vec_deque/into_iter.rs @@ -54,14 +54,14 @@ impl Iterator for IntoIter { } #[inline] - fn advance_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_by(&mut self, n: usize) -> usize { if self.inner.len < n { let len = self.inner.len; self.inner.clear(); - Err(len) + len - n } else { self.inner.drain(..n); - Ok(()) + 0 } } @@ -182,14 +182,14 @@ impl DoubleEndedIterator for IntoIter { } #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_back_by(&mut self, n: usize) -> usize { let len = self.inner.len; if len >= n { self.inner.truncate(len - n); - Ok(()) + 0 } else { self.inner.clear(); - Err(len) + n - len } } diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs index d9f3937144d04..5b91c1635f0d6 100644 --- a/library/alloc/src/collections/vec_deque/iter.rs +++ b/library/alloc/src/collections/vec_deque/iter.rs @@ -55,13 +55,13 @@ impl<'a, T> Iterator for Iter<'a, T> { } } - fn advance_by(&mut self, n: usize) -> Result<(), usize> { - let m = match self.i1.advance_by(n) { - Ok(_) => return Ok(()), - Err(m) => m, - }; + fn advance_by(&mut self, n: usize) -> usize { + let remaining = self.i1.advance_by(n); + if remaining == 0 { + return 0; + } mem::swap(&mut self.i1, &mut self.i2); - self.i1.advance_by(n - m).map_err(|o| o + m) + self.i1.advance_by(remaining) } #[inline] @@ -125,14 +125,13 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { } } - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { - let m = match self.i2.advance_back_by(n) { - Ok(_) => return Ok(()), - Err(m) => m, - }; - + fn advance_back_by(&mut self, n: usize) -> usize { + let remaining = self.i2.advance_back_by(n); + if remaining == 0 { + return 0; + } mem::swap(&mut self.i1, &mut self.i2); - self.i2.advance_back_by(n - m).map_err(|o| m + o) + self.i2.advance_back_by(remaining) } fn rfold(self, accum: Acc, mut f: F) -> Acc diff --git a/library/alloc/src/collections/vec_deque/iter_mut.rs b/library/alloc/src/collections/vec_deque/iter_mut.rs index 2c59d95cd53e9..848cb3649c852 100644 --- a/library/alloc/src/collections/vec_deque/iter_mut.rs +++ b/library/alloc/src/collections/vec_deque/iter_mut.rs @@ -47,13 +47,13 @@ impl<'a, T> Iterator for IterMut<'a, T> { } } - fn advance_by(&mut self, n: usize) -> Result<(), usize> { - let m = match self.i1.advance_by(n) { - Ok(_) => return Ok(()), - Err(m) => m, - }; + fn advance_by(&mut self, n: usize) -> usize { + let remaining = self.i1.advance_by(n); + if remaining == 0 { + return 0; + } mem::swap(&mut self.i1, &mut self.i2); - self.i1.advance_by(n - m).map_err(|o| o + m) + self.i1.advance_by(remaining) } #[inline] @@ -117,14 +117,13 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { } } - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { - let m = match self.i2.advance_back_by(n) { - Ok(_) => return Ok(()), - Err(m) => m, - }; - + fn advance_back_by(&mut self, n: usize) -> usize { + let remaining = self.i2.advance_back_by(n); + if remaining == 0 { + return 0; + } mem::swap(&mut self.i1, &mut self.i2); - self.i2.advance_back_by(n - m).map_err(|o| m + o) + self.i2.advance_back_by(remaining) } fn rfold(self, accum: Acc, mut f: F) -> Acc diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index f6525eb900386..504ca4333bed5 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -213,7 +213,7 @@ impl Iterator for IntoIter { } #[inline] - fn advance_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_by(&mut self, n: usize) -> usize { let step_size = self.len().min(n); let to_drop = ptr::slice_from_raw_parts_mut(self.ptr as *mut T, step_size); if T::IS_ZST { @@ -227,10 +227,7 @@ impl Iterator for IntoIter { unsafe { ptr::drop_in_place(to_drop); } - if step_size < n { - return Err(step_size); - } - Ok(()) + n - step_size } #[inline] @@ -313,7 +310,7 @@ impl DoubleEndedIterator for IntoIter { } #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_back_by(&mut self, n: usize) -> usize { let step_size = self.len().min(n); if T::IS_ZST { // SAFETY: same as for advance_by() @@ -327,10 +324,7 @@ impl DoubleEndedIterator for IntoIter { unsafe { ptr::drop_in_place(to_drop); } - if step_size < n { - return Err(step_size); - } - Ok(()) + n - step_size } } diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 2f07c2911a502..e00af189fbfed 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -1,4 +1,5 @@ use core::alloc::{Allocator, Layout}; +use core::assert_eq; use core::iter::IntoIterator; use core::ptr::NonNull; use std::alloc::System; @@ -1062,21 +1063,21 @@ fn test_into_iter_leak() { #[test] fn test_into_iter_advance_by() { - let mut i = [1, 2, 3, 4, 5].into_iter(); - i.advance_by(0).unwrap(); - i.advance_back_by(0).unwrap(); + let mut i = vec![1, 2, 3, 4, 5].into_iter(); + assert_eq!(i.advance_by(0), 0); + assert_eq!(i.advance_back_by(0), 0); assert_eq!(i.as_slice(), [1, 2, 3, 4, 5]); - i.advance_by(1).unwrap(); - i.advance_back_by(1).unwrap(); + assert_eq!(i.advance_by(1), 0); + assert_eq!(i.advance_back_by(1), 0); assert_eq!(i.as_slice(), [2, 3, 4]); - assert_eq!(i.advance_back_by(usize::MAX), Err(3)); + assert_eq!(i.advance_back_by(usize::MAX), usize::MAX - 3); - assert_eq!(i.advance_by(usize::MAX), Err(0)); + assert_eq!(i.advance_by(usize::MAX), usize::MAX); - i.advance_by(0).unwrap(); - i.advance_back_by(0).unwrap(); + assert_eq!(i.advance_by(0), 0); + assert_eq!(i.advance_back_by(0), 0); assert_eq!(i.len(), 0); } @@ -1124,7 +1125,7 @@ fn test_into_iter_zst() { for _ in vec![C; 5].into_iter().rev() {} let mut it = vec![C, C].into_iter(); - it.advance_by(1).unwrap(); + assert_eq!(it.advance_by(1), 0); drop(it); let mut it = vec![C, C].into_iter(); diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index 8259c087d22e4..2d853dd6684ec 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -284,12 +284,11 @@ impl Iterator for IntoIter { self.next_back() } - fn advance_by(&mut self, n: usize) -> Result<(), usize> { - let original_len = self.len(); - + fn advance_by(&mut self, n: usize) -> usize { // This also moves the start, which marks them as conceptually "dropped", // so if anything goes bad then our drop impl won't double-free them. let range_to_drop = self.alive.take_prefix(n); + let remaining = n - range_to_drop.len(); // SAFETY: These elements are currently initialized, so it's fine to drop them. unsafe { @@ -297,7 +296,7 @@ impl Iterator for IntoIter { ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice)); } - if n > original_len { Err(original_len) } else { Ok(()) } + remaining } } @@ -334,12 +333,11 @@ impl DoubleEndedIterator for IntoIter { }) } - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { - let original_len = self.len(); - + fn advance_back_by(&mut self, n: usize) -> usize { // This also moves the end, which marks them as conceptually "dropped", // so if anything goes bad then our drop impl won't double-free them. let range_to_drop = self.alive.take_suffix(n); + let remaining = n - range_to_drop.len(); // SAFETY: These elements are currently initialized, so it's fine to drop them. unsafe { @@ -347,7 +345,7 @@ impl DoubleEndedIterator for IntoIter { ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice)); } - if n > original_len { Err(original_len) } else { Ok(()) } + remaining } } diff --git a/library/core/src/iter/adapters/by_ref_sized.rs b/library/core/src/iter/adapters/by_ref_sized.rs index 477e7117c3ea1..ff28e5760d0d6 100644 --- a/library/core/src/iter/adapters/by_ref_sized.rs +++ b/library/core/src/iter/adapters/by_ref_sized.rs @@ -26,7 +26,7 @@ impl Iterator for ByRefSized<'_, I> { } #[inline] - fn advance_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_by(&mut self, n: usize) -> usize { I::advance_by(self.0, n) } @@ -62,7 +62,7 @@ impl DoubleEndedIterator for ByRefSized<'_, I> { } #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_back_by(&mut self, n: usize) -> usize { I::advance_back_by(self.0, n) } diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs index d4b2640e81dc9..965a33de1cdb2 100644 --- a/library/core/src/iter/adapters/chain.rs +++ b/library/core/src/iter/adapters/chain.rs @@ -95,38 +95,33 @@ where } #[inline] - fn advance_by(&mut self, n: usize) -> Result<(), usize> { - let mut rem = n; - + fn advance_by(&mut self, mut n: usize) -> usize { if let Some(ref mut a) = self.a { - match a.advance_by(rem) { - Ok(()) => return Ok(()), - Err(k) => rem -= k, + n = a.advance_by(n); + if n == 0 { + return n; } self.a = None; } if let Some(ref mut b) = self.b { - match b.advance_by(rem) { - Ok(()) => return Ok(()), - Err(k) => rem -= k, - } + n = b.advance_by(n); // we don't fuse the second iterator } - if rem == 0 { Ok(()) } else { Err(n - rem) } + n } #[inline] fn nth(&mut self, mut n: usize) -> Option { if let Some(ref mut a) = self.a { - match a.advance_by(n) { - Ok(()) => match a.next() { - None => n = 0, + n = match a.advance_by(n) { + 0 => match a.next() { + None => 0, x => return x, }, - Err(k) => n -= k, - } + k => k, + }; self.a = None; } @@ -186,38 +181,33 @@ where } #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { - let mut rem = n; - + fn advance_back_by(&mut self, mut n: usize) -> usize { if let Some(ref mut b) = self.b { - match b.advance_back_by(rem) { - Ok(()) => return Ok(()), - Err(k) => rem -= k, + n = b.advance_back_by(n); + if n == 0 { + return n; } self.b = None; } if let Some(ref mut a) = self.a { - match a.advance_back_by(rem) { - Ok(()) => return Ok(()), - Err(k) => rem -= k, - } + n = a.advance_back_by(n); // we don't fuse the second iterator } - if rem == 0 { Ok(()) } else { Err(n - rem) } + n } #[inline] fn nth_back(&mut self, mut n: usize) -> Option { if let Some(ref mut b) = self.b { - match b.advance_back_by(n) { - Ok(()) => match b.next_back() { - None => n = 0, + n = match b.advance_back_by(n) { + 0 => match b.next_back() { + None => 0, x => return x, }, - Err(k) => n -= k, - } + k => k, + }; self.b = None; } diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs index a076ab925e366..7533de588db5f 100644 --- a/library/core/src/iter/adapters/copied.rs +++ b/library/core/src/iter/adapters/copied.rs @@ -89,7 +89,7 @@ where } #[inline] - fn advance_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_by(&mut self, n: usize) -> usize { self.it.advance_by(n) } @@ -130,7 +130,7 @@ where } #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_back_by(&mut self, n: usize) -> usize { self.it.advance_back_by(n) } } diff --git a/library/core/src/iter/adapters/cycle.rs b/library/core/src/iter/adapters/cycle.rs index 02b5939072ef0..2d1fcf667bf20 100644 --- a/library/core/src/iter/adapters/cycle.rs +++ b/library/core/src/iter/adapters/cycle.rs @@ -81,23 +81,22 @@ where #[inline] #[rustc_inherit_overflow_checks] - fn advance_by(&mut self, n: usize) -> Result<(), usize> { - let mut rem = n; - match self.iter.advance_by(rem) { - ret @ Ok(_) => return ret, - Err(advanced) => rem -= advanced, + fn advance_by(&mut self, n: usize) -> usize { + let mut n = self.iter.advance_by(n); + if n == 0 { + return n; } - while rem > 0 { + while n > 0 { self.iter = self.orig.clone(); - match self.iter.advance_by(rem) { - ret @ Ok(_) => return ret, - Err(0) => return Err(n - rem), - Err(advanced) => rem -= advanced, + let rem = self.iter.advance_by(n); + if rem == n { + return n; } + n = rem; } - Ok(()) + 0 } // No `fold` override, because `fold` doesn't make much sense for `Cycle`, diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs index 8c32a35a12f86..30017d13a6c01 100644 --- a/library/core/src/iter/adapters/enumerate.rs +++ b/library/core/src/iter/adapters/enumerate.rs @@ -114,17 +114,10 @@ where #[inline] #[rustc_inherit_overflow_checks] - fn advance_by(&mut self, n: usize) -> Result<(), usize> { - match self.iter.advance_by(n) { - ret @ Ok(_) => { - self.count += n; - ret - } - ret @ Err(advanced) => { - self.count += advanced; - ret - } - } + fn advance_by(&mut self, n: usize) -> usize { + let n = self.iter.advance_by(n); + self.count += n; + n } #[rustc_inherit_overflow_checks] @@ -208,7 +201,7 @@ where } #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_back_by(&mut self, n: usize) -> usize { // we do not need to update the count since that only tallies the number of items // consumed from the front. consuming items from the back can never reduce that. self.iter.advance_back_by(n) diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index e4020c45f71bc..980c4bebc9718 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -75,7 +75,7 @@ where } #[inline] - fn advance_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_by(&mut self, n: usize) -> usize { self.inner.advance_by(n) } @@ -120,7 +120,7 @@ where } #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_back_by(&mut self, n: usize) -> usize { self.inner.advance_back_by(n) } } @@ -236,7 +236,7 @@ where } #[inline] - fn advance_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_by(&mut self, n: usize) -> usize { self.inner.advance_by(n) } @@ -281,7 +281,7 @@ where } #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_back_by(&mut self, n: usize) -> usize { self.inner.advance_back_by(n) } } @@ -552,19 +552,19 @@ where #[inline] #[rustc_inherit_overflow_checks] - fn advance_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_by(&mut self, n: usize) -> usize { #[inline] #[rustc_inherit_overflow_checks] fn advance(n: usize, iter: &mut U) -> ControlFlow<(), usize> { match iter.advance_by(n) { - Ok(()) => ControlFlow::Break(()), - Err(advanced) => ControlFlow::Continue(n - advanced), + 0 => ControlFlow::Break(()), + remaining => ControlFlow::Continue(remaining), } } match self.iter_try_fold(n, advance) { - ControlFlow::Continue(remaining) if remaining > 0 => Err(n - remaining), - _ => Ok(()), + ControlFlow::Continue(remaining) => remaining, + _ => 0, } } @@ -642,19 +642,19 @@ where #[inline] #[rustc_inherit_overflow_checks] - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_back_by(&mut self, n: usize) -> usize { #[inline] #[rustc_inherit_overflow_checks] fn advance(n: usize, iter: &mut U) -> ControlFlow<(), usize> { match iter.advance_back_by(n) { - Ok(()) => ControlFlow::Break(()), - Err(advanced) => ControlFlow::Continue(n - advanced), + 0 => ControlFlow::Break(()), + remaining => ControlFlow::Continue(remaining), } } match self.iter_try_rfold(n, advance) { - ControlFlow::Continue(remaining) if remaining > 0 => Err(n - remaining), - _ => Ok(()), + ControlFlow::Continue(remaining) => remaining, + _ => 0, } } } diff --git a/library/core/src/iter/adapters/rev.rs b/library/core/src/iter/adapters/rev.rs index 8ae6d96fde4cc..b64baf838a2e2 100644 --- a/library/core/src/iter/adapters/rev.rs +++ b/library/core/src/iter/adapters/rev.rs @@ -38,7 +38,7 @@ where } #[inline] - fn advance_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_by(&mut self, n: usize) -> usize { self.iter.advance_back_by(n) } @@ -83,7 +83,7 @@ where } #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_back_by(&mut self, n: usize) -> usize { self.iter.advance_by(n) } diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs index c6334880db57c..bb32e19b542f4 100644 --- a/library/core/src/iter/adapters/skip.rs +++ b/library/core/src/iter/adapters/skip.rs @@ -128,34 +128,21 @@ where #[inline] #[rustc_inherit_overflow_checks] - fn advance_by(&mut self, n: usize) -> Result<(), usize> { - let mut rem = n; - let step_one = self.n.saturating_add(rem); - - match self.iter.advance_by(step_one) { - Ok(_) => { - rem -= step_one - self.n; - self.n = 0; - } - Err(advanced) => { - let advanced_without_skip = advanced.saturating_sub(self.n); - self.n = self.n.saturating_sub(advanced); - return if n == 0 { Ok(()) } else { Err(advanced_without_skip) }; - } - } - - // step_one calculation may have saturated - if unlikely(rem > 0) { - return match self.iter.advance_by(rem) { - ret @ Ok(_) => ret, - Err(advanced) => { - rem -= advanced; - Err(n - rem) - } - }; + fn advance_by(&mut self, mut n: usize) -> usize { + let skip_inner = self.n; + let skip_and_advance = skip_inner.saturating_add(n); + + let remainder = self.iter.advance_by(skip_and_advance); + let advanced_inner = skip_and_advance - remainder; + n -= advanced_inner.saturating_sub(skip_inner); + self.n = self.n.saturating_sub(advanced_inner); + + // skip_and_advance may have saturated + if unlikely(remainder == 0 && n > 0) { + n = self.iter.advance_by(n); } - Ok(()) + n } } @@ -209,13 +196,13 @@ where impl_fold_via_try_fold! { rfold -> try_rfold } #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_back_by(&mut self, n: usize) -> usize { let min = crate::cmp::min(self.len(), n); - return match self.iter.advance_back_by(min) { - ret @ Ok(_) if n <= min => ret, - Ok(_) => Err(min), - _ => panic!("ExactSizeIterator contract violation"), + let rem = self.iter.advance_back_by(min); + if rem != 0 { + panic!("ExactSizeIterator contract violation"); }; + n - min } } diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs index d947c7b0e3013..12e2395fe680a 100644 --- a/library/core/src/iter/adapters/take.rs +++ b/library/core/src/iter/adapters/take.rs @@ -121,18 +121,12 @@ where #[inline] #[rustc_inherit_overflow_checks] - fn advance_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_by(&mut self, n: usize) -> usize { let min = self.n.min(n); - match self.iter.advance_by(min) { - Ok(_) => { - self.n -= min; - if min < n { Err(min) } else { Ok(()) } - } - ret @ Err(advanced) => { - self.n -= advanced; - ret - } - } + let rem = self.iter.advance_by(min); + let advanced = min - rem; + self.n -= advanced; + n - advanced } } @@ -223,7 +217,7 @@ where #[inline] #[rustc_inherit_overflow_checks] - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_back_by(&mut self, n: usize) -> usize { // The amount by which the inner iterator needs to be shortened for it to be // at most as long as the take() amount. let trim_inner = self.iter.len().saturating_sub(self.n); @@ -232,12 +226,11 @@ where // about having to advance more than usize::MAX here. let advance_by = trim_inner.saturating_add(n); - let advanced = match self.iter.advance_back_by(advance_by) { - Ok(_) => advance_by - trim_inner, - Err(advanced) => advanced - trim_inner, - }; - self.n -= advanced; - return if advanced < n { Err(advanced) } else { Ok(()) }; + let remainder = self.iter.advance_back_by(advance_by); + let advanced_by_inner = advance_by - remainder; + let advanced_by = advanced_by_inner - trim_inner; + self.n -= advanced_by; + n - advanced_by } } diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index f19636fba5d95..63c719f8b3a35 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -530,12 +530,12 @@ trait RangeIteratorImpl { // Iterator fn spec_next(&mut self) -> Option; fn spec_nth(&mut self, n: usize) -> Option; - fn spec_advance_by(&mut self, n: usize) -> Result<(), usize>; + fn spec_advance_by(&mut self, n: usize) -> usize; // DoubleEndedIterator fn spec_next_back(&mut self) -> Option; fn spec_nth_back(&mut self, n: usize) -> Option; - fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize>; + fn spec_advance_back_by(&mut self, n: usize) -> usize; } impl const RangeIteratorImpl for ops::Range { @@ -567,7 +567,7 @@ impl const RangeIteratorImpl for ops::Range } #[inline] - default fn spec_advance_by(&mut self, n: usize) -> Result<(), usize> { + default fn spec_advance_by(&mut self, n: usize) -> usize { let available = if self.start <= self.end { Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX) } else { @@ -579,7 +579,7 @@ impl const RangeIteratorImpl for ops::Range self.start = Step::forward_checked(self.start.clone(), taken).expect("`Step` invariants not upheld"); - if taken < n { Err(taken) } else { Ok(()) } + n - taken } #[inline] @@ -608,7 +608,7 @@ impl const RangeIteratorImpl for ops::Range } #[inline] - default fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize> { + default fn spec_advance_back_by(&mut self, n: usize) -> usize { let available = if self.start <= self.end { Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX) } else { @@ -620,7 +620,7 @@ impl const RangeIteratorImpl for ops::Range self.end = Step::backward_checked(self.end.clone(), taken).expect("`Step` invariants not upheld"); - if taken < n { Err(taken) } else { Ok(()) } + n - taken } } @@ -651,7 +651,7 @@ impl const RangeIteratorImpl for ops::R } #[inline] - fn spec_advance_by(&mut self, n: usize) -> Result<(), usize> { + fn spec_advance_by(&mut self, n: usize) -> usize { let available = if self.start <= self.end { Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX) } else { @@ -666,7 +666,7 @@ impl const RangeIteratorImpl for ops::R // Otherwise 0 is returned which always safe to use. self.start = unsafe { Step::forward_unchecked(self.start.clone(), taken) }; - if taken < n { Err(taken) } else { Ok(()) } + n - taken } #[inline] @@ -695,7 +695,7 @@ impl const RangeIteratorImpl for ops::R } #[inline] - fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize> { + fn spec_advance_back_by(&mut self, n: usize) -> usize { let available = if self.start <= self.end { Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX) } else { @@ -707,7 +707,7 @@ impl const RangeIteratorImpl for ops::R // SAFETY: same as the spec_advance_by() implementation self.end = unsafe { Step::backward_unchecked(self.end.clone(), taken) }; - if taken < n { Err(taken) } else { Ok(()) } + n - taken } } @@ -757,7 +757,7 @@ impl const Iterator for ops::Range { } #[inline] - fn advance_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_by(&mut self, n: usize) -> usize { self.spec_advance_by(n) } @@ -836,7 +836,7 @@ impl const DoubleEndedIterator for ops::Range< } #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_back_by(&mut self, n: usize) -> usize { self.spec_advance_back_by(n) } } diff --git a/library/core/src/iter/sources/repeat.rs b/library/core/src/iter/sources/repeat.rs index 733142ed01103..56a6d973705c1 100644 --- a/library/core/src/iter/sources/repeat.rs +++ b/library/core/src/iter/sources/repeat.rs @@ -80,10 +80,10 @@ impl Iterator for Repeat { } #[inline] - fn advance_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_by(&mut self, n: usize) -> usize { // Advancing an infinite iterator of a single element is a no-op. let _ = n; - Ok(()) + 0 } #[inline] @@ -109,10 +109,10 @@ impl DoubleEndedIterator for Repeat { } #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_back_by(&mut self, n: usize) -> usize { // Advancing an infinite iterator of a single element is a no-op. let _ = n; - Ok(()) + 0 } #[inline] diff --git a/library/core/src/iter/sources/repeat_n.rs b/library/core/src/iter/sources/repeat_n.rs index dc61d6065b8ed..918f2a36ed01d 100644 --- a/library/core/src/iter/sources/repeat_n.rs +++ b/library/core/src/iter/sources/repeat_n.rs @@ -137,7 +137,7 @@ impl Iterator for RepeatN { } #[inline] - fn advance_by(&mut self, skip: usize) -> Result<(), usize> { + fn advance_by(&mut self, skip: usize) -> usize { let len = self.count; if skip >= len { @@ -145,10 +145,10 @@ impl Iterator for RepeatN { } if skip > len { - Err(len) + skip - len } else { self.count = len - skip; - Ok(()) + 0 } } @@ -178,7 +178,7 @@ impl DoubleEndedIterator for RepeatN { } #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_back_by(&mut self, n: usize) -> usize { self.advance_by(n) } diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index 7a10dea500a96..06538d61aa0dc 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -100,10 +100,10 @@ pub trait DoubleEndedIterator: Iterator { /// eagerly skip `n` elements starting from the back by calling [`next_back`] up /// to `n` times until [`None`] is encountered. /// - /// `advance_back_by(n)` will return [`Ok(())`] if the iterator successfully advances by - /// `n` elements, or [`Err(k)`] if [`None`] is encountered, where `k` is the number of - /// elements the iterator is advanced by before running out of elements (i.e. the length - /// of the iterator). Note that `k` is always less than `n`. + /// `advance_back_by(n)` will return `0` if the iterator successfully advances by + /// `n` elements, or an usize `k` if [`None`] is encountered, where `k` is remaining number + /// of steps that could not be advanced because the iterator ran out. + /// Note that `k` is always less than `n`. /// /// Calling `advance_back_by(0)` can do meaningful work, for example [`Flatten`] can advance its /// outer iterator until it finds an inner iterator that is not empty, which then often @@ -123,24 +123,26 @@ pub trait DoubleEndedIterator: Iterator { /// let a = [3, 4, 5, 6]; /// let mut iter = a.iter(); /// - /// assert_eq!(iter.advance_back_by(2), Ok(())); + /// assert_eq!(iter.advance_back_by(2), 0); /// assert_eq!(iter.next_back(), Some(&4)); - /// assert_eq!(iter.advance_back_by(0), Ok(())); - /// assert_eq!(iter.advance_back_by(100), Err(1)); // only `&3` was skipped + /// assert_eq!(iter.advance_back_by(0), 0); + /// assert_eq!(iter.advance_back_by(100), 99); // only `&3` was skipped /// ``` /// /// [`Ok(())`]: Ok /// [`Err(k)`]: Err #[inline] #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> + fn advance_back_by(&mut self, n: usize) -> usize where Self::Item: ~const Destruct, { for i in 0..n { - self.next_back().ok_or(i)?; + if self.next_back().is_none() { + return n - i; + } } - Ok(()) + 0 } /// Returns the `n`th element from the end of the iterator. @@ -188,7 +190,9 @@ pub trait DoubleEndedIterator: Iterator { #[stable(feature = "iter_nth_back", since = "1.37.0")] #[rustc_do_not_const_check] fn nth_back(&mut self, n: usize) -> Option { - self.advance_back_by(n).ok()?; + if self.advance_back_by(n) > 0 { + return None; + } self.next_back() } @@ -374,7 +378,7 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I { fn next_back(&mut self) -> Option { (**self).next_back() } - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_back_by(&mut self, n: usize) -> usize { (**self).advance_back_by(n) } fn nth_back(&mut self, n: usize) -> Option { diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 16c9f668b8ea8..f2de040c63524 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -308,10 +308,10 @@ pub trait Iterator { /// This method will eagerly skip `n` elements by calling [`next`] up to `n` /// times until [`None`] is encountered. /// - /// `advance_by(n)` will return [`Ok(())`][Ok] if the iterator successfully advances by - /// `n` elements, or [`Err(k)`][Err] if [`None`] is encountered, where `k` is the number - /// of elements the iterator is advanced by before running out of elements (i.e. the - /// length of the iterator). Note that `k` is always less than `n`. + /// `advance_by(n)` will return `0` if the iterator successfully advances by + /// `n` elements, or an usize `k` if [`None`] is encountered, where `k` is remaining number + /// of steps that could not be advanced because the iterator ran out. + /// Note that `k` is always less than `n`. /// /// Calling `advance_by(0)` can do meaningful work, for example [`Flatten`] /// can advance its outer iterator until it finds an inner iterator that is not empty, which @@ -330,21 +330,23 @@ pub trait Iterator { /// let a = [1, 2, 3, 4]; /// let mut iter = a.iter(); /// - /// assert_eq!(iter.advance_by(2), Ok(())); + /// assert_eq!(iter.advance_by(2), 0); /// assert_eq!(iter.next(), Some(&3)); - /// assert_eq!(iter.advance_by(0), Ok(())); - /// assert_eq!(iter.advance_by(100), Err(1)); // only `&4` was skipped + /// assert_eq!(iter.advance_by(0), 0); + /// assert_eq!(iter.advance_by(100), 99); // only `&4` was skipped /// ``` #[inline] #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] - fn advance_by(&mut self, n: usize) -> Result<(), usize> + fn advance_by(&mut self, n: usize) -> usize where Self::Item: ~const Destruct, { for i in 0..n { - self.next().ok_or(i)?; + if self.next().is_none() { + return n - i; + } } - Ok(()) + 0 } /// Returns the `n`th element of the iterator. @@ -392,7 +394,9 @@ pub trait Iterator { where Self::Item: ~const Destruct, { - self.advance_by(n).ok()?; + if self.advance_by(n) > 0 { + return None; + } self.next() } @@ -4013,7 +4017,7 @@ impl Iterator for &mut I { fn size_hint(&self) -> (usize, Option) { (**self).size_hint() } - fn advance_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_by(&mut self, n: usize) -> usize { (**self).advance_by(n) } fn nth(&mut self, n: usize) -> Option { diff --git a/library/core/src/ops/index_range.rs b/library/core/src/ops/index_range.rs index 3e06776d2c6fa..744ec3b024528 100644 --- a/library/core/src/ops/index_range.rs +++ b/library/core/src/ops/index_range.rs @@ -132,10 +132,9 @@ impl Iterator for IndexRange { } #[inline] - fn advance_by(&mut self, n: usize) -> Result<(), usize> { - let original_len = self.len(); - self.take_prefix(n); - if n > original_len { Err(original_len) } else { Ok(()) } + fn advance_by(&mut self, n: usize) -> usize { + let taken = self.take_prefix(n); + n - taken.len() } } @@ -151,10 +150,9 @@ impl DoubleEndedIterator for IndexRange { } #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { - let original_len = self.len(); - self.take_suffix(n); - if n > original_len { Err(original_len) } else { Ok(()) } + fn advance_back_by(&mut self, n: usize) -> usize { + let taken = self.take_suffix(n); + n - taken.len() } } diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index a800da546b450..d3e9b9c2b225f 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -176,11 +176,11 @@ macro_rules! iterator { } #[inline] - fn advance_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_by(&mut self, n: usize) -> usize { let advance = cmp::min(len!(self), n); // SAFETY: By construction, `advance` does not exceed `self.len()`. unsafe { self.post_inc_start(advance) }; - if advance == n { Ok(()) } else { Err(advance) } + n - advance } #[inline] @@ -371,11 +371,11 @@ macro_rules! iterator { } #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + fn advance_back_by(&mut self, n: usize) -> usize { let advance = cmp::min(len!(self), n); // SAFETY: By construction, `advance` does not exceed `self.len()`. unsafe { self.pre_dec_end(advance) }; - if advance == n { Ok(()) } else { Err(advance) } + n - advance } } diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs index 5327e4f813925..9b90c77e151d4 100644 --- a/library/core/tests/array.rs +++ b/library/core/tests/array.rs @@ -1,4 +1,4 @@ -use core::array; +use core::{array, assert_eq}; use core::convert::TryFrom; use core::sync::atomic::{AtomicUsize, Ordering}; @@ -535,17 +535,17 @@ fn array_intoiter_advance_by() { let mut it = IntoIterator::into_iter(a); let r = it.advance_by(1); - assert_eq!(r, Ok(())); + assert_eq!(r, 0); assert_eq!(it.len(), 99); assert_eq!(counter.get(), 1); let r = it.advance_by(0); - assert_eq!(r, Ok(())); + assert_eq!(r, 0); assert_eq!(it.len(), 99); assert_eq!(counter.get(), 1); let r = it.advance_by(11); - assert_eq!(r, Ok(())); + assert_eq!(r, 0); assert_eq!(it.len(), 88); assert_eq!(counter.get(), 12); @@ -557,17 +557,17 @@ fn array_intoiter_advance_by() { assert_eq!(counter.get(), 13); let r = it.advance_by(123456); - assert_eq!(r, Err(87)); + assert_eq!(r, 123456 - 87); assert_eq!(it.len(), 0); assert_eq!(counter.get(), 100); let r = it.advance_by(0); - assert_eq!(r, Ok(())); + assert_eq!(r, 0); assert_eq!(it.len(), 0); assert_eq!(counter.get(), 100); let r = it.advance_by(10); - assert_eq!(r, Err(0)); + assert_eq!(r, 10); assert_eq!(it.len(), 0); assert_eq!(counter.get(), 100); } @@ -588,17 +588,17 @@ fn array_intoiter_advance_back_by() { let mut it = IntoIterator::into_iter(a); let r = it.advance_back_by(1); - assert_eq!(r, Ok(())); + assert_eq!(r, 0); assert_eq!(it.len(), 99); assert_eq!(counter.get(), 1); let r = it.advance_back_by(0); - assert_eq!(r, Ok(())); + assert_eq!(r, 0); assert_eq!(it.len(), 99); assert_eq!(counter.get(), 1); let r = it.advance_back_by(11); - assert_eq!(r, Ok(())); + assert_eq!(r, 0); assert_eq!(it.len(), 88); assert_eq!(counter.get(), 12); @@ -610,17 +610,17 @@ fn array_intoiter_advance_back_by() { assert_eq!(counter.get(), 13); let r = it.advance_back_by(123456); - assert_eq!(r, Err(87)); + assert_eq!(r, 123456 - 87); assert_eq!(it.len(), 0); assert_eq!(counter.get(), 100); let r = it.advance_back_by(0); - assert_eq!(r, Ok(())); + assert_eq!(r, 0); assert_eq!(it.len(), 0); assert_eq!(counter.get(), 100); let r = it.advance_back_by(10); - assert_eq!(r, Err(0)); + assert_eq!(r, 10); assert_eq!(it.len(), 0); assert_eq!(counter.get(), 100); } @@ -679,8 +679,8 @@ fn array_into_iter_fold() { let a = [1, 2, 3, 4, 5, 6]; let mut it = a.into_iter(); - it.advance_by(1).unwrap(); - it.advance_back_by(2).unwrap(); + assert_eq!(it.advance_by(1), 0); + assert_eq!(it.advance_back_by(2), 0); let s = it.fold(10, |a, b| 10 * a + b); assert_eq!(s, 10234); } @@ -695,8 +695,8 @@ fn array_into_iter_rfold() { let a = [1, 2, 3, 4, 5, 6]; let mut it = a.into_iter(); - it.advance_by(1).unwrap(); - it.advance_back_by(2).unwrap(); + assert_eq!(it.advance_by(1), 0); + assert_eq!(it.advance_back_by(2), 0); let s = it.rfold(10, |a, b| 10 * a + b); assert_eq!(s, 10432); } diff --git a/library/core/tests/iter/adapters/chain.rs b/library/core/tests/iter/adapters/chain.rs index f419f9cec12f8..4da9263d7ac32 100644 --- a/library/core/tests/iter/adapters/chain.rs +++ b/library/core/tests/iter/adapters/chain.rs @@ -31,28 +31,28 @@ fn test_iterator_chain_advance_by() { for i in 0..xs.len() { let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys)); - iter.advance_by(i).unwrap(); + assert_eq!(0, iter.advance_by(i)); assert_eq!(iter.next(), Some(&xs[i])); - assert_eq!(iter.advance_by(100), Err(len - i - 1)); - iter.advance_by(0).unwrap(); + assert_eq!(iter.advance_by(100), 100 - (len - i - 1)); + assert_eq!(0, iter.advance_by(0)); } for i in 0..ys.len() { let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys)); - iter.advance_by(xs.len() + i).unwrap(); + assert_eq!(iter.advance_by(xs.len() + i), 0); assert_eq!(iter.next(), Some(&ys[i])); - assert_eq!(iter.advance_by(100), Err(ys.len() - i - 1)); - iter.advance_by(0).unwrap(); + assert_eq!(iter.advance_by(100), 100 - (ys.len() - i - 1)); + assert_eq!(iter.advance_by(0), 0); } let mut iter = xs.iter().chain(ys); - iter.advance_by(len).unwrap(); + assert_eq!(iter.advance_by(len), 0); assert_eq!(iter.next(), None); - iter.advance_by(0).unwrap(); + assert_eq!(iter.advance_by(0), 0); let mut iter = xs.iter().chain(ys); - assert_eq!(iter.advance_by(len + 1), Err(len)); - iter.advance_by(0).unwrap(); + assert_eq!(iter.advance_by(len + 1), 1); + assert_eq!(iter.advance_by(0), 0); } test_chain(&[], &[]); @@ -68,28 +68,28 @@ fn test_iterator_chain_advance_back_by() { for i in 0..ys.len() { let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys)); - iter.advance_back_by(i).unwrap(); + assert_eq!(iter.advance_back_by(i), 0); assert_eq!(iter.next_back(), Some(&ys[ys.len() - i - 1])); - assert_eq!(iter.advance_back_by(100), Err(len - i - 1)); - iter.advance_back_by(0).unwrap(); + assert_eq!(iter.advance_back_by(100), 100 - (len - i - 1)); + assert_eq!(iter.advance_back_by(0), 0); } for i in 0..xs.len() { let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys)); - iter.advance_back_by(ys.len() + i).unwrap(); + assert_eq!(iter.advance_back_by(ys.len() + i), 0); assert_eq!(iter.next_back(), Some(&xs[xs.len() - i - 1])); - assert_eq!(iter.advance_back_by(100), Err(xs.len() - i - 1)); - iter.advance_back_by(0).unwrap(); + assert_eq!(iter.advance_back_by(100), 100 - (xs.len() - i - 1)); + assert_eq!(iter.advance_back_by(0), 0); } let mut iter = xs.iter().chain(ys); - iter.advance_back_by(len).unwrap(); + assert_eq!(iter.advance_back_by(len), 0); assert_eq!(iter.next_back(), None); - iter.advance_back_by(0).unwrap(); + assert_eq!(iter.advance_back_by(0), 0); let mut iter = xs.iter().chain(ys); - assert_eq!(iter.advance_back_by(len + 1), Err(len)); - iter.advance_back_by(0).unwrap(); + assert_eq!(iter.advance_back_by(len + 1), 1); + assert_eq!(iter.advance_back_by(0), 0); } test_chain(&[], &[]); diff --git a/library/core/tests/iter/adapters/flatten.rs b/library/core/tests/iter/adapters/flatten.rs index 690fd0c21974b..e8e06a8ca40f5 100644 --- a/library/core/tests/iter/adapters/flatten.rs +++ b/library/core/tests/iter/adapters/flatten.rs @@ -1,3 +1,4 @@ +use core::assert_eq; use super::*; use core::iter::*; @@ -61,19 +62,19 @@ fn test_flatten_try_folds() { fn test_flatten_advance_by() { let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten(); - it.advance_by(5).unwrap(); + assert_eq!(it.advance_by(5), 0); assert_eq!(it.next(), Some(5)); - it.advance_by(9).unwrap(); + assert_eq!(it.advance_by(9), 0); assert_eq!(it.next(), Some(15)); - it.advance_back_by(4).unwrap(); + assert_eq!(it.advance_back_by(4), 0); assert_eq!(it.next_back(), Some(35)); - it.advance_back_by(9).unwrap(); + assert_eq!(it.advance_back_by(9), 0); assert_eq!(it.next_back(), Some(25)); - assert_eq!(it.advance_by(usize::MAX), Err(9)); - assert_eq!(it.advance_back_by(usize::MAX), Err(0)); - it.advance_by(0).unwrap(); - it.advance_back_by(0).unwrap(); + assert_eq!(it.advance_by(usize::MAX), usize::MAX - 9); + assert_eq!(it.advance_back_by(usize::MAX), usize::MAX); + assert_eq!(it.advance_by(0), 0); + assert_eq!(it.advance_back_by(0), 0); assert_eq!(it.size_hint(), (0, Some(0))); } @@ -174,19 +175,19 @@ fn test_flatten_count() { let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten(); assert_eq!(it.clone().count(), 40); - it.advance_by(5).unwrap(); + assert_eq!(it.advance_by(5), 0); assert_eq!(it.clone().count(), 35); - it.advance_back_by(5).unwrap(); + assert_eq!(it.advance_back_by(5), 0); assert_eq!(it.clone().count(), 30); - it.advance_by(10).unwrap(); + assert_eq!(it.advance_by(10), 0); assert_eq!(it.clone().count(), 20); - it.advance_back_by(8).unwrap(); + assert_eq!(it.advance_back_by(8), 0); assert_eq!(it.clone().count(), 12); - it.advance_by(4).unwrap(); + assert_eq!(it.advance_by(4), 0); assert_eq!(it.clone().count(), 8); - it.advance_back_by(5).unwrap(); + assert_eq!(it.advance_back_by(5), 0); assert_eq!(it.clone().count(), 3); - it.advance_by(3).unwrap(); + assert_eq!(it.advance_by(3), 0); assert_eq!(it.clone().count(), 0); } @@ -195,18 +196,18 @@ fn test_flatten_last() { let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten(); assert_eq!(it.clone().last(), Some(39)); - it.advance_by(5).unwrap(); // 5..40 + assert_eq!(it.advance_by(5), 0); // 5..40 assert_eq!(it.clone().last(), Some(39)); - it.advance_back_by(5).unwrap(); // 5..35 + assert_eq!(it.advance_back_by(5), 0); // 5..35 assert_eq!(it.clone().last(), Some(34)); - it.advance_by(10).unwrap(); // 15..35 + assert_eq!(it.advance_by(10), 0); // 15..35 assert_eq!(it.clone().last(), Some(34)); - it.advance_back_by(8).unwrap(); // 15..27 + assert_eq!(it.advance_back_by(8), 0); // 15..27 assert_eq!(it.clone().last(), Some(26)); - it.advance_by(4).unwrap(); // 19..27 + assert_eq!(it.advance_by(4), 0); // 19..27 assert_eq!(it.clone().last(), Some(26)); - it.advance_back_by(5).unwrap(); // 19..22 + assert_eq!(it.advance_back_by(5), 0); // 19..22 assert_eq!(it.clone().last(), Some(21)); - it.advance_by(3).unwrap(); // 22..22 + assert_eq!(it.advance_by(3), 0); // 22..22 assert_eq!(it.clone().last(), None); } diff --git a/library/core/tests/iter/adapters/skip.rs b/library/core/tests/iter/adapters/skip.rs index 754641834e803..134dead4ad3e9 100644 --- a/library/core/tests/iter/adapters/skip.rs +++ b/library/core/tests/iter/adapters/skip.rs @@ -73,13 +73,16 @@ fn test_iterator_skip_nth() { #[test] fn test_skip_advance_by() { - assert_eq!((0..0).skip(10).advance_by(0), Ok(())); - assert_eq!((0..0).skip(10).advance_by(1), Err(0)); - assert_eq!((0u128..(usize::MAX as u128) + 1).skip(usize::MAX).advance_by(usize::MAX), Err(1)); - assert_eq!((0u128..u128::MAX).skip(usize::MAX).advance_by(1), Ok(())); - - assert_eq!((0..2).skip(1).advance_back_by(10), Err(1)); - assert_eq!((0..0).skip(1).advance_back_by(0), Ok(())); + assert_eq!((0..0).skip(10).advance_by(0), 0); + assert_eq!((0..0).skip(10).advance_by(1), 1); + assert_eq!( + (0u128..(usize::MAX as u128) + 1).skip(usize::MAX - 10).advance_by(usize::MAX - 5), + usize::MAX - 16 + ); + assert_eq!((0u128..u128::MAX).skip(usize::MAX - 10).advance_by(20), 0); + + assert_eq!((0..2).skip(1).advance_back_by(10), 9); + assert_eq!((0..0).skip(1).advance_back_by(0), 0); } #[test] diff --git a/library/core/tests/iter/adapters/take.rs b/library/core/tests/iter/adapters/take.rs index 3e26b43a2ede5..8ba7f0c5f8a95 100644 --- a/library/core/tests/iter/adapters/take.rs +++ b/library/core/tests/iter/adapters/take.rs @@ -76,23 +76,23 @@ fn test_iterator_take_nth_back() { #[test] fn test_take_advance_by() { let mut take = (0..10).take(3); - assert_eq!(take.advance_by(2), Ok(())); + assert_eq!(take.advance_by(2), 0); assert_eq!(take.next(), Some(2)); - assert_eq!(take.advance_by(1), Err(0)); + assert_eq!(take.advance_by(1), 1); - assert_eq!((0..0).take(10).advance_by(0), Ok(())); - assert_eq!((0..0).take(10).advance_by(1), Err(0)); - assert_eq!((0..10).take(4).advance_by(5), Err(4)); + assert_eq!((0..0).take(10).advance_by(0), 0); + assert_eq!((0..0).take(10).advance_by(1), 1); + assert_eq!((0..10).take(4).advance_by(5), 1); let mut take = (0..10).take(3); - assert_eq!(take.advance_back_by(2), Ok(())); + assert_eq!(take.advance_back_by(2), 0); assert_eq!(take.next(), Some(0)); - assert_eq!(take.advance_back_by(1), Err(0)); + assert_eq!(take.advance_back_by(1), 1); - assert_eq!((0..2).take(1).advance_back_by(10), Err(1)); - assert_eq!((0..0).take(1).advance_back_by(1), Err(0)); - assert_eq!((0..0).take(1).advance_back_by(0), Ok(())); - assert_eq!((0..usize::MAX).take(100).advance_back_by(usize::MAX), Err(100)); + assert_eq!((0..2).take(1).advance_back_by(10), 9); + assert_eq!((0..0).take(1).advance_back_by(1), 1); + assert_eq!((0..0).take(1).advance_back_by(0), 0); + assert_eq!((0..usize::MAX).take(100).advance_back_by(usize::MAX), usize::MAX - 100); } #[test] diff --git a/library/core/tests/iter/range.rs b/library/core/tests/iter/range.rs index 0f91ffe2dfc94..d375dbf2ce441 100644 --- a/library/core/tests/iter/range.rs +++ b/library/core/tests/iter/range.rs @@ -287,25 +287,25 @@ fn test_range_step() { #[test] fn test_range_advance_by() { let mut r = 0..usize::MAX; - r.advance_by(0).unwrap(); - r.advance_back_by(0).unwrap(); + assert_eq!(0, r.advance_by(0)); + assert_eq!(0, r.advance_back_by(0)); assert_eq!(r.len(), usize::MAX); - r.advance_by(1).unwrap(); - r.advance_back_by(1).unwrap(); + assert_eq!(0, r.advance_by(1)); + assert_eq!(0, r.advance_back_by(1)); assert_eq!((r.start, r.end), (1, usize::MAX - 1)); - assert_eq!(r.advance_by(usize::MAX), Err(usize::MAX - 2)); + assert_eq!(2, r.advance_by(usize::MAX)); - r.advance_by(0).unwrap(); - r.advance_back_by(0).unwrap(); + assert_eq!(0, r.advance_by(0)); + assert_eq!(0, r.advance_back_by(0)); let mut r = 0u128..u128::MAX; - r.advance_by(usize::MAX).unwrap(); - r.advance_back_by(usize::MAX).unwrap(); + assert_eq!(0, r.advance_by(usize::MAX)); + assert_eq!(0, r.advance_back_by(usize::MAX)); assert_eq!((r.start, r.end), (0u128 + usize::MAX as u128, u128::MAX - usize::MAX as u128)); } diff --git a/library/core/tests/iter/traits/iterator.rs b/library/core/tests/iter/traits/iterator.rs index 62566a9502d04..4b446727c9a10 100644 --- a/library/core/tests/iter/traits/iterator.rs +++ b/library/core/tests/iter/traits/iterator.rs @@ -148,13 +148,13 @@ fn test_iterator_advance_by() { for i in 0..v.len() { let mut iter = v.iter(); - assert_eq!(iter.advance_by(i), Ok(())); + assert_eq!(iter.advance_by(i), 0); assert_eq!(iter.next().unwrap(), &v[i]); - assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i)); + assert_eq!(iter.advance_by(100), 100 - (v.len() - 1 - i)); } - assert_eq!(v.iter().advance_by(v.len()), Ok(())); - assert_eq!(v.iter().advance_by(100), Err(v.len())); + assert_eq!(v.iter().advance_by(v.len()), 0); + assert_eq!(v.iter().advance_by(100), 100 - v.len()); } #[test] @@ -163,13 +163,13 @@ fn test_iterator_advance_back_by() { for i in 0..v.len() { let mut iter = v.iter(); - assert_eq!(iter.advance_back_by(i), Ok(())); + assert_eq!(iter.advance_back_by(i), 0); assert_eq!(iter.next_back().unwrap(), &v[v.len() - 1 - i]); - assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i)); + assert_eq!(iter.advance_back_by(100), 100 - (v.len() - 1 - i)); } - assert_eq!(v.iter().advance_back_by(v.len()), Ok(())); - assert_eq!(v.iter().advance_back_by(100), Err(v.len())); + assert_eq!(v.iter().advance_back_by(v.len()), 0); + assert_eq!(v.iter().advance_back_by(100), 100 - v.len()); } #[test] @@ -178,13 +178,13 @@ fn test_iterator_rev_advance_back_by() { for i in 0..v.len() { let mut iter = v.iter().rev(); - assert_eq!(iter.advance_back_by(i), Ok(())); + assert_eq!(iter.advance_back_by(i), 0); assert_eq!(iter.next_back().unwrap(), &v[i]); - assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i)); + assert_eq!(iter.advance_back_by(100), 100 - (v.len() - 1 - i)); } - assert_eq!(v.iter().rev().advance_back_by(v.len()), Ok(())); - assert_eq!(v.iter().rev().advance_back_by(100), Err(v.len())); + assert_eq!(v.iter().rev().advance_back_by(v.len()), 0); + assert_eq!(v.iter().rev().advance_back_by(100), 100 - v.len()); } #[test] @@ -422,13 +422,13 @@ fn test_iterator_rev_advance_by() { for i in 0..v.len() { let mut iter = v.iter().rev(); - assert_eq!(iter.advance_by(i), Ok(())); + assert_eq!(iter.advance_by(i), 0); assert_eq!(iter.next().unwrap(), &v[v.len() - 1 - i]); - assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i)); + assert_eq!(iter.advance_by(100), 100 - (v.len() - 1 - i)); } - assert_eq!(v.iter().rev().advance_by(v.len()), Ok(())); - assert_eq!(v.iter().rev().advance_by(100), Err(v.len())); + assert_eq!(v.iter().rev().advance_by(v.len()), 0); + assert_eq!(v.iter().rev().advance_by(100), 100 - v.len()); } #[test] diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index 39559cdbb5ea9..a675d9e13fbb1 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -142,20 +142,20 @@ fn test_iterator_advance_by() { for i in 0..=v.len() { let mut iter = v.iter(); - iter.advance_by(i).unwrap(); + assert_eq!(iter.advance_by(i), 0); assert_eq!(iter.as_slice(), &v[i..]); } let mut iter = v.iter(); - assert_eq!(iter.advance_by(v.len() + 1), Err(v.len())); + assert_eq!(iter.advance_by(v.len() + 1), 1); assert_eq!(iter.as_slice(), &[]); let mut iter = v.iter(); - iter.advance_by(3).unwrap(); + assert_eq!(iter.advance_by(3), 0); assert_eq!(iter.as_slice(), &v[3..]); - iter.advance_by(2).unwrap(); + assert_eq!(iter.advance_by(2), 0); assert_eq!(iter.as_slice(), &[]); - iter.advance_by(0).unwrap(); + assert_eq!(iter.advance_by(0), 0); } #[test] @@ -164,20 +164,20 @@ fn test_iterator_advance_back_by() { for i in 0..=v.len() { let mut iter = v.iter(); - iter.advance_back_by(i).unwrap(); + assert_eq!(iter.advance_back_by(i), 0); assert_eq!(iter.as_slice(), &v[..v.len() - i]); } let mut iter = v.iter(); - assert_eq!(iter.advance_back_by(v.len() + 1), Err(v.len())); + assert_eq!(iter.advance_back_by(v.len() + 1), 1); assert_eq!(iter.as_slice(), &[]); let mut iter = v.iter(); - iter.advance_back_by(3).unwrap(); + assert_eq!(iter.advance_back_by(3), 0); assert_eq!(iter.as_slice(), &v[..v.len() - 3]); - iter.advance_back_by(2).unwrap(); + assert_eq!(iter.advance_back_by(2), 0); assert_eq!(iter.as_slice(), &[]); - iter.advance_back_by(0).unwrap(); + assert_eq!(iter.advance_back_by(0), 0); } #[test] From e29b27b4a4c6b6fc80e38d2747c8076a59475c03 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Mon, 13 Mar 2023 20:07:53 +0100 Subject: [PATCH 2/4] replace advance_by returning usize with Result<(), NonZeroUsize> --- .../src/collections/vec_deque/into_iter.rs | 15 ++++--- .../alloc/src/collections/vec_deque/iter.rs | 26 ++++++----- .../src/collections/vec_deque/iter_mut.rs | 27 ++++++----- library/alloc/src/vec/into_iter.rs | 9 ++-- library/alloc/tests/vec.rs | 19 ++++---- library/core/src/array/iter.rs | 9 ++-- .../core/src/iter/adapters/by_ref_sized.rs | 5 ++- library/core/src/iter/adapters/chain.rs | 37 +++++++-------- library/core/src/iter/adapters/copied.rs | 5 ++- library/core/src/iter/adapters/cycle.rs | 23 +++++----- library/core/src/iter/adapters/enumerate.rs | 15 ++++--- library/core/src/iter/adapters/flatten.rs | 29 ++++++------ library/core/src/iter/adapters/rev.rs | 5 ++- library/core/src/iter/adapters/skip.rs | 23 ++++++---- library/core/src/iter/adapters/take.rs | 19 +++++--- library/core/src/iter/range.rs | 25 ++++++----- library/core/src/iter/sources/repeat.rs | 9 ++-- library/core/src/iter/sources/repeat_n.rs | 10 +++-- library/core/src/iter/traits/double_ended.rs | 19 ++++---- library/core/src/iter/traits/iterator.rs | 21 ++++----- library/core/src/ops/index_range.rs | 9 ++-- library/core/src/slice/iter/macros.rs | 8 ++-- library/core/tests/array.rs | 33 +++++++------- library/core/tests/iter/adapters/chain.rs | 41 ++++++++--------- library/core/tests/iter/adapters/enumerate.rs | 15 +++++++ library/core/tests/iter/adapters/flatten.rs | 45 ++++++++++--------- library/core/tests/iter/adapters/skip.rs | 13 +++--- library/core/tests/iter/adapters/take.rs | 23 +++++----- library/core/tests/iter/range.rs | 19 ++++---- library/core/tests/iter/traits/iterator.rs | 34 +++++++------- library/core/tests/slice.rs | 21 ++++----- 31 files changed, 340 insertions(+), 271 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/into_iter.rs b/library/alloc/src/collections/vec_deque/into_iter.rs index 8ba963b790d89..c277c62ad14d9 100644 --- a/library/alloc/src/collections/vec_deque/into_iter.rs +++ b/library/alloc/src/collections/vec_deque/into_iter.rs @@ -1,4 +1,5 @@ use core::iter::{FusedIterator, TrustedLen}; +use core::num::NonZeroUsize; use core::{array, fmt, mem::MaybeUninit, ops::Try, ptr}; use crate::alloc::{Allocator, Global}; @@ -54,15 +55,16 @@ impl Iterator for IntoIter { } #[inline] - fn advance_by(&mut self, n: usize) -> usize { - if self.inner.len < n { + fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { + let rem = if self.inner.len < n { let len = self.inner.len; self.inner.clear(); len - n } else { self.inner.drain(..n); 0 - } + }; + NonZeroUsize::new(rem).map_or(Ok(()), Err) } #[inline] @@ -182,15 +184,16 @@ impl DoubleEndedIterator for IntoIter { } #[inline] - fn advance_back_by(&mut self, n: usize) -> usize { + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { let len = self.inner.len; - if len >= n { + let rem = if len >= n { self.inner.truncate(len - n); 0 } else { self.inner.clear(); n - len - } + }; + NonZeroUsize::new(rem).map_or(Ok(()), Err) } fn try_rfold(&mut self, mut init: B, mut f: F) -> R diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs index 5b91c1635f0d6..646a2a991e701 100644 --- a/library/alloc/src/collections/vec_deque/iter.rs +++ b/library/alloc/src/collections/vec_deque/iter.rs @@ -1,4 +1,5 @@ use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce}; +use core::num::NonZeroUsize; use core::ops::Try; use core::{fmt, mem, slice}; @@ -55,13 +56,15 @@ impl<'a, T> Iterator for Iter<'a, T> { } } - fn advance_by(&mut self, n: usize) -> usize { + fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { let remaining = self.i1.advance_by(n); - if remaining == 0 { - return 0; + match remaining { + Ok(()) => return Ok(()), + Err(n) => { + mem::swap(&mut self.i1, &mut self.i2); + self.i1.advance_by(n.get()) + } } - mem::swap(&mut self.i1, &mut self.i2); - self.i1.advance_by(remaining) } #[inline] @@ -125,13 +128,14 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { } } - fn advance_back_by(&mut self, n: usize) -> usize { - let remaining = self.i2.advance_back_by(n); - if remaining == 0 { - return 0; + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { + match self.i2.advance_back_by(n) { + Ok(()) => return Ok(()), + Err(n) => { + mem::swap(&mut self.i1, &mut self.i2); + self.i2.advance_back_by(n.get()) + } } - mem::swap(&mut self.i1, &mut self.i2); - self.i2.advance_back_by(remaining) } fn rfold(self, accum: Acc, mut f: F) -> Acc diff --git a/library/alloc/src/collections/vec_deque/iter_mut.rs b/library/alloc/src/collections/vec_deque/iter_mut.rs index 848cb3649c852..7defbb1090ffd 100644 --- a/library/alloc/src/collections/vec_deque/iter_mut.rs +++ b/library/alloc/src/collections/vec_deque/iter_mut.rs @@ -1,4 +1,5 @@ use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce}; +use core::num::NonZeroUsize; use core::ops::Try; use core::{fmt, mem, slice}; @@ -47,13 +48,14 @@ impl<'a, T> Iterator for IterMut<'a, T> { } } - fn advance_by(&mut self, n: usize) -> usize { - let remaining = self.i1.advance_by(n); - if remaining == 0 { - return 0; + fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { + match self.i1.advance_by(n) { + Ok(()) => return Ok(()), + Err(remaining) => { + mem::swap(&mut self.i1, &mut self.i2); + self.i1.advance_by(remaining.get()) + } } - mem::swap(&mut self.i1, &mut self.i2); - self.i1.advance_by(remaining) } #[inline] @@ -117,13 +119,14 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { } } - fn advance_back_by(&mut self, n: usize) -> usize { - let remaining = self.i2.advance_back_by(n); - if remaining == 0 { - return 0; + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { + match self.i2.advance_back_by(n) { + Ok(()) => return Ok(()), + Err(remaining) => { + mem::swap(&mut self.i1, &mut self.i2); + self.i2.advance_back_by(remaining.get()) + } } - mem::swap(&mut self.i1, &mut self.i2); - self.i2.advance_back_by(remaining) } fn rfold(self, accum: Acc, mut f: F) -> Acc diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 504ca4333bed5..6a05f70e43747 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -11,6 +11,7 @@ use core::iter::{ }; use core::marker::PhantomData; use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties}; +use core::num::NonZeroUsize; #[cfg(not(no_global_oom_handling))] use core::ops::Deref; use core::ptr::{self, NonNull}; @@ -213,7 +214,7 @@ impl Iterator for IntoIter { } #[inline] - fn advance_by(&mut self, n: usize) -> usize { + fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { let step_size = self.len().min(n); let to_drop = ptr::slice_from_raw_parts_mut(self.ptr as *mut T, step_size); if T::IS_ZST { @@ -227,7 +228,7 @@ impl Iterator for IntoIter { unsafe { ptr::drop_in_place(to_drop); } - n - step_size + NonZeroUsize::new(n - step_size).map_or(Ok(()), Err) } #[inline] @@ -310,7 +311,7 @@ impl DoubleEndedIterator for IntoIter { } #[inline] - fn advance_back_by(&mut self, n: usize) -> usize { + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { let step_size = self.len().min(n); if T::IS_ZST { // SAFETY: same as for advance_by() @@ -324,7 +325,7 @@ impl DoubleEndedIterator for IntoIter { unsafe { ptr::drop_in_place(to_drop); } - n - step_size + NonZeroUsize::new(n - step_size).map_or(Ok(()), Err) } } diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index e00af189fbfed..3ee16f04e92f5 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -1,6 +1,7 @@ use core::alloc::{Allocator, Layout}; use core::assert_eq; use core::iter::IntoIterator; +use core::num::NonZeroUsize; use core::ptr::NonNull; use std::alloc::System; use std::assert_matches::assert_matches; @@ -1064,20 +1065,20 @@ fn test_into_iter_leak() { #[test] fn test_into_iter_advance_by() { let mut i = vec![1, 2, 3, 4, 5].into_iter(); - assert_eq!(i.advance_by(0), 0); - assert_eq!(i.advance_back_by(0), 0); + assert_eq!(i.advance_by(0), Ok(())); + assert_eq!(i.advance_back_by(0), Ok(())); assert_eq!(i.as_slice(), [1, 2, 3, 4, 5]); - assert_eq!(i.advance_by(1), 0); - assert_eq!(i.advance_back_by(1), 0); + assert_eq!(i.advance_by(1), Ok(())); + assert_eq!(i.advance_back_by(1), Ok(())); assert_eq!(i.as_slice(), [2, 3, 4]); - assert_eq!(i.advance_back_by(usize::MAX), usize::MAX - 3); + assert_eq!(i.advance_back_by(usize::MAX), Err(NonZeroUsize::new(usize::MAX - 3).unwrap())); - assert_eq!(i.advance_by(usize::MAX), usize::MAX); + assert_eq!(i.advance_by(usize::MAX), Err(NonZeroUsize::new(usize::MAX).unwrap())); - assert_eq!(i.advance_by(0), 0); - assert_eq!(i.advance_back_by(0), 0); + assert_eq!(i.advance_by(0), Ok(())); + assert_eq!(i.advance_back_by(0), Ok(())); assert_eq!(i.len(), 0); } @@ -1125,7 +1126,7 @@ fn test_into_iter_zst() { for _ in vec![C; 5].into_iter().rev() {} let mut it = vec![C, C].into_iter(); - assert_eq!(it.advance_by(1), 0); + assert_eq!(it.advance_by(1), Ok(())); drop(it); let mut it = vec![C, C].into_iter(); diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index 2d853dd6684ec..73e2c2cfbbef6 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -1,5 +1,6 @@ //! Defines the `IntoIter` owned iterator for arrays. +use crate::num::NonZeroUsize; use crate::{ fmt, iter::{self, ExactSizeIterator, FusedIterator, TrustedLen}, @@ -284,7 +285,7 @@ impl Iterator for IntoIter { self.next_back() } - fn advance_by(&mut self, n: usize) -> usize { + fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { // This also moves the start, which marks them as conceptually "dropped", // so if anything goes bad then our drop impl won't double-free them. let range_to_drop = self.alive.take_prefix(n); @@ -296,7 +297,7 @@ impl Iterator for IntoIter { ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice)); } - remaining + NonZeroUsize::new(remaining).map_or(Ok(()), Err) } } @@ -333,7 +334,7 @@ impl DoubleEndedIterator for IntoIter { }) } - fn advance_back_by(&mut self, n: usize) -> usize { + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { // This also moves the end, which marks them as conceptually "dropped", // so if anything goes bad then our drop impl won't double-free them. let range_to_drop = self.alive.take_suffix(n); @@ -345,7 +346,7 @@ impl DoubleEndedIterator for IntoIter { ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice)); } - remaining + NonZeroUsize::new(remaining).map_or(Ok(()), Err) } } diff --git a/library/core/src/iter/adapters/by_ref_sized.rs b/library/core/src/iter/adapters/by_ref_sized.rs index ff28e5760d0d6..4e0e19ddc7822 100644 --- a/library/core/src/iter/adapters/by_ref_sized.rs +++ b/library/core/src/iter/adapters/by_ref_sized.rs @@ -1,3 +1,4 @@ +use crate::num::NonZeroUsize; use crate::ops::{NeverShortCircuit, Try}; /// Like `Iterator::by_ref`, but requiring `Sized` so it can forward generics. @@ -26,7 +27,7 @@ impl Iterator for ByRefSized<'_, I> { } #[inline] - fn advance_by(&mut self, n: usize) -> usize { + fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { I::advance_by(self.0, n) } @@ -62,7 +63,7 @@ impl DoubleEndedIterator for ByRefSized<'_, I> { } #[inline] - fn advance_back_by(&mut self, n: usize) -> usize { + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { I::advance_back_by(self.0, n) } diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs index 965a33de1cdb2..2046b70c9c6b4 100644 --- a/library/core/src/iter/adapters/chain.rs +++ b/library/core/src/iter/adapters/chain.rs @@ -1,4 +1,5 @@ use crate::iter::{DoubleEndedIterator, FusedIterator, Iterator, TrustedLen}; +use crate::num::NonZeroUsize; use crate::ops::Try; /// An iterator that links two iterators together, in a chain. @@ -95,32 +96,32 @@ where } #[inline] - fn advance_by(&mut self, mut n: usize) -> usize { + fn advance_by(&mut self, mut n: usize) -> Result<(), NonZeroUsize> { if let Some(ref mut a) = self.a { - n = a.advance_by(n); - if n == 0 { - return n; - } + n = match a.advance_by(n) { + Ok(()) => return Ok(()), + Err(k) => k.get(), + }; self.a = None; } if let Some(ref mut b) = self.b { - n = b.advance_by(n); + return b.advance_by(n); // we don't fuse the second iterator } - n + NonZeroUsize::new(n).map_or(Ok(()), Err) } #[inline] fn nth(&mut self, mut n: usize) -> Option { if let Some(ref mut a) = self.a { n = match a.advance_by(n) { - 0 => match a.next() { + Ok(()) => match a.next() { None => 0, x => return x, }, - k => k, + Err(k) => k.get(), }; self.a = None; @@ -181,32 +182,32 @@ where } #[inline] - fn advance_back_by(&mut self, mut n: usize) -> usize { + fn advance_back_by(&mut self, mut n: usize) -> Result<(), NonZeroUsize> { if let Some(ref mut b) = self.b { - n = b.advance_back_by(n); - if n == 0 { - return n; - } + n = match b.advance_back_by(n) { + Ok(()) => return Ok(()), + Err(k) => k.get(), + }; self.b = None; } if let Some(ref mut a) = self.a { - n = a.advance_back_by(n); + return a.advance_back_by(n); // we don't fuse the second iterator } - n + NonZeroUsize::new(n).map_or(Ok(()), Err) } #[inline] fn nth_back(&mut self, mut n: usize) -> Option { if let Some(ref mut b) = self.b { n = match b.advance_back_by(n) { - 0 => match b.next_back() { + Ok(()) => match b.next_back() { None => 0, x => return x, }, - k => k, + Err(k) => k.get(), }; self.b = None; diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs index 7533de588db5f..2289025d0a780 100644 --- a/library/core/src/iter/adapters/copied.rs +++ b/library/core/src/iter/adapters/copied.rs @@ -4,6 +4,7 @@ use crate::iter::adapters::{ use crate::iter::{FusedIterator, TrustedLen}; use crate::mem::MaybeUninit; use crate::mem::SizedTypeProperties; +use crate::num::NonZeroUsize; use crate::ops::Try; use crate::{array, ptr}; @@ -89,7 +90,7 @@ where } #[inline] - fn advance_by(&mut self, n: usize) -> usize { + fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { self.it.advance_by(n) } @@ -130,7 +131,7 @@ where } #[inline] - fn advance_back_by(&mut self, n: usize) -> usize { + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { self.it.advance_back_by(n) } } diff --git a/library/core/src/iter/adapters/cycle.rs b/library/core/src/iter/adapters/cycle.rs index 2d1fcf667bf20..51bd09b6effe1 100644 --- a/library/core/src/iter/adapters/cycle.rs +++ b/library/core/src/iter/adapters/cycle.rs @@ -1,3 +1,4 @@ +use crate::num::NonZeroUsize; use crate::{iter::FusedIterator, ops::Try}; /// An iterator that repeats endlessly. @@ -81,22 +82,22 @@ where #[inline] #[rustc_inherit_overflow_checks] - fn advance_by(&mut self, n: usize) -> usize { - let mut n = self.iter.advance_by(n); - if n == 0 { - return n; - } + fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { + let mut n = match self.iter.advance_by(n) { + Ok(()) => return Ok(()), + Err(rem) => rem.get(), + }; while n > 0 { self.iter = self.orig.clone(); - let rem = self.iter.advance_by(n); - if rem == n { - return n; - } - n = rem; + n = match self.iter.advance_by(n) { + Ok(()) => return Ok(()), + e @ Err(rem) if rem.get() == n => return e, + Err(rem) => rem.get(), + }; } - 0 + NonZeroUsize::new(n).map_or(Ok(()), Err) } // No `fold` override, because `fold` doesn't make much sense for `Cycle`, diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs index 30017d13a6c01..479ea6d83c74e 100644 --- a/library/core/src/iter/adapters/enumerate.rs +++ b/library/core/src/iter/adapters/enumerate.rs @@ -2,6 +2,7 @@ use crate::iter::adapters::{ zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce, }; use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen}; +use crate::num::NonZeroUsize; use crate::ops::Try; /// An iterator that yields the current count and the element during iteration. @@ -114,10 +115,14 @@ where #[inline] #[rustc_inherit_overflow_checks] - fn advance_by(&mut self, n: usize) -> usize { - let n = self.iter.advance_by(n); - self.count += n; - n + fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { + let remaining = self.iter.advance_by(n); + let advanced = match remaining { + Ok(()) => n, + Err(rem) => n - rem.get(), + }; + self.count += advanced; + remaining } #[rustc_inherit_overflow_checks] @@ -201,7 +206,7 @@ where } #[inline] - fn advance_back_by(&mut self, n: usize) -> usize { + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { // we do not need to update the count since that only tallies the number of items // consumed from the front. consuming items from the back can never reduce that. self.iter.advance_back_by(n) diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 980c4bebc9718..e0308e3360f45 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -1,5 +1,6 @@ use crate::fmt; use crate::iter::{DoubleEndedIterator, Fuse, FusedIterator, Iterator, Map, TrustedLen}; +use crate::num::NonZeroUsize; use crate::ops::{ControlFlow, Try}; /// An iterator that maps each element to an iterator, and yields the elements @@ -75,7 +76,7 @@ where } #[inline] - fn advance_by(&mut self, n: usize) -> usize { + fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { self.inner.advance_by(n) } @@ -120,7 +121,7 @@ where } #[inline] - fn advance_back_by(&mut self, n: usize) -> usize { + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { self.inner.advance_back_by(n) } } @@ -236,7 +237,7 @@ where } #[inline] - fn advance_by(&mut self, n: usize) -> usize { + fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { self.inner.advance_by(n) } @@ -281,7 +282,7 @@ where } #[inline] - fn advance_back_by(&mut self, n: usize) -> usize { + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { self.inner.advance_back_by(n) } } @@ -552,19 +553,19 @@ where #[inline] #[rustc_inherit_overflow_checks] - fn advance_by(&mut self, n: usize) -> usize { + fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { #[inline] #[rustc_inherit_overflow_checks] fn advance(n: usize, iter: &mut U) -> ControlFlow<(), usize> { match iter.advance_by(n) { - 0 => ControlFlow::Break(()), - remaining => ControlFlow::Continue(remaining), + Ok(()) => ControlFlow::Break(()), + Err(remaining) => ControlFlow::Continue(remaining.get()), } } match self.iter_try_fold(n, advance) { - ControlFlow::Continue(remaining) => remaining, - _ => 0, + ControlFlow::Continue(remaining) => NonZeroUsize::new(remaining).map_or(Ok(()), Err), + _ => Ok(()), } } @@ -642,19 +643,19 @@ where #[inline] #[rustc_inherit_overflow_checks] - fn advance_back_by(&mut self, n: usize) -> usize { + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { #[inline] #[rustc_inherit_overflow_checks] fn advance(n: usize, iter: &mut U) -> ControlFlow<(), usize> { match iter.advance_back_by(n) { - 0 => ControlFlow::Break(()), - remaining => ControlFlow::Continue(remaining), + Ok(()) => ControlFlow::Break(()), + Err(remaining) => ControlFlow::Continue(remaining.get()), } } match self.iter_try_rfold(n, advance) { - ControlFlow::Continue(remaining) => remaining, - _ => 0, + ControlFlow::Continue(remaining) => NonZeroUsize::new(remaining).map_or(Ok(()), Err), + _ => Ok(()), } } } diff --git a/library/core/src/iter/adapters/rev.rs b/library/core/src/iter/adapters/rev.rs index b64baf838a2e2..1d882087f695d 100644 --- a/library/core/src/iter/adapters/rev.rs +++ b/library/core/src/iter/adapters/rev.rs @@ -1,4 +1,5 @@ use crate::iter::{FusedIterator, TrustedLen}; +use crate::num::NonZeroUsize; use crate::ops::Try; /// A double-ended iterator with the direction inverted. @@ -38,7 +39,7 @@ where } #[inline] - fn advance_by(&mut self, n: usize) -> usize { + fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { self.iter.advance_back_by(n) } @@ -83,7 +84,7 @@ where } #[inline] - fn advance_back_by(&mut self, n: usize) -> usize { + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { self.iter.advance_by(n) } diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs index bb32e19b542f4..306338bc7cca0 100644 --- a/library/core/src/iter/adapters/skip.rs +++ b/library/core/src/iter/adapters/skip.rs @@ -1,5 +1,6 @@ use crate::intrinsics::unlikely; use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; +use crate::num::NonZeroUsize; use crate::ops::{ControlFlow, Try}; /// An iterator that skips over `n` elements of `iter`. @@ -128,21 +129,27 @@ where #[inline] #[rustc_inherit_overflow_checks] - fn advance_by(&mut self, mut n: usize) -> usize { + fn advance_by(&mut self, mut n: usize) -> Result<(), NonZeroUsize> { let skip_inner = self.n; let skip_and_advance = skip_inner.saturating_add(n); - let remainder = self.iter.advance_by(skip_and_advance); + let remainder = match self.iter.advance_by(skip_and_advance) { + Ok(()) => 0, + Err(n) => n.get(), + }; let advanced_inner = skip_and_advance - remainder; n -= advanced_inner.saturating_sub(skip_inner); self.n = self.n.saturating_sub(advanced_inner); // skip_and_advance may have saturated if unlikely(remainder == 0 && n > 0) { - n = self.iter.advance_by(n); + n = match self.iter.advance_by(n) { + Ok(()) => 0, + Err(n) => n.get(), + } } - n + NonZeroUsize::new(n).map_or(Ok(()), Err) } } @@ -196,13 +203,11 @@ where impl_fold_via_try_fold! { rfold -> try_rfold } #[inline] - fn advance_back_by(&mut self, n: usize) -> usize { + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { let min = crate::cmp::min(self.len(), n); let rem = self.iter.advance_back_by(min); - if rem != 0 { - panic!("ExactSizeIterator contract violation"); - }; - n - min + assert!(rem.is_ok(), "ExactSizeIterator contract violation"); + NonZeroUsize::new(n - min).map_or(Ok(()), Err) } } diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs index 12e2395fe680a..ce18bffe7146f 100644 --- a/library/core/src/iter/adapters/take.rs +++ b/library/core/src/iter/adapters/take.rs @@ -1,5 +1,6 @@ use crate::cmp; use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen}; +use crate::num::NonZeroUsize; use crate::ops::{ControlFlow, Try}; /// An iterator that only iterates over the first `n` iterations of `iter`. @@ -121,12 +122,15 @@ where #[inline] #[rustc_inherit_overflow_checks] - fn advance_by(&mut self, n: usize) -> usize { + fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { let min = self.n.min(n); - let rem = self.iter.advance_by(min); + let rem = match self.iter.advance_by(min) { + Ok(()) => 0, + Err(rem) => rem.get(), + }; let advanced = min - rem; self.n -= advanced; - n - advanced + NonZeroUsize::new(n - advanced).map_or(Ok(()), Err) } } @@ -217,7 +221,7 @@ where #[inline] #[rustc_inherit_overflow_checks] - fn advance_back_by(&mut self, n: usize) -> usize { + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { // The amount by which the inner iterator needs to be shortened for it to be // at most as long as the take() amount. let trim_inner = self.iter.len().saturating_sub(self.n); @@ -226,11 +230,14 @@ where // about having to advance more than usize::MAX here. let advance_by = trim_inner.saturating_add(n); - let remainder = self.iter.advance_back_by(advance_by); + let remainder = match self.iter.advance_back_by(advance_by) { + Ok(()) => 0, + Err(rem) => rem.get(), + }; let advanced_by_inner = advance_by - remainder; let advanced_by = advanced_by_inner - trim_inner; self.n -= advanced_by; - n - advanced_by + NonZeroUsize::new(n - advanced_by).map_or(Ok(()), Err) } } diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 63c719f8b3a35..1cd71193bd772 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -1,6 +1,7 @@ use crate::convert::TryFrom; use crate::marker::Destruct; use crate::mem; +use crate::num::NonZeroUsize; use crate::ops::{self, Try}; use super::{ @@ -530,12 +531,12 @@ trait RangeIteratorImpl { // Iterator fn spec_next(&mut self) -> Option; fn spec_nth(&mut self, n: usize) -> Option; - fn spec_advance_by(&mut self, n: usize) -> usize; + fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize>; // DoubleEndedIterator fn spec_next_back(&mut self) -> Option; fn spec_nth_back(&mut self, n: usize) -> Option; - fn spec_advance_back_by(&mut self, n: usize) -> usize; + fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize>; } impl const RangeIteratorImpl for ops::Range { @@ -567,7 +568,7 @@ impl const RangeIteratorImpl for ops::Range } #[inline] - default fn spec_advance_by(&mut self, n: usize) -> usize { + default fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { let available = if self.start <= self.end { Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX) } else { @@ -579,7 +580,7 @@ impl const RangeIteratorImpl for ops::Range self.start = Step::forward_checked(self.start.clone(), taken).expect("`Step` invariants not upheld"); - n - taken + NonZeroUsize::new(n - taken).map_or(Ok(()), Err) } #[inline] @@ -608,7 +609,7 @@ impl const RangeIteratorImpl for ops::Range } #[inline] - default fn spec_advance_back_by(&mut self, n: usize) -> usize { + default fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { let available = if self.start <= self.end { Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX) } else { @@ -620,7 +621,7 @@ impl const RangeIteratorImpl for ops::Range self.end = Step::backward_checked(self.end.clone(), taken).expect("`Step` invariants not upheld"); - n - taken + NonZeroUsize::new(n - taken).map_or(Ok(()), Err) } } @@ -651,7 +652,7 @@ impl const RangeIteratorImpl for ops::R } #[inline] - fn spec_advance_by(&mut self, n: usize) -> usize { + fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { let available = if self.start <= self.end { Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX) } else { @@ -666,7 +667,7 @@ impl const RangeIteratorImpl for ops::R // Otherwise 0 is returned which always safe to use. self.start = unsafe { Step::forward_unchecked(self.start.clone(), taken) }; - n - taken + NonZeroUsize::new(n - taken).map_or(Ok(()), Err) } #[inline] @@ -695,7 +696,7 @@ impl const RangeIteratorImpl for ops::R } #[inline] - fn spec_advance_back_by(&mut self, n: usize) -> usize { + fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { let available = if self.start <= self.end { Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX) } else { @@ -707,7 +708,7 @@ impl const RangeIteratorImpl for ops::R // SAFETY: same as the spec_advance_by() implementation self.end = unsafe { Step::backward_unchecked(self.end.clone(), taken) }; - n - taken + NonZeroUsize::new(n - taken).map_or(Ok(()), Err) } } @@ -757,7 +758,7 @@ impl const Iterator for ops::Range { } #[inline] - fn advance_by(&mut self, n: usize) -> usize { + fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { self.spec_advance_by(n) } @@ -836,7 +837,7 @@ impl const DoubleEndedIterator for ops::Range< } #[inline] - fn advance_back_by(&mut self, n: usize) -> usize { + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { self.spec_advance_back_by(n) } } diff --git a/library/core/src/iter/sources/repeat.rs b/library/core/src/iter/sources/repeat.rs index 56a6d973705c1..67051f6e97bdd 100644 --- a/library/core/src/iter/sources/repeat.rs +++ b/library/core/src/iter/sources/repeat.rs @@ -1,4 +1,5 @@ use crate::iter::{FusedIterator, TrustedLen}; +use crate::num::NonZeroUsize; /// Creates a new iterator that endlessly repeats a single element. /// @@ -80,10 +81,10 @@ impl Iterator for Repeat { } #[inline] - fn advance_by(&mut self, n: usize) -> usize { + fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { // Advancing an infinite iterator of a single element is a no-op. let _ = n; - 0 + Ok(()) } #[inline] @@ -109,10 +110,10 @@ impl DoubleEndedIterator for Repeat { } #[inline] - fn advance_back_by(&mut self, n: usize) -> usize { + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { // Advancing an infinite iterator of a single element is a no-op. let _ = n; - 0 + Ok(()) } #[inline] diff --git a/library/core/src/iter/sources/repeat_n.rs b/library/core/src/iter/sources/repeat_n.rs index 918f2a36ed01d..0b0445850bf52 100644 --- a/library/core/src/iter/sources/repeat_n.rs +++ b/library/core/src/iter/sources/repeat_n.rs @@ -1,5 +1,6 @@ use crate::iter::{FusedIterator, TrustedLen}; use crate::mem::ManuallyDrop; +use crate::num::NonZeroUsize; /// Creates a new iterator that repeats a single element a given number of times. /// @@ -137,7 +138,7 @@ impl Iterator for RepeatN { } #[inline] - fn advance_by(&mut self, skip: usize) -> usize { + fn advance_by(&mut self, skip: usize) -> Result<(), NonZeroUsize> { let len = self.count; if skip >= len { @@ -145,10 +146,11 @@ impl Iterator for RepeatN { } if skip > len { - skip - len + // SAFETY: we just checked that the difference is positive + Err(unsafe { NonZeroUsize::new_unchecked(skip - len) }) } else { self.count = len - skip; - 0 + Ok(()) } } @@ -178,7 +180,7 @@ impl DoubleEndedIterator for RepeatN { } #[inline] - fn advance_back_by(&mut self, n: usize) -> usize { + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { self.advance_by(n) } diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index 06538d61aa0dc..182b365b030ae 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -1,4 +1,5 @@ use crate::marker::Destruct; +use crate::num::NonZeroUsize; use crate::ops::{ControlFlow, Try}; /// An iterator able to yield elements from both ends. @@ -120,29 +121,31 @@ pub trait DoubleEndedIterator: Iterator { /// ``` /// #![feature(iter_advance_by)] /// + /// use std::num::NonZeroUsize; /// let a = [3, 4, 5, 6]; /// let mut iter = a.iter(); /// - /// assert_eq!(iter.advance_back_by(2), 0); + /// assert_eq!(iter.advance_back_by(2), Ok(())); /// assert_eq!(iter.next_back(), Some(&4)); - /// assert_eq!(iter.advance_back_by(0), 0); - /// assert_eq!(iter.advance_back_by(100), 99); // only `&3` was skipped + /// assert_eq!(iter.advance_back_by(0), Ok(())); + /// assert_eq!(iter.advance_back_by(100), Err(NonZeroUsize::new(99).unwrap())); // only `&3` was skipped /// ``` /// /// [`Ok(())`]: Ok /// [`Err(k)`]: Err #[inline] #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] - fn advance_back_by(&mut self, n: usize) -> usize + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> where Self::Item: ~const Destruct, { for i in 0..n { if self.next_back().is_none() { - return n - i; + // SAFETY: `i` is always less than `n`. + return Err(unsafe { NonZeroUsize::new_unchecked(n - i) }); } } - 0 + Ok(()) } /// Returns the `n`th element from the end of the iterator. @@ -190,7 +193,7 @@ pub trait DoubleEndedIterator: Iterator { #[stable(feature = "iter_nth_back", since = "1.37.0")] #[rustc_do_not_const_check] fn nth_back(&mut self, n: usize) -> Option { - if self.advance_back_by(n) > 0 { + if self.advance_back_by(n).is_err() { return None; } self.next_back() @@ -378,7 +381,7 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I { fn next_back(&mut self) -> Option { (**self).next_back() } - fn advance_back_by(&mut self, n: usize) -> usize { + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { (**self).advance_back_by(n) } fn nth_back(&mut self, n: usize) -> Option { diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index f2de040c63524..5a1ee80f7968d 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1,6 +1,7 @@ use crate::array; use crate::cmp::{self, Ordering}; use crate::marker::Destruct; +use crate::num::NonZeroUsize; use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try}; use super::super::try_process; @@ -327,26 +328,28 @@ pub trait Iterator { /// ``` /// #![feature(iter_advance_by)] /// + /// use std::num::NonZeroUsize; /// let a = [1, 2, 3, 4]; /// let mut iter = a.iter(); /// - /// assert_eq!(iter.advance_by(2), 0); + /// assert_eq!(iter.advance_by(2), Ok(())); /// assert_eq!(iter.next(), Some(&3)); - /// assert_eq!(iter.advance_by(0), 0); - /// assert_eq!(iter.advance_by(100), 99); // only `&4` was skipped + /// assert_eq!(iter.advance_by(0), Ok(())); + /// assert_eq!(iter.advance_by(100), Err(NonZeroUsize::new(99).unwrap())); // only `&4` was skipped /// ``` #[inline] #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] - fn advance_by(&mut self, n: usize) -> usize + fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> where Self::Item: ~const Destruct, { for i in 0..n { if self.next().is_none() { - return n - i; + // SAFETY: `i` is always less than `n`. + return Err(unsafe { NonZeroUsize::new_unchecked(n - i) }); } } - 0 + Ok(()) } /// Returns the `n`th element of the iterator. @@ -394,9 +397,7 @@ pub trait Iterator { where Self::Item: ~const Destruct, { - if self.advance_by(n) > 0 { - return None; - } + self.advance_by(n).ok()?; self.next() } @@ -4017,7 +4018,7 @@ impl Iterator for &mut I { fn size_hint(&self) -> (usize, Option) { (**self).size_hint() } - fn advance_by(&mut self, n: usize) -> usize { + fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { (**self).advance_by(n) } fn nth(&mut self, n: usize) -> Option { diff --git a/library/core/src/ops/index_range.rs b/library/core/src/ops/index_range.rs index 744ec3b024528..265022a394e88 100644 --- a/library/core/src/ops/index_range.rs +++ b/library/core/src/ops/index_range.rs @@ -1,5 +1,6 @@ use crate::intrinsics::{assert_unsafe_precondition, unchecked_add, unchecked_sub}; use crate::iter::{FusedIterator, TrustedLen}; +use crate::num::NonZeroUsize; /// Like a `Range`, but with a safety invariant that `start <= end`. /// @@ -132,9 +133,9 @@ impl Iterator for IndexRange { } #[inline] - fn advance_by(&mut self, n: usize) -> usize { + fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { let taken = self.take_prefix(n); - n - taken.len() + NonZeroUsize::new(n - taken.len()).map_or(Ok(()), Err) } } @@ -150,9 +151,9 @@ impl DoubleEndedIterator for IndexRange { } #[inline] - fn advance_back_by(&mut self, n: usize) -> usize { + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { let taken = self.take_suffix(n); - n - taken.len() + NonZeroUsize::new(n - taken.len()).map_or(Ok(()), Err) } } diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index d3e9b9c2b225f..b73e35f1e9138 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -176,11 +176,11 @@ macro_rules! iterator { } #[inline] - fn advance_by(&mut self, n: usize) -> usize { + fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { let advance = cmp::min(len!(self), n); // SAFETY: By construction, `advance` does not exceed `self.len()`. unsafe { self.post_inc_start(advance) }; - n - advance + NonZeroUsize::new(n - advance).map_or(Ok(()), Err) } #[inline] @@ -371,11 +371,11 @@ macro_rules! iterator { } #[inline] - fn advance_back_by(&mut self, n: usize) -> usize { + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { let advance = cmp::min(len!(self), n); // SAFETY: By construction, `advance` does not exceed `self.len()`. unsafe { self.pre_dec_end(advance) }; - n - advance + NonZeroUsize::new(n - advance).map_or(Ok(()), Err) } } diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs index 9b90c77e151d4..0869644c040f5 100644 --- a/library/core/tests/array.rs +++ b/library/core/tests/array.rs @@ -1,5 +1,6 @@ use core::{array, assert_eq}; use core::convert::TryFrom; +use core::num::NonZeroUsize; use core::sync::atomic::{AtomicUsize, Ordering}; #[test] @@ -535,17 +536,17 @@ fn array_intoiter_advance_by() { let mut it = IntoIterator::into_iter(a); let r = it.advance_by(1); - assert_eq!(r, 0); + assert_eq!(r, Ok(())); assert_eq!(it.len(), 99); assert_eq!(counter.get(), 1); let r = it.advance_by(0); - assert_eq!(r, 0); + assert_eq!(r, Ok(())); assert_eq!(it.len(), 99); assert_eq!(counter.get(), 1); let r = it.advance_by(11); - assert_eq!(r, 0); + assert_eq!(r, Ok(())); assert_eq!(it.len(), 88); assert_eq!(counter.get(), 12); @@ -557,17 +558,17 @@ fn array_intoiter_advance_by() { assert_eq!(counter.get(), 13); let r = it.advance_by(123456); - assert_eq!(r, 123456 - 87); + assert_eq!(r, Err(NonZeroUsize::new(123456 - 87).unwrap())); assert_eq!(it.len(), 0); assert_eq!(counter.get(), 100); let r = it.advance_by(0); - assert_eq!(r, 0); + assert_eq!(r, Ok(())); assert_eq!(it.len(), 0); assert_eq!(counter.get(), 100); let r = it.advance_by(10); - assert_eq!(r, 10); + assert_eq!(r, Err(NonZeroUsize::new(10).unwrap())); assert_eq!(it.len(), 0); assert_eq!(counter.get(), 100); } @@ -588,17 +589,17 @@ fn array_intoiter_advance_back_by() { let mut it = IntoIterator::into_iter(a); let r = it.advance_back_by(1); - assert_eq!(r, 0); + assert_eq!(r, Ok(())); assert_eq!(it.len(), 99); assert_eq!(counter.get(), 1); let r = it.advance_back_by(0); - assert_eq!(r, 0); + assert_eq!(r, Ok(())); assert_eq!(it.len(), 99); assert_eq!(counter.get(), 1); let r = it.advance_back_by(11); - assert_eq!(r, 0); + assert_eq!(r, Ok(())); assert_eq!(it.len(), 88); assert_eq!(counter.get(), 12); @@ -610,17 +611,17 @@ fn array_intoiter_advance_back_by() { assert_eq!(counter.get(), 13); let r = it.advance_back_by(123456); - assert_eq!(r, 123456 - 87); + assert_eq!(r, Err(NonZeroUsize::new(123456 - 87).unwrap())); assert_eq!(it.len(), 0); assert_eq!(counter.get(), 100); let r = it.advance_back_by(0); - assert_eq!(r, 0); + assert_eq!(r, Ok(())); assert_eq!(it.len(), 0); assert_eq!(counter.get(), 100); let r = it.advance_back_by(10); - assert_eq!(r, 10); + assert_eq!(r, Err(NonZeroUsize::new(10).unwrap())); assert_eq!(it.len(), 0); assert_eq!(counter.get(), 100); } @@ -679,8 +680,8 @@ fn array_into_iter_fold() { let a = [1, 2, 3, 4, 5, 6]; let mut it = a.into_iter(); - assert_eq!(it.advance_by(1), 0); - assert_eq!(it.advance_back_by(2), 0); + assert_eq!(it.advance_by(1), Ok(())); + assert_eq!(it.advance_back_by(2), Ok(())); let s = it.fold(10, |a, b| 10 * a + b); assert_eq!(s, 10234); } @@ -695,8 +696,8 @@ fn array_into_iter_rfold() { let a = [1, 2, 3, 4, 5, 6]; let mut it = a.into_iter(); - assert_eq!(it.advance_by(1), 0); - assert_eq!(it.advance_back_by(2), 0); + assert_eq!(it.advance_by(1), Ok(())); + assert_eq!(it.advance_back_by(2), Ok(())); let s = it.rfold(10, |a, b| 10 * a + b); assert_eq!(s, 10432); } diff --git a/library/core/tests/iter/adapters/chain.rs b/library/core/tests/iter/adapters/chain.rs index 4da9263d7ac32..175a1b638e1a1 100644 --- a/library/core/tests/iter/adapters/chain.rs +++ b/library/core/tests/iter/adapters/chain.rs @@ -1,5 +1,6 @@ use super::*; use core::iter::*; +use core::num::NonZeroUsize; #[test] fn test_iterator_chain() { @@ -31,28 +32,28 @@ fn test_iterator_chain_advance_by() { for i in 0..xs.len() { let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys)); - assert_eq!(0, iter.advance_by(i)); + assert_eq!(iter.advance_by(i), Ok(())); assert_eq!(iter.next(), Some(&xs[i])); - assert_eq!(iter.advance_by(100), 100 - (len - i - 1)); - assert_eq!(0, iter.advance_by(0)); + assert_eq!(iter.advance_by(100), Err(NonZeroUsize::new(100 - (len - i - 1)).unwrap())); + assert_eq!(iter.advance_by(0), Ok(())); } for i in 0..ys.len() { let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys)); - assert_eq!(iter.advance_by(xs.len() + i), 0); + assert_eq!(iter.advance_by(xs.len() + i), Ok(())); assert_eq!(iter.next(), Some(&ys[i])); - assert_eq!(iter.advance_by(100), 100 - (ys.len() - i - 1)); - assert_eq!(iter.advance_by(0), 0); + assert_eq!(iter.advance_by(100), Err(NonZeroUsize::new(100 - (ys.len() - i - 1)).unwrap())); + assert_eq!(iter.advance_by(0), Ok(())); } let mut iter = xs.iter().chain(ys); - assert_eq!(iter.advance_by(len), 0); + assert_eq!(iter.advance_by(len), Ok(())); assert_eq!(iter.next(), None); - assert_eq!(iter.advance_by(0), 0); + assert_eq!(iter.advance_by(0), Ok(())); let mut iter = xs.iter().chain(ys); - assert_eq!(iter.advance_by(len + 1), 1); - assert_eq!(iter.advance_by(0), 0); + assert_eq!(iter.advance_by(len + 1), Err(NonZeroUsize::new(1).unwrap())); + assert_eq!(iter.advance_by(0), Ok(())); } test_chain(&[], &[]); @@ -68,28 +69,28 @@ fn test_iterator_chain_advance_back_by() { for i in 0..ys.len() { let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys)); - assert_eq!(iter.advance_back_by(i), 0); + assert_eq!(iter.advance_back_by(i), Ok(())); assert_eq!(iter.next_back(), Some(&ys[ys.len() - i - 1])); - assert_eq!(iter.advance_back_by(100), 100 - (len - i - 1)); - assert_eq!(iter.advance_back_by(0), 0); + assert_eq!(iter.advance_back_by(100), Err(NonZeroUsize::new(100 - (len - i - 1)).unwrap())); + assert_eq!(iter.advance_back_by(0), Ok(())); } for i in 0..xs.len() { let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys)); - assert_eq!(iter.advance_back_by(ys.len() + i), 0); + assert_eq!(iter.advance_back_by(ys.len() + i), Ok(())); assert_eq!(iter.next_back(), Some(&xs[xs.len() - i - 1])); - assert_eq!(iter.advance_back_by(100), 100 - (xs.len() - i - 1)); - assert_eq!(iter.advance_back_by(0), 0); + assert_eq!(iter.advance_back_by(100), Err(NonZeroUsize::new(100 - (xs.len() - i - 1)).unwrap())); + assert_eq!(iter.advance_back_by(0), Ok(())); } let mut iter = xs.iter().chain(ys); - assert_eq!(iter.advance_back_by(len), 0); + assert_eq!(iter.advance_back_by(len), Ok(())); assert_eq!(iter.next_back(), None); - assert_eq!(iter.advance_back_by(0), 0); + assert_eq!(iter.advance_back_by(0), Ok(())); let mut iter = xs.iter().chain(ys); - assert_eq!(iter.advance_back_by(len + 1), 1); - assert_eq!(iter.advance_back_by(0), 0); + assert_eq!(iter.advance_back_by(len + 1), Err(NonZeroUsize::new(1).unwrap())); + assert_eq!(iter.advance_back_by(0), Ok(())); } test_chain(&[], &[]); diff --git a/library/core/tests/iter/adapters/enumerate.rs b/library/core/tests/iter/adapters/enumerate.rs index 0e60338784797..ff57973a62a4b 100644 --- a/library/core/tests/iter/adapters/enumerate.rs +++ b/library/core/tests/iter/adapters/enumerate.rs @@ -1,4 +1,5 @@ use core::iter::*; +use core::num::NonZeroUsize; #[test] fn test_iterator_enumerate() { @@ -55,6 +56,20 @@ fn test_iterator_enumerate_count() { assert_eq!(xs.iter().enumerate().count(), 6); } +#[test] +fn test_iterator_enumerate_advance_by() { + let xs = [0, 1, 2, 3, 4, 5]; + let mut it = xs.iter().enumerate(); + assert_eq!(it.advance_by(0), Ok(())); + assert_eq!(it.next(), Some((0, &0))); + assert_eq!(it.advance_by(1), Ok(())); + assert_eq!(it.next(), Some((2, &2))); + assert_eq!(it.advance_by(2), Ok(())); + assert_eq!(it.next(), Some((5, &5))); + assert_eq!(it.advance_by(1), Err(NonZeroUsize::new(1).unwrap())); + assert_eq!(it.next(), None); +} + #[test] fn test_iterator_enumerate_fold() { let xs = [0, 1, 2, 3, 4, 5]; diff --git a/library/core/tests/iter/adapters/flatten.rs b/library/core/tests/iter/adapters/flatten.rs index e8e06a8ca40f5..91809c9e5fd5d 100644 --- a/library/core/tests/iter/adapters/flatten.rs +++ b/library/core/tests/iter/adapters/flatten.rs @@ -1,6 +1,7 @@ use core::assert_eq; use super::*; use core::iter::*; +use core::num::NonZeroUsize; #[test] fn test_iterator_flatten() { @@ -62,19 +63,19 @@ fn test_flatten_try_folds() { fn test_flatten_advance_by() { let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten(); - assert_eq!(it.advance_by(5), 0); + assert_eq!(it.advance_by(5), Ok(())); assert_eq!(it.next(), Some(5)); - assert_eq!(it.advance_by(9), 0); + assert_eq!(it.advance_by(9), Ok(())); assert_eq!(it.next(), Some(15)); - assert_eq!(it.advance_back_by(4), 0); + assert_eq!(it.advance_back_by(4), Ok(())); assert_eq!(it.next_back(), Some(35)); - assert_eq!(it.advance_back_by(9), 0); + assert_eq!(it.advance_back_by(9), Ok(())); assert_eq!(it.next_back(), Some(25)); - assert_eq!(it.advance_by(usize::MAX), usize::MAX - 9); - assert_eq!(it.advance_back_by(usize::MAX), usize::MAX); - assert_eq!(it.advance_by(0), 0); - assert_eq!(it.advance_back_by(0), 0); + assert_eq!(it.advance_by(usize::MAX), Err(NonZeroUsize::new(usize::MAX - 9).unwrap())); + assert_eq!(it.advance_back_by(usize::MAX), Err(NonZeroUsize::new(usize::MAX).unwrap())); + assert_eq!(it.advance_by(0), Ok(())); + assert_eq!(it.advance_back_by(0), Ok(())); assert_eq!(it.size_hint(), (0, Some(0))); } @@ -175,19 +176,19 @@ fn test_flatten_count() { let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten(); assert_eq!(it.clone().count(), 40); - assert_eq!(it.advance_by(5), 0); + assert_eq!(it.advance_by(5), Ok(())); assert_eq!(it.clone().count(), 35); - assert_eq!(it.advance_back_by(5), 0); + assert_eq!(it.advance_back_by(5), Ok(())); assert_eq!(it.clone().count(), 30); - assert_eq!(it.advance_by(10), 0); + assert_eq!(it.advance_by(10), Ok(())); assert_eq!(it.clone().count(), 20); - assert_eq!(it.advance_back_by(8), 0); + assert_eq!(it.advance_back_by(8), Ok(())); assert_eq!(it.clone().count(), 12); - assert_eq!(it.advance_by(4), 0); + assert_eq!(it.advance_by(4), Ok(())); assert_eq!(it.clone().count(), 8); - assert_eq!(it.advance_back_by(5), 0); + assert_eq!(it.advance_back_by(5), Ok(())); assert_eq!(it.clone().count(), 3); - assert_eq!(it.advance_by(3), 0); + assert_eq!(it.advance_by(3), Ok(())); assert_eq!(it.clone().count(), 0); } @@ -196,18 +197,18 @@ fn test_flatten_last() { let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten(); assert_eq!(it.clone().last(), Some(39)); - assert_eq!(it.advance_by(5), 0); // 5..40 + assert_eq!(it.advance_by(5), Ok(())); // 5..40 assert_eq!(it.clone().last(), Some(39)); - assert_eq!(it.advance_back_by(5), 0); // 5..35 + assert_eq!(it.advance_back_by(5), Ok(())); // 5..35 assert_eq!(it.clone().last(), Some(34)); - assert_eq!(it.advance_by(10), 0); // 15..35 + assert_eq!(it.advance_by(10), Ok(())); // 15..35 assert_eq!(it.clone().last(), Some(34)); - assert_eq!(it.advance_back_by(8), 0); // 15..27 + assert_eq!(it.advance_back_by(8), Ok(())); // 15..27 assert_eq!(it.clone().last(), Some(26)); - assert_eq!(it.advance_by(4), 0); // 19..27 + assert_eq!(it.advance_by(4), Ok(())); // 19..27 assert_eq!(it.clone().last(), Some(26)); - assert_eq!(it.advance_back_by(5), 0); // 19..22 + assert_eq!(it.advance_back_by(5), Ok(())); // 19..22 assert_eq!(it.clone().last(), Some(21)); - assert_eq!(it.advance_by(3), 0); // 22..22 + assert_eq!(it.advance_by(3), Ok(())); // 22..22 assert_eq!(it.clone().last(), None); } diff --git a/library/core/tests/iter/adapters/skip.rs b/library/core/tests/iter/adapters/skip.rs index 134dead4ad3e9..e3e88a84fadf6 100644 --- a/library/core/tests/iter/adapters/skip.rs +++ b/library/core/tests/iter/adapters/skip.rs @@ -1,4 +1,5 @@ use core::iter::*; +use core::num::NonZeroUsize; use super::Unfuse; @@ -73,16 +74,16 @@ fn test_iterator_skip_nth() { #[test] fn test_skip_advance_by() { - assert_eq!((0..0).skip(10).advance_by(0), 0); - assert_eq!((0..0).skip(10).advance_by(1), 1); + assert_eq!((0..0).skip(10).advance_by(0), Ok(())); + assert_eq!((0..0).skip(10).advance_by(1), Err(NonZeroUsize::new(1).unwrap())); assert_eq!( (0u128..(usize::MAX as u128) + 1).skip(usize::MAX - 10).advance_by(usize::MAX - 5), - usize::MAX - 16 + Err(NonZeroUsize::new(usize::MAX - 16).unwrap()) ); - assert_eq!((0u128..u128::MAX).skip(usize::MAX - 10).advance_by(20), 0); + assert_eq!((0u128..u128::MAX).skip(usize::MAX - 10).advance_by(20), Ok(())); - assert_eq!((0..2).skip(1).advance_back_by(10), 9); - assert_eq!((0..0).skip(1).advance_back_by(0), 0); + assert_eq!((0..2).skip(1).advance_back_by(10), Err(NonZeroUsize::new(9).unwrap())); + assert_eq!((0..0).skip(1).advance_back_by(0), Ok(())); } #[test] diff --git a/library/core/tests/iter/adapters/take.rs b/library/core/tests/iter/adapters/take.rs index 8ba7f0c5f8a95..3cad47c06de03 100644 --- a/library/core/tests/iter/adapters/take.rs +++ b/library/core/tests/iter/adapters/take.rs @@ -1,4 +1,5 @@ use core::iter::*; +use core::num::NonZeroUsize; #[test] fn test_iterator_take() { @@ -76,23 +77,23 @@ fn test_iterator_take_nth_back() { #[test] fn test_take_advance_by() { let mut take = (0..10).take(3); - assert_eq!(take.advance_by(2), 0); + assert_eq!(take.advance_by(2), Ok(())); assert_eq!(take.next(), Some(2)); - assert_eq!(take.advance_by(1), 1); + assert_eq!(take.advance_by(1), Err(NonZeroUsize::new(1).unwrap())); - assert_eq!((0..0).take(10).advance_by(0), 0); - assert_eq!((0..0).take(10).advance_by(1), 1); - assert_eq!((0..10).take(4).advance_by(5), 1); + assert_eq!((0..0).take(10).advance_by(0), Ok(())); + assert_eq!((0..0).take(10).advance_by(1), Err(NonZeroUsize::new(1).unwrap())); + assert_eq!((0..10).take(4).advance_by(5), Err(NonZeroUsize::new(1).unwrap())); let mut take = (0..10).take(3); - assert_eq!(take.advance_back_by(2), 0); + assert_eq!(take.advance_back_by(2), Ok(())); assert_eq!(take.next(), Some(0)); - assert_eq!(take.advance_back_by(1), 1); + assert_eq!(take.advance_back_by(1), Err(NonZeroUsize::new(1).unwrap())); - assert_eq!((0..2).take(1).advance_back_by(10), 9); - assert_eq!((0..0).take(1).advance_back_by(1), 1); - assert_eq!((0..0).take(1).advance_back_by(0), 0); - assert_eq!((0..usize::MAX).take(100).advance_back_by(usize::MAX), usize::MAX - 100); + assert_eq!((0..2).take(1).advance_back_by(10), Err(NonZeroUsize::new(9).unwrap())); + assert_eq!((0..0).take(1).advance_back_by(1), Err(NonZeroUsize::new(1).unwrap())); + assert_eq!((0..0).take(1).advance_back_by(0), Ok(())); + assert_eq!((0..usize::MAX).take(100).advance_back_by(usize::MAX), Err(NonZeroUsize::new(usize::MAX - 100).unwrap())); } #[test] diff --git a/library/core/tests/iter/range.rs b/library/core/tests/iter/range.rs index d375dbf2ce441..0a77ecddb84d5 100644 --- a/library/core/tests/iter/range.rs +++ b/library/core/tests/iter/range.rs @@ -1,3 +1,4 @@ +use core::num::NonZeroUsize; use super::*; #[test] @@ -287,25 +288,25 @@ fn test_range_step() { #[test] fn test_range_advance_by() { let mut r = 0..usize::MAX; - assert_eq!(0, r.advance_by(0)); - assert_eq!(0, r.advance_back_by(0)); + assert_eq!(Ok(()), r.advance_by(0)); + assert_eq!(Ok(()), r.advance_back_by(0)); assert_eq!(r.len(), usize::MAX); - assert_eq!(0, r.advance_by(1)); - assert_eq!(0, r.advance_back_by(1)); + assert_eq!(Ok(()), r.advance_by(1)); + assert_eq!(Ok(()), r.advance_back_by(1)); assert_eq!((r.start, r.end), (1, usize::MAX - 1)); - assert_eq!(2, r.advance_by(usize::MAX)); + assert_eq!(Err(NonZeroUsize::new(2).unwrap()), r.advance_by(usize::MAX)); - assert_eq!(0, r.advance_by(0)); - assert_eq!(0, r.advance_back_by(0)); + assert_eq!(Ok(()), r.advance_by(0)); + assert_eq!(Ok(()), r.advance_back_by(0)); let mut r = 0u128..u128::MAX; - assert_eq!(0, r.advance_by(usize::MAX)); - assert_eq!(0, r.advance_back_by(usize::MAX)); + assert_eq!(Ok(()), r.advance_by(usize::MAX)); + assert_eq!(Ok(()), r.advance_back_by(usize::MAX)); assert_eq!((r.start, r.end), (0u128 + usize::MAX as u128, u128::MAX - usize::MAX as u128)); } diff --git a/library/core/tests/iter/traits/iterator.rs b/library/core/tests/iter/traits/iterator.rs index 4b446727c9a10..9eebfb1f1f359 100644 --- a/library/core/tests/iter/traits/iterator.rs +++ b/library/core/tests/iter/traits/iterator.rs @@ -1,3 +1,5 @@ +use core::num::NonZeroUsize; + /// A wrapper struct that implements `Eq` and `Ord` based on the wrapped /// integer modulo 3. Used to test that `Iterator::max` and `Iterator::min` /// return the correct element if some of them are equal. @@ -148,13 +150,13 @@ fn test_iterator_advance_by() { for i in 0..v.len() { let mut iter = v.iter(); - assert_eq!(iter.advance_by(i), 0); + assert_eq!(iter.advance_by(i), Ok(())); assert_eq!(iter.next().unwrap(), &v[i]); - assert_eq!(iter.advance_by(100), 100 - (v.len() - 1 - i)); + assert_eq!(iter.advance_by(100), Err(NonZeroUsize::new(100 - (v.len() - 1 - i)).unwrap())); } - assert_eq!(v.iter().advance_by(v.len()), 0); - assert_eq!(v.iter().advance_by(100), 100 - v.len()); + assert_eq!(v.iter().advance_by(v.len()), Ok(())); + assert_eq!(v.iter().advance_by(100), Err(NonZeroUsize::new(100 - v.len()).unwrap())); } #[test] @@ -163,13 +165,13 @@ fn test_iterator_advance_back_by() { for i in 0..v.len() { let mut iter = v.iter(); - assert_eq!(iter.advance_back_by(i), 0); + assert_eq!(iter.advance_back_by(i), Ok(())); assert_eq!(iter.next_back().unwrap(), &v[v.len() - 1 - i]); - assert_eq!(iter.advance_back_by(100), 100 - (v.len() - 1 - i)); + assert_eq!(iter.advance_back_by(100), Err(NonZeroUsize::new(100 - (v.len() - 1 - i)).unwrap())); } - assert_eq!(v.iter().advance_back_by(v.len()), 0); - assert_eq!(v.iter().advance_back_by(100), 100 - v.len()); + assert_eq!(v.iter().advance_back_by(v.len()), Ok(())); + assert_eq!(v.iter().advance_back_by(100), Err(NonZeroUsize::new(100 - v.len()).unwrap())); } #[test] @@ -178,13 +180,13 @@ fn test_iterator_rev_advance_back_by() { for i in 0..v.len() { let mut iter = v.iter().rev(); - assert_eq!(iter.advance_back_by(i), 0); + assert_eq!(iter.advance_back_by(i), Ok(())); assert_eq!(iter.next_back().unwrap(), &v[i]); - assert_eq!(iter.advance_back_by(100), 100 - (v.len() - 1 - i)); + assert_eq!(iter.advance_back_by(100), Err(NonZeroUsize::new(100 - (v.len() - 1 - i)).unwrap())); } - assert_eq!(v.iter().rev().advance_back_by(v.len()), 0); - assert_eq!(v.iter().rev().advance_back_by(100), 100 - v.len()); + assert_eq!(v.iter().rev().advance_back_by(v.len()), Ok(())); + assert_eq!(v.iter().rev().advance_back_by(100), Err(NonZeroUsize::new(100 - v.len()).unwrap())); } #[test] @@ -422,13 +424,13 @@ fn test_iterator_rev_advance_by() { for i in 0..v.len() { let mut iter = v.iter().rev(); - assert_eq!(iter.advance_by(i), 0); + assert_eq!(iter.advance_by(i), Ok(())); assert_eq!(iter.next().unwrap(), &v[v.len() - 1 - i]); - assert_eq!(iter.advance_by(100), 100 - (v.len() - 1 - i)); + assert_eq!(iter.advance_by(100), Err(NonZeroUsize::new(100 - (v.len() - 1 - i)).unwrap())); } - assert_eq!(v.iter().rev().advance_by(v.len()), 0); - assert_eq!(v.iter().rev().advance_by(100), 100 - v.len()); + assert_eq!(v.iter().rev().advance_by(v.len()), Ok(())); + assert_eq!(v.iter().rev().advance_by(100), Err(NonZeroUsize::new(100 - v.len()).unwrap())); } #[test] diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index a675d9e13fbb1..88f54591bb4a4 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -1,6 +1,7 @@ use core::cell::Cell; use core::cmp::Ordering; use core::mem::MaybeUninit; +use core::num::NonZeroUsize; use core::result::Result::{Err, Ok}; use core::slice; @@ -142,20 +143,20 @@ fn test_iterator_advance_by() { for i in 0..=v.len() { let mut iter = v.iter(); - assert_eq!(iter.advance_by(i), 0); + assert_eq!(iter.advance_by(i), Ok(())); assert_eq!(iter.as_slice(), &v[i..]); } let mut iter = v.iter(); - assert_eq!(iter.advance_by(v.len() + 1), 1); + assert_eq!(iter.advance_by(v.len() + 1), Err(NonZeroUsize::new(1).unwrap())); assert_eq!(iter.as_slice(), &[]); let mut iter = v.iter(); - assert_eq!(iter.advance_by(3), 0); + assert_eq!(iter.advance_by(3), Ok(())); assert_eq!(iter.as_slice(), &v[3..]); - assert_eq!(iter.advance_by(2), 0); + assert_eq!(iter.advance_by(2), Ok(())); assert_eq!(iter.as_slice(), &[]); - assert_eq!(iter.advance_by(0), 0); + assert_eq!(iter.advance_by(0), Ok(())); } #[test] @@ -164,20 +165,20 @@ fn test_iterator_advance_back_by() { for i in 0..=v.len() { let mut iter = v.iter(); - assert_eq!(iter.advance_back_by(i), 0); + assert_eq!(iter.advance_back_by(i), Ok(())); assert_eq!(iter.as_slice(), &v[..v.len() - i]); } let mut iter = v.iter(); - assert_eq!(iter.advance_back_by(v.len() + 1), 1); + assert_eq!(iter.advance_back_by(v.len() + 1), Err(NonZeroUsize::new(1).unwrap())); assert_eq!(iter.as_slice(), &[]); let mut iter = v.iter(); - assert_eq!(iter.advance_back_by(3), 0); + assert_eq!(iter.advance_back_by(3), Ok(())); assert_eq!(iter.as_slice(), &v[..v.len() - 3]); - assert_eq!(iter.advance_back_by(2), 0); + assert_eq!(iter.advance_back_by(2), Ok(())); assert_eq!(iter.as_slice(), &[]); - assert_eq!(iter.advance_back_by(0), 0); + assert_eq!(iter.advance_back_by(0), Ok(())); } #[test] From 9cd9da2cd1c365791c7bf41be5759ebc34180aa0 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Mon, 13 Mar 2023 20:16:43 +0100 Subject: [PATCH 3/4] update documentation --- library/core/src/iter/traits/double_ended.rs | 9 +++++---- library/core/src/iter/traits/iterator.rs | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index 182b365b030ae..d82ecb698dd08 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -101,10 +101,11 @@ pub trait DoubleEndedIterator: Iterator { /// eagerly skip `n` elements starting from the back by calling [`next_back`] up /// to `n` times until [`None`] is encountered. /// - /// `advance_back_by(n)` will return `0` if the iterator successfully advances by - /// `n` elements, or an usize `k` if [`None`] is encountered, where `k` is remaining number - /// of steps that could not be advanced because the iterator ran out. - /// Note that `k` is always less than `n`. + /// `advance_back_by(n)` will return `Ok(())` if the iterator successfully advances by + /// `n` elements, or a `Err(NonZeroUsize)` with value `k` if [`None`] is encountered, where `k` + /// is remaining number of steps that could not be advanced because the iterator ran out. + /// If `self` is empty and `n` is non-zero, then this returns `Err(n)`. + /// Otherwise, `k` is always less than `n`. /// /// Calling `advance_back_by(0)` can do meaningful work, for example [`Flatten`] can advance its /// outer iterator until it finds an inner iterator that is not empty, which then often diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 5a1ee80f7968d..080330fa41ef5 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -309,10 +309,11 @@ pub trait Iterator { /// This method will eagerly skip `n` elements by calling [`next`] up to `n` /// times until [`None`] is encountered. /// - /// `advance_by(n)` will return `0` if the iterator successfully advances by - /// `n` elements, or an usize `k` if [`None`] is encountered, where `k` is remaining number - /// of steps that could not be advanced because the iterator ran out. - /// Note that `k` is always less than `n`. + /// `advance_by(n)` will return `Ok(())` if the iterator successfully advances by + /// `n` elements, or a `Err(NonZeroUsize)` with value `k` if [`None`] is encountered, + /// where `k` is remaining number of steps that could not be advanced because the iterator ran out. + /// If `self` is empty and `n` is non-zero, then this returns `Err(n)`. + /// Otherwise, `k` is always less than `n`. /// /// Calling `advance_by(0)` can do meaningful work, for example [`Flatten`] /// can advance its outer iterator until it finds an inner iterator that is not empty, which From 41807938d2fbc7928d75b1d68ac08899682168a2 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Mon, 27 Mar 2023 14:56:14 +0200 Subject: [PATCH 4/4] fix advance_by impl for vec_deque and add tests --- .../src/collections/vec_deque/into_iter.rs | 14 +++++------ library/alloc/tests/vec_deque.rs | 23 +++++++++++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/into_iter.rs b/library/alloc/src/collections/vec_deque/into_iter.rs index c277c62ad14d9..e2b40f7912e0f 100644 --- a/library/alloc/src/collections/vec_deque/into_iter.rs +++ b/library/alloc/src/collections/vec_deque/into_iter.rs @@ -56,10 +56,10 @@ impl Iterator for IntoIter { #[inline] fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { - let rem = if self.inner.len < n { - let len = self.inner.len; + let len = self.inner.len; + let rem = if len < n { self.inner.clear(); - len - n + n - len } else { self.inner.drain(..n); 0 @@ -186,12 +186,12 @@ impl DoubleEndedIterator for IntoIter { #[inline] fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { let len = self.inner.len; - let rem = if len >= n { - self.inner.truncate(len - n); - 0 - } else { + let rem = if len < n { self.inner.clear(); n - len + } else { + self.inner.truncate(len - n); + 0 }; NonZeroUsize::new(rem).map_or(Ok(()), Err) } diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs index 5a0b852e8d5e2..ddc27e34ed994 100644 --- a/library/alloc/tests/vec_deque.rs +++ b/library/alloc/tests/vec_deque.rs @@ -1,3 +1,4 @@ +use core::num::NonZeroUsize; use std::assert_matches::assert_matches; use std::collections::TryReserveErrorKind::*; use std::collections::{vec_deque::Drain, VecDeque}; @@ -426,6 +427,28 @@ fn test_into_iter() { assert_eq!(it.next(), Some(7)); assert_eq!(it.size_hint(), (5, Some(5))); } + + // advance_by + { + let mut d = VecDeque::new(); + for i in 0..=4 { + d.push_back(i); + } + for i in 6..=8 { + d.push_front(i); + } + + let mut it = d.into_iter(); + assert_eq!(it.advance_by(1), Ok(())); + assert_eq!(it.next(), Some(7)); + assert_eq!(it.advance_back_by(1), Ok(())); + assert_eq!(it.next_back(), Some(3)); + + let mut it = VecDeque::from(vec![1, 2, 3, 4, 5]).into_iter(); + assert_eq!(it.advance_by(10), Err(NonZeroUsize::new(5).unwrap())); + let mut it = VecDeque::from(vec![1, 2, 3, 4, 5]).into_iter(); + assert_eq!(it.advance_back_by(10), Err(NonZeroUsize::new(5).unwrap())); + } } #[test]