Hi all,
Playground: Rust Playground
Problem
I'm having trouble implementing a custom iterator for the situation described below, and I hope someone might be able to help:
I am writing a sequential ray tracer for optical systems design where I need to iterate over (Gap, Surface, Option<Gap>) triplets. Each triplet is a single step in the ray trace of a system, and there is always one more surface than there are gaps. I have the following requirements:
- A system has many submodels in which the sequence of gaps are different and owned by each submodel
- A system only has one sequence of surfaces that can be shared amongst all its submodels
- The surfaces need to be mutable, but they must not be mutated during iteration
Since I need multiple ownership of my surfaces and occasionally need to mutate them, I decided to wrap them in a Rc<RefCell<...>>
. This way I thought I could keep the Ref
guard on the surfaces to keep the borrow alive while I was iterating over the submodel.
Attempt at a solution
struct Model {
surfs: Rc<RefCell<Vec<Surf>>>,
gaps: Vec<Gap>,
}
Next, I write the iterator struct as follows:
struct ModelIter<'a> {
model: &'a Model,
index: usize,
guard: Ref<'a, Vec<Surf>>,
}
impl<'a> ModelIter<'a> {
fn new(model: &'a Model) -> Self {
// Borrow the surfaces here for the lifetime of the ModelIter
let guard: Ref<'a, Vec<Surf>> = model.surfs.borrow();
Self {
model,
index: 0,
guard,
}
}
}
The guard
field is necessary so that the Ref
returned by the RefCell
's borrow method is not dropped during the lifetime of the iterator.
Compiler Error
So far, so good. Unfortunately, I have not managed to implement the Iterator
trait on this struct because I can't get the lifetimes to work out correctly.
impl<'a> Iterator for ModelIter<'a> {
type Item = Step<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.index == self.model.gaps.len() - 1 {
// We are at the last gap
let result = Some((
&self.model.gaps[self.index],
&self.guard[self.index + 1],
None,
));
self.index += 1;
result
} else if {
//...
}
}
}
The compiler states:
error: lifetime may not live long enough
--> src/main.rs:44:13
|
32 | impl<'a> Iterator for ModelIter<'a> {
| -- lifetime `'a` defined here
...
35 | fn next(&mut self) -> Option<Self::Item> {
| - let's call the lifetime of this reference `'1`
...
44 | result
| ^^^^^^ method was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
error: could not compile `playground` (bin "playground") due to 1 previous error
I think that likely my lifetime annotations are incorrect in the struct definitions, but I can't seem to understand really what's going on.
Any advice would be appreciated! Thanks!