There's actually more to your problem and it is not the Index trait implementation. Also, your example is not really a minimal, complete, and verifiable example (MCVE), so I have to guess as to what your exact problem is here.
The core of your problem is, that you cannot have your iterator return a reference, if it owns the content without borrowing the iterator itself. Your implementation of the Index trait for you SubImage is fine.
I will try to simulate your problem. Let's say we have a struct Julmond and it borrows some slice of integers (similar to your SubImage).
struct Julmond<'a>(&'a [i32]);
impl<'a> Index<usize> for Julmond<'a> {
type Output = [i32];
fn index<'b>(&'b self, idx: usize) -> &'b [i32] {
if idx < self.0.len() {
&self.0[idx..] // we always take a subslice from idx until the end
} else {
panic!("Index out of bounds!")
}
}
}
The Index trait requires that we borrow self. That is fine, since some implementors might own the data you're indexing into. This borrowing of self is expressed by linking the named lifetimes of self and the outgoing reference in the traits method signature:
fn index(&'a self, index: Idx) -> &'a Self::Output;
If we index into a Julmond, that value is considered borrowed as long as we hold on to the resulting reference into the Julmond:
let array = [1, 2, 3, 4, 5, 6];
let mut j = Julmond(&array);
let r = &j[3];
&mut j; // Error: r is still in scope and therefore j is still borrowed
What I can read from your example code is that you have some type that owns your SubImage and implements the Iterator trait. We will try to mimic that with another struct Nebelung implementing the Iterator trait on the way:
struct Nebelung<'a> {
j: Julmond<'a>,
pos: usize,
}
impl<'a> Iterator for Nebelung<'a> {
type Item = &'a [i32];
fn next(&mut self) -> Option<&'a [i32]> {
if self.pos < self.j.0.len() {
let tmp_pos = self.pos;
self.pos += 1;
Some(&self.j[tmp_pos]) // problematic line
} else {
None
}
}
}
This implementation returns an ever shrinking slice of the array from the underlying Julmond struct. We can test it like this:
fn main() {
let array = [1, 2, 3, 4, 5, 6];
let j = Julmond(&array);
let n = Nebelung { j: &j, pos: 0 };
for s in n {
println!("{:?}", s);
}
}
But this doesn't work. The compiler will complain (like in your example) that it cannot infer an appropriate lifetime for 'a. The reason is the borrow of self in the index method. When we call the index operator with j[tmp_pos] we are borrowing j. But j is owned by self of type Nebelung and so borrowing from j means we are borrowing from self. We are trying to return a reference to something that is owned by self and that requires that self has to be borrowed as well. The compiler suggests the right thing: linking the lifetimes of self and the outgoing reference. However, this violates the method signature of next.
If we want to return a reference from an iterator, that iterator cannot own the returned value. Otherwise, we would have to borrow the iterator in the call but that is not possible with next.
The only way around this, is having the iterator NOT own the value. So we modify the Nebelung struct to hold a reference to a Julmond:
struct Nebelung<'a: 'b, 'b> {
j: &'b Julmond<'a>,
pos: usize,
}
The 'a: 'b means that "'a outlives 'b" and it is required here. Since our reference j to a Julmond must not outlive the borrowed content of the Julmond. Ok great, our Nebelung is not the owner of the Julmond anymore. Just a borrower. Now we can implement the Iterator trait for it like this:
impl<'a, 'b> Iterator for Nebelung<'a, 'b> {
type Item = &'b [i32];
fn next(&mut self) -> Option<&'b [i32]> {
if self.pos < self.j.0.len() {
let tmp_pos = self.pos;
self.pos += 1;
Some(&self.j[tmp_pos])
} else {
None
}
}
}
The lifetimes of self and the outgoing reference are not required to be linked, since we are just returning a reference to some value which we are not the owner of. So the call to &self.j[tmp_pos] is not a borrow from self anymore. It is a borrow from the Julmond (via the index implementation).
Complete example
Whatever type you are implementing the Iterator trait for. You cannot have next (or next_back) return a reference if the type owns the value. Have your type borrow the SubImage instead.