about summary refs log tree commit diff
path: root/library/core/src
diff options
context:
space:
mode:
authornils <48135649+Nilstrieb@users.noreply.github.com>2023-03-28 12:51:11 +0200
committerGitHub <noreply@github.com>2023-03-28 12:51:11 +0200
commit0883848882483e216714d5be5a1fde87dd5a1690 (patch)
treed95b525e10a670b6f775785c18dd41d68c9f84bc /library/core/src
parent857b6316163158b7b44b5521cf4b8e023e375a8f (diff)
parent41807938d2fbc7928d75b1d68ac08899682168a2 (diff)
Rollup merge of #92284 - the8472:simplify-advance-by, r=scottmcm
Change advance(_back)_by to return the remainder instead of the number of processed elements

When advance_by can't advance the iterator by the number of requested elements it now returns the amount by which it couldn't be advanced instead of the amount by which it did.

This simplifies adapters like chain, flatten or cycle because the remainder doesn't have to be calculated as the difference between requested steps and completed steps anymore.

Additionally switching from `Result<(), usize>` to `Result<(), NonZeroUsize>` reduces the size of the result and makes converting from/to a usize representing the number of remaining steps cheap.
Diffstat (limited to 'library/core/src')
-rw-r--r--library/core/src/array/iter.rs15
-rw-r--r--library/core/src/iter/adapters/by_ref_sized.rs5
-rw-r--r--library/core/src/iter/adapters/chain.rs51
-rw-r--r--library/core/src/iter/adapters/copied.rs5
-rw-r--r--library/core/src/iter/adapters/cycle.rs26
-rw-r--r--library/core/src/iter/adapters/enumerate.rs22
-rw-r--r--library/core/src/iter/adapters/flatten.rs21
-rw-r--r--library/core/src/iter/adapters/rev.rs5
-rw-r--r--library/core/src/iter/adapters/skip.rs54
-rw-r--r--library/core/src/iter/adapters/take.rs34
-rw-r--r--library/core/src/iter/range.rs25
-rw-r--r--library/core/src/iter/sources/repeat.rs5
-rw-r--r--library/core/src/iter/sources/repeat_n.rs8
-rw-r--r--library/core/src/iter/traits/double_ended.rs26
-rw-r--r--library/core/src/iter/traits/iterator.rs22
-rw-r--r--library/core/src/ops/index_range.rs15
-rw-r--r--library/core/src/slice/iter/macros.rs8
17 files changed, 174 insertions, 173 deletions
diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs
index 8259c087d22..73e2c2cfbbe 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,12 +285,11 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
         self.next_back()
     }
 
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
-        let original_len = self.len();
-
+    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);
+        let remaining = n - range_to_drop.len();
 
         // SAFETY: These elements are currently initialized, so it's fine to drop them.
         unsafe {
@@ -297,7 +297,7 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
             ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice));
         }
 
-        if n > original_len { Err(original_len) } else { Ok(()) }
+        NonZeroUsize::new(remaining).map_or(Ok(()), Err)
     }
 }
 
@@ -334,12 +334,11 @@ impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
         })
     }
 
-    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
-        let original_len = self.len();
-
+    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);
+        let remaining = n - range_to_drop.len();
 
         // SAFETY: These elements are currently initialized, so it's fine to drop them.
         unsafe {
@@ -347,7 +346,7 @@ impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
             ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice));
         }
 
-        if n > original_len { Err(original_len) } else { Ok(()) }
+        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 477e7117c3e..4e0e19ddc78 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<I: Iterator> Iterator for ByRefSized<'_, I> {
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         I::advance_by(self.0, n)
     }
 
@@ -62,7 +63,7 @@ impl<I: DoubleEndedIterator> DoubleEndedIterator for ByRefSized<'_, I> {
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), 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 d4b2640e81d..2046b70c9c6 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,38 +96,33 @@ where
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
-        let mut rem = n;
-
+    fn advance_by(&mut self, mut n: usize) -> Result<(), NonZeroUsize> {
         if let Some(ref mut a) = self.a {
-            match a.advance_by(rem) {
+            n = match a.advance_by(n) {
                 Ok(()) => return Ok(()),
-                Err(k) => rem -= k,
-            }
+                Err(k) => k.get(),
+            };
             self.a = None;
         }
 
         if let Some(ref mut b) = self.b {
-            match b.advance_by(rem) {
-                Ok(()) => return Ok(()),
-                Err(k) => rem -= k,
-            }
+            return b.advance_by(n);
             // we don't fuse the second iterator
         }
 
-        if rem == 0 { Ok(()) } else { Err(n - rem) }
+        NonZeroUsize::new(n).map_or(Ok(()), Err)
     }
 
     #[inline]
     fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
         if let Some(ref mut a) = self.a {
-            match a.advance_by(n) {
+            n = match a.advance_by(n) {
                 Ok(()) => match a.next() {
-                    None => n = 0,
+                    None => 0,
                     x => return x,
                 },
-                Err(k) => n -= k,
-            }
+                Err(k) => k.get(),
+            };
 
             self.a = None;
         }
