0

The Issue

I'm trying to implement an iterator that yields windows (i.e. slices) into a buffer owned by the iterator itself – for example, if the buffer contains [0, 1, 2, 3, 4, 5], the iterator might yield [0, 1, 2, 3], [2, 3], or [3, 4, 5]. Here's a minimal example (Playground):

struct Slicer<'a> {
    full: Vec<u32>,
    cur_slice: &'a mut [u32]
}

impl<'a> Slicer<'a> {
    fn new() -> Slicer<'a> {
        let mut full = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
        Slicer {
            full: full, // Is there a way to transfer ownership of `full` here?
            cur_slice: full.as_mut_slice()
        }
    }
}

impl<'a> Iterator for Slicer<'a>
{
    type Item = &'a [u32];

    fn next(&mut self) -> Option<&'a [u32]> {
        if self.cur_slice.len() != 0 {
            // In the actual program, this is streaming new data into the
            // buffer. This is just an example of modifying the slice.
            let len = self.cur_slice.len();
            self.cur_slice = self.cur_slice[..len - 1].as_mut();
            Some(self.cur_slice) // Getting a lifetime error here…
        } else {
            None
        }
    }
}

fn main() {
    let mut slicer = Slicer::new();
    while let Some(x) = slicer.next() {
        println!("{x:?}");
    }
}

This results in two separate errors: error[E0515]: cannot return value referencing local variable `full` and error: lifetime may not live long enough. Full errors:

error[E0515]: cannot return value referencing local variable `full`
  --> src\main.rs:11:9
   |
11 | /         Slicer {
12 | |             full: full,
13 | |             cur_slice: full.as_mut_slice()
   | |                        ---- `full` is borrowed here
14 | |         }
   | |_________^ returns a value referencing data owned by the current function
error: lifetime may not live long enough
  --> src\main.rs:26:13
   |
16 | impl<'a> Iterator for Slicer<'a>
   |      -- lifetime `'a` defined here
...
20 |     fn next(&mut self) -> Option<&'a [u32]> {
   |             - let's call the lifetime of this reference `'1`
...
26 |             Some(self.cur_slice) // Getting a lifetime error here…
   |             ^^^^^^^^^^^^^^^^^^^^ method was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`

Now, from what I understand, this counts as an iterator that refers to itself – which an Iterator is unable to do (because the signature of next doesn't include an explicit lifetime for &mut self – with fairly good reason, from what I understand). This appears to be a perfect use case for lending iterators (as mentioned in this previous StackOverflow answer, and in fact, a window iterator is the primary example in the docs), but I attempted an implementation using a lending iterator, and was presented with exactly the same errors.

The Question

How does one fix this? Is there a way to make the lending iterator approach work? Is there a different composition that achieves the same effect?

(Note that I can't copy the data, as that would defeat the purpose of the iterator, which is meant to be a more ergonomic interface into parsing a particular file format with a lot of data.)

3
  • 1
    Since you already noticed that Iterator fundamentally can't do this I don't see how adding that implementation is relevant here, if you add your attempt using LendingIterator we can look at that and figure out where you went wrong. External resources like your gist are problematic if you don't include them within the post itself for several reasons. Commented May 1, 2024 at 18:37
  • The simplest approach however would be to not implement Iterator for your struct at all but add a separate Iter struct alltogether. Commented May 1, 2024 at 18:44
  • "full: full, // Is there a way to transfer ownership of full here?" → yes, that's what the code you comment on does… Commented May 1, 2024 at 18:53

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.