What guarantees does core::iter::Repeat give around observing calls to clone? · Issue #81292 · rust-lang/rust (original) (raw)

Currently, core::iter::Repeat::nth calls core::iter::Repeat::next n times.

This allows a struct with interior mutability or other global state and a custom clone implementation to observe the number of times it has been cloned.

use std::sync::atomic::{AtomicUsize, Ordering};

static COUNTER: AtomicUsize = AtomicUsize::new(0);

struct X;

impl Clone for X { fn clone(&self) -> Self { COUNTER.fetch_add(1, Ordering::SeqCst); Self } }

fn main() { let mut iter = core::iter::repeat(X); for _ in 0..10_000 { let _ = iter.next(); } println!("counter: {}", COUNTER.load(Ordering::SeqCst)); let _ = iter.nth(555); println!("counter: {}", COUNTER.load(Ordering::SeqCst)); }

Currently, this program outputs:

counter: 10000
counter: 10556

Would it be possible to override the implementations of some Iterator methods that have default implementations without breaking any documented contract?

impl<A: Clone> Iterator for Repeat { type Item = A;

#[inline]
fn next(&mut self) -> Option<A> {
    Some(self.element.clone())
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
    (usize::MAX, None)
}

#[inline]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
    // Advancing an infinite iterator of a single element is a no-op.
    let _ = n;
}

#[inline]
fn nth(&mut self, n: usize) -> Option<T> {
    let _ = n;
    Some(self.element.clone())
}

fn last(self) -> Option<T> {
    loop {}
}

fn count(self) -> usize {
    loop {}
}

}

impl<A: Clone> DoubleEndedIterator for Repeat { #[inline] fn next_back(&mut self) -> Option { Some(self.element.clone()) }

#[inline]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
    // Advancing an infinite iterator of a single element is a no-op.
    let _ = n;
}

#[inline]
fn nth_back(&mut self, n: usize) -> Option<T> {
    let _ = n;
    Some(self.element.clone())
}

}