@@ -186,38 +182,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) -> Result<(), NonZeroUsize> {
         if let Some(ref mut b) = self.b {
-            match b.advance_back_by(rem) {
+            n = match b.advance_back_by(n) {
                 Ok(()) => return Ok(()),
-                Err(k) => rem -= k,
-            }
+                Err(k) => k.get(),
+            };
             self.b = None;
         }
 
         if let Some(ref mut a) = self.a {
-            match a.advance_back_by(rem) {
-                Ok(()) => return Ok(()),
-                Err(k) => rem -= k,
-            }
+            return a.advance_back_by(n);
             // we don't fuse the second iterator
         }
 
-        if rem == 0 { Ok(()) } else { Err(n - rem) }
+        NonZeroUsize::new(n).map_or(Ok(()), Err)
     }
 
     #[inline]
     fn nth_back(&mut self, mut n: usize) -> Option<Self::Item> {
         if let Some(ref mut b) = self.b {
-            match b.advance_back_by(n) {
+            n = match b.advance_back_by(n) {
                 Ok(()) => match b.next_back() {
-                    None => n = 0,
+                    None => 0,
                     x => return x,
                 },
-                Err(k) => n -= 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 a076ab925e3..2289025d0a7 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) -> Result<(), 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) -> Result<(), 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 02b5939072e..51bd09b6eff 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,23 +82,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) -> Result<(), NonZeroUsize> {
+        let mut n = match self.iter.advance_by(n) {
+            Ok(()) => return Ok(()),
+            Err(rem) => rem.get(),
+        };
 
-        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,
-            }
+            n = match self.iter.advance_by(n) {
+                Ok(()) => return Ok(()),
+                e @ Err(rem) if rem.get() == n => return e,
+                Err(rem) => rem.get(),
+            };
         }
 
-        Ok(())
+        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 8c32a35a12f..479ea6d83c7 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,17 +115,14 @@ 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) -> 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]
@@ -208,7 +206,7 @@ where
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), 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 e4020c45f71..e0308e3360f 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) -> Result<(), 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) -> Result<(), 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) -> Result<(), 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) -> Result<(), usize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         self.inner.advance_back_by(n)
     }
 }
@@ -552,18 +553,18 @@ where
 
     #[inline]
     #[rustc_inherit_overflow_checks]
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         #[inline]
         #[rustc_inherit_overflow_checks]
         fn advance<U: Iterator>(n: usize, iter: &mut U) -> ControlFlow<(), usize> {
             match iter.advance_by(n) {
                 Ok(()) => ControlFlow::Break(()),
-                Err(advanced) => ControlFlow::Continue(n - advanced),
+                Err(remaining) => ControlFlow::Continue(remaining.get()),
             }
         }
 
         match self.iter_try_fold(n, advance) {
-            ControlFlow::Continue(remaining) if remaining > 0 => Err(n - remaining),
+            ControlFlow::Continue(remaining) => NonZeroUsize::new(remaining).map_or(Ok(()), Err),
             _ => Ok(()),
         }
     }
@@ -642,18 +643,18 @@ where
 
     #[inline]
     #[rustc_inherit_overflow_checks]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         #[inline]
         #[rustc_inherit_overflow_checks]
         fn advance<U: DoubleEndedIterator>(n: usize, iter: &mut U) -> ControlFlow<(), usize> {
             match iter.advance_back_by(n) {
                 Ok(()) => ControlFlow::Break(()),
-                Err(advanced) => ControlFlow::Continue(n - advanced),
+                Err(remaining) => ControlFlow::Continue(remaining.get()),
             }
         }
 
         match self.iter_try_rfold(n, advance) {
-            ControlFlow::Continue(remaining) if remaining > 0 => Err(n - remaining),
+            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 8ae6d96fde4..1d882087f69 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) -> Result<(), 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) -> Result<(), 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 c6334880db5..306338bc7cc 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,34 +129,27 @@ 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) };
-            }
-        }
+    fn advance_by(&mut self, mut n: usize) -> Result<(), NonZeroUsize> {
+        let skip_inner = self.n;
+        let skip_and_advance = skip_inner.saturating_add(n);
 
-        // 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)
-                }
-            };
+        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 = match self.iter.advance_by(n) {
+                Ok(()) => 0,
+                Err(n) => n.get(),
+            }
         }
 
