Data structure that owns a Vec<> and an iterator over the data

I would like to implement a struct that owns some data and internally stores an iterator over the data. I tried to write the iterator type down explicitly, but it becomes very long an complicated. My real world example involves multiple iterators that are the result of a filter having a predicate and I did not manage to get that signature right.

So I tried something like this:

struct MyStruct<I>
    where I: Iterator
{
    data: Vec<u8>,
    it: I
}

impl<I: Iterator> MyStruct<I> {
    fn new(data: Vec<u8>) -> Self {
        MyStruct {
            data,
            it: data.iter()
        }
    }
}

fn main() {
    let data = vec![1,2,3];
    let my = MyStruct::new(data);
}

I expected - or rather hoped - that I would be inferred automatically, but that does not work. I also tried to make it a Box<dyn Iterator>. But then I run into errors that ask me to specify specific casts that require me to specify lifetimes of the items returned by the iterator. I kind of understand why that's needed but I have no idea how to specify the lifetimes.

In case that makes the problem more plausible: MyStruct will itself become an iterator. It will implement a very specific iteration strategy over the owned Vec<>. To do so I need to store the iterators as internal state.

Could somebody give me a hint how to solve something like that?

This is the so-called “self-referential struct” problem — a struct containing some data and (an iterator containing) a reference to that same data. The rules of Rust syntax and the borrow checker do not contain any way to express this data structure.

It is possible to do so anyway with the help of libraries like ouroboros, which use unsafe code and macros to produce a safe abstraction. (Doing so has proven very tricky, and history is littered with self-reference libraries with unfixable soundness bugs. But, if you’re not trying to break it, you're probably fine.)

2 Likes

Another potential approach is to just not use references or a borrowing iterator for the state of your[1] iterator. Use indices or raw pointers and some unsafe, etc.

But I'm not sure how applicable this is to your actual use case.


  1. impl<..> Iterator for MyStruct<..> ↩︎

2 Likes

My own preference is to implement Iterator on the containing type by inlining its state and logic:

4 Likes