Please help me solve a lifetime issue related to smart pointers and iterators

I am working with a trait that allows iteration over data held in a struct. A simplified representation of it would be:

trait ByteIterator {
    fn iterate_bytes<'a>(&'a self) -> Box<dyn Iterator<Item = u8> + 'a>;
}

What is noticeable here is that the returned iterator and the &self reference have the same lifetime ('a), which makes sense.

A straightforward implementation would be something like this:

struct Data {
    bytes: Vec<u8>,
}

impl ByteIterator for Data {
    fn iterate_bytes<'a>(&'a self) -> Box<dyn Iterator<Item = u8> + 'a> {
        let iter = self.bytes.iter().map(|byte| *byte);
        Box::new(iter)
    }
}

All good so far!

Another thing I need is to share the Data as an owned value. Therefore I create another type:

struct SharedData {
    data: Rc<RefCell<Data>>,
}

The problem comes when implementing ByteIterator for SharedData:

impl ByteIterator for SharedData {
    fn iterate_bytes<'a>(&'a self) -> Box<dyn Iterator<Item = u8> + 'a> {
        let data_ref = self.data.borrow();
        let iter = data_ref.iterate_bytes();
        Box::new(iter)  // compiler error!!
    }
}

Here, data_ref goes out of scope and the end of the function, while iter holds a reference to data_ref, so it doesn't work.

Any suggestion on how to get this to work? I am open to change the trait definition if similar feature can be achieved. Thank you!

You can implement an iterator that holds onto a Ref<'a, [u8]> instead of holding onto a reference.

Something that tries to hold onto a reference to the underlying data and hold onto the Ref<'a, Data> would be a self-referencial struct, which is too restrictive (e.g. you can't return it or otherwise move it).

1 Like

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.