-        Ok(())
+        NonZeroUsize::new(n).map_or(Ok(()), Err)
     }
 }
 
@@ -209,13 +203,11 @@ 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) -> Result<(), NonZeroUsize> {
         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);
+        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 d947c7b0e30..ce18bffe714 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,18 +122,15 @@ where
 
     #[inline]
     #[rustc_inherit_overflow_checks]
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         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 = match self.iter.advance_by(min) {
+            Ok(()) => 0,
+            Err(rem) => rem.get(),
+        };
+        let advanced = min - rem;
+        self.n -= advanced;
+        NonZeroUsize::new(n - advanced).map_or(Ok(()), Err)
     }
 }
 
@@ -223,7 +221,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) -> 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);
@@ -232,12 +230,14 @@ 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,
+        let remainder = match self.iter.advance_back_by(advance_by) {
+            Ok(()) => 0,
+            Err(rem) => rem.get(),
         };
-        self.n -= advanced;
-        return if advanced < n { Err(advanced) } else { Ok(()) };
+        let advanced_by_inner = advance_by - remainder;
+        let advanced_by = advanced_by_inner - trim_inner;
+        self.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 f19636fba5d..1cd71193bd7 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<Self::Item>;
     fn spec_nth(&mut self, n: usize) -> Option<Self::Item>;
-    fn spec_advance_by(&mut self, n: usize) -> Result<(), usize>;
+    fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize>;
 
     // DoubleEndedIterator
     fn spec_next_back(&mut self) -> Option<Self::Item>;
     fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item>;
-    fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize>;
+    fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize>;
 }
 
 impl<A: ~const Step + ~const Destruct> const RangeIteratorImpl for ops::Range<A> {
@@ -567,7 +568,7 @@ impl<A: ~const Step + ~const Destruct> const RangeIteratorImpl for ops::Range<A>
     }
 
     #[inline]
-    default fn spec_advance_by(&mut self, n: usize) -> Result<(), 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<A: ~const Step + ~const Destruct> const RangeIteratorImpl for ops::Range<A>
         self.start =
             Step::forward_checked(self.start.clone(), taken).expect("`Step` invariants not upheld");
 
-        if taken < n { Err(taken) } else { Ok(()) }
+        NonZeroUsize::new(n - taken).map_or(Ok(()), Err)
     }
 
     #[inline]
@@ -608,7 +609,7 @@ impl<A: ~const Step + ~const Destruct> const RangeIteratorImpl for ops::Range<A>
     }
 
     #[inline]
-    default fn spec_advance_back_by(&mut self, n: usize) -> Result<(), 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<A: ~const Step + ~const Destruct> const RangeIteratorImpl for ops::Range<A>
         self.end =
             Step::backward_checked(self.end.clone(), taken).expect("`Step` invariants not upheld");
 
-        if taken < n { Err(taken) } else { Ok(()) }
+        NonZeroUsize::new(n - taken).map_or(Ok(()), Err)
     }
 }
 
@@ -651,7 +652,7 @@ impl<T: ~const TrustedStep + ~const Destruct> const RangeIteratorImpl for ops::R
     }
 
     #[inline]
-    fn spec_advance_by(&mut self, n: usize) -> Result<(), 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<T: ~const TrustedStep + ~const Destruct> 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(()) }
+        NonZeroUsize::new(n - taken).map_or(Ok(()), Err)
     }
 
     #[inline]
@@ -695,7 +696,7 @@ impl<T: ~const TrustedStep + ~const Destruct> 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) -> 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<T: ~const TrustedStep + ~const Destruct> 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(()) }
+        NonZeroUsize::new(n - taken).map_or(Ok(()), Err)
     }
 }
 
