Implementing a replayable iterator
⚓ Rust 📅 2026-03-20 👤 surdeus 👁️ 4I ran into an interesting issue the other day and have been struggling to find a neat solution.
I have a type (let's call it Generator). It implements IntoIterator, but only for Generator, not for &Generator.
Now I need to use it somewhere that requires the iterator to be reusable, with the requirement that &T implements IntoIterator (specifically, the HRTB for<'a> &'a T: IntoIterator<Item = &'a I>).
To solve this, I want to create a wrapper that stores all encountered values and replays them, if no stored value is available, the next item from the real iterator is fetched.
However, I run into a lot of issues with shared/interior mutability and references to potentially moving memory addresses.
Here's the pseudoish-code idea:
struct BufferingIntoIterator<T>
where T: IntoIterator
{
it: T::IntoIter,
buffer: ???
}
struct BufferingIterator<T>
where T: IntoIterator
{
it: &T::IntoITer,
buffer: &???,
index: usize,
}
impl<T> IntoIterator for &BufferingIterator<T> {
type Item = &T::Item;
type IntoITer = BufferingIterator<T>;
fn into_iter(self) -> Self::IntoIter {
BufferingIterator::new(self)
}
}
impl<T> Iterator for BufferingIterator<T> {
type Item = &T::Item;
fn next(&mut self) -> Option<Self::Item> {
if index == buffer.len() {
if let Some(next) = self.it.next() {
self.buffer.push(next);
} else {
return None;
}
}
let item = buffer.get(index);
self.index += 1;
item
}
}
I've tried with the buffer as Rc<RefCell<Vec<T::Item>>> but that both gives me a lifetime issue because the item is tied to the lifetime of the RefMut/Ref I get when borrowing the RefCell and even then, the Vec would move things around in memory when it runs out of capacity. I could solve the latter by storing Box<T> in the Vec, but then the lifetime is still tied to the Ref inside next().
Solutions should be lazy and, preferably, succinct, safe, and without dependencies (i.e., using an arena is undesirable). (I'm not sure you can actually hit all of those, so see it as a challenge :D)
In the real situation where this arose, I solved it by just collecting into a Vec and then passing that, but for a generic solution, I don't want it to be eager because that might be unnecessary and won't work with infinite iterators.
Here's a Playground that you can "solve"
1 post - 1 participant
🏷️ Rust_feed