Implement `Iterator` for `RwLockReadGuard<'a, I>`

I have a RwLockReadGuard<'a, I>, where &I: IntoIterator<Item = &T>. I would like to use it like an Iterator<Item = &T> so I can pass it around and compose it by iterator combinators.

I have to tried to write something like (here for simplicity I is Vec<T>):

pub struct Foo<'a, T> {
    lock: RwLockReadGuard<'a , Vec<T>>,
    iter: slice::Iter<'a, T>,
}

and implement Iterator for Foo.

However there is no safe way to initialize Foo, since the only way to get slice::Iter is:

impl<'a, T> Foo<'a, T> {
    fn new(lock: RwLockReadGuard<'a , Vec<T>>) -> Self {
        let iter = lock.iter();
        Self {lock, iter} // <----- compile error!
    }
}

which involves the so-called self-referential structure.

I've seen such a structure before here. No idea if this is really safe. Miri doesn't complain.

2 Likes

Due to the way that the iterator trait is defined, it will always be possible to write this code, no matter what the iterator is.

let item = iter.next().unwrap();
drop(iter);
use(item);

But if item is a reference that points inside the read guard, and the iterator has ownership of the read guard, then drop(iter) would release the guard, meaning that using item afterwards would not be allowed.

So in short, you cannot do this with the iterator trait.

EDIT: @jofas example is unsound, see this playground.

7 Likes

Thanks for the great explanation Alice! I could reproduce your example with the original ArcAtomicRefCellIterator and raised an issue in the repo.

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.