@@ -757,7 +758,7 @@ impl<A: ~const Step + ~const Destruct> const Iterator for ops::Range<A> {
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         self.spec_advance_by(n)
     }
 
@@ -836,7 +837,7 @@ impl<A: ~const Step + ~const Destruct> const DoubleEndedIterator for ops::Range<
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), 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 733142ed011..67051f6e97b 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,7 +81,7 @@ impl<A: Clone> Iterator for Repeat<A> {
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         // Advancing an infinite iterator of a single element is a no-op.
         let _ = n;
         Ok(())
@@ -109,7 +110,7 @@ impl<A: Clone> DoubleEndedIterator for Repeat<A> {
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), 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;
         Ok(())
diff --git a/library/core/src/iter/sources/repeat_n.rs b/library/core/src/iter/sources/repeat_n.rs
index dc61d6065b8..0b0445850bf 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<A: Clone> Iterator for RepeatN<A> {
     }
 
     #[inline]
-    fn advance_by(&mut self, skip: usize) -> Result<(), usize> {
+    fn advance_by(&mut self, skip: usize) -> Result<(), NonZeroUsize> {
         let len = self.count;
 
         if skip >= len {
@@ -145,7 +146,8 @@ impl<A: Clone> Iterator for RepeatN<A> {
         }
 
         if skip > len {
-            Err(len)
+            // SAFETY: we just checked that the difference is positive
+            Err(unsafe { NonZeroUsize::new_unchecked(skip - len) })
         } else {
             self.count = len - skip;
             Ok(())
@@ -178,7 +180,7 @@ impl<A: Clone> DoubleEndedIterator for RepeatN<A> {
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), 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 7a10dea500a..d82ecb698dd 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.
@@ -100,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 [`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 `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
@@ -120,25 +122,29 @@ 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), Ok(()));
     /// 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(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) -> Result<(), usize>
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize>
     where
         Self::Item: ~const Destruct,
     {
         for i in 0..n {
-            self.next_back().ok_or(i)?;
+            if self.next_back().is_none() {
+                // SAFETY: `i` is always less than `n`.
+                return Err(unsafe { NonZeroUsize::new_unchecked(n - i) });
+            }
         }
         Ok(())
     }
@@ -188,7 +194,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::Item> {
-        self.advance_back_by(n).ok()?;
+        if self.advance_back_by(n).is_err() {
+            return None;
+        }
         self.next_back()
     }
 
@@ -374,7 +382,7 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I {
     fn next_back(&mut self) -> Option<I::Item> {
         (**self).next_back()
     }
-    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         (**self).advance_back_by(n)
     }
     fn nth_back(&mut self, n: usize) -> Option<I::Item> {
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 16c9f668b8e..080330fa41e 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;
@@ -308,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 [`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 `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
@@ -327,22 +329,26 @@ 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), Ok(()));
     /// 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(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) -> Result<(), usize>
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize>
     where
         Self::Item: ~const Destruct,
     {
         for i in 0..n {
-            self.next().ok_or(i)?;
+            if self.next().is_none() {
+                // SAFETY: `i` is always less than `n`.
+                return Err(unsafe { NonZeroUsize::new_unchecked(n - i) });
+            }
         }
         Ok(())
     }
@@ -4013,7 +4019,7 @@ impl<I: Iterator + ?Sized> Iterator for &mut I {
     fn size_hint(&self) -> (usize, Option<usize>) {
         (**self).size_hint()
     }
-    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
         (**self).advance_by(n)
     }
     fn nth(&mut self, n: usize) -> Option<Self::Item> {
diff --git a/library/core/src/ops/index_range.rs b/library/core/src/ops/index_range.rs
index 3e06776d2c6..265022a394e 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<usize>`, but with a safety invariant that `start <= end`.
 ///
@@ -132,10 +133,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) -> Result<(), NonZeroUsize> {
+        let taken = self.take_prefix(n);
+        NonZeroUsize::new(n - taken.len()).map_or(Ok(()), Err)
     }
 }
 
@@ -151,10 +151,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) -> Result<(), NonZeroUsize> {
+        let taken = self.take_suffix(n);
+        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 a800da546b4..b73e35f1e91 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) -> Result<(), NonZeroUsize> {
                 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) }
+                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) -> Result<(), 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) };
-                if advance == n { Ok(()) } else { Err(advance) }
+                NonZeroUsize::new(n - advance).map_or(Ok(()), Err)
             }
         }