diff --git a/library/core/src/iter/adapters/step_by.rs b/library/core/src/iter/adapters/step_by.rs index 3a1ff98ec3343..aa4e46743a316 100644 --- a/library/core/src/iter/adapters/step_by.rs +++ b/library/core/src/iter/adapters/step_by.rs @@ -1,5 +1,5 @@ use crate::intrinsics; -use crate::iter::{TrustedLen, TrustedRandomAccess, from_fn}; +use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, from_fn}; use crate::num::NonZero; use crate::ops::{Range, Try}; use crate::range::RangeIter; @@ -136,6 +136,11 @@ where #[stable(feature = "iterator_step_by", since = "1.28.0")] impl ExactSizeIterator for StepBy where I: ExactSizeIterator {} +// StepBy stops yielding items once the underlying iterator does, so it is fused +// whenever the underlying iterator is fused. +#[stable(feature = "step_by_fused", since = "CURRENT_RUSTC_VERSION")] +impl FusedIterator for StepBy where I: FusedIterator {} + // SAFETY: This adapter is shortening. TrustedLen requires the upper bound to be calculated correctly. // These requirements can only be satisfied when the upper bound of the inner iterator's upper // bound is never `None`. I: TrustedRandomAccess happens to provide this guarantee while diff --git a/library/coretests/tests/iter/adapters/step_by.rs b/library/coretests/tests/iter/adapters/step_by.rs index 810c014fdc8d9..7580b6fb9f8af 100644 --- a/library/coretests/tests/iter/adapters/step_by.rs +++ b/library/coretests/tests/iter/adapters/step_by.rs @@ -418,3 +418,16 @@ fn test_step_by_nth_non_fused_on_non_first_take() { // so we should expect `StepBy::nth` to return `None` assert_eq!(iter.nth(usize::MAX), None) } + +#[test] +fn test_step_by_fused() { + // `StepBy` is fused whenever the underlying iterator is fused. + fn assert_fused(_: I) {} + assert_fused((0..10).step_by(3)); + + // Once the underlying fused iterator is exhausted, `StepBy` keeps yielding `None`. + let mut it = (0..3).step_by(5); + assert_eq!(it.next(), Some(0)); + assert_eq!(it.next(), None); + assert_eq!(it.next(), None); +}