Hi everyone,
I'm trying to polish up my Rust skills and wanted to play around with winit and wgpu. While doing so, I ran into a curious lifetime issue that puzzles me. This question is a distillation of what I was struggling with there.
The situation is as follows: First we create a bunch of Window
s. Then we create for each Window
a Surface
for rendering into that window. The Surface
borrows the window, so it has a lifetime parameter tracking the lifetime of the Window
.
My idea was now to have a CommonOwner
that holds all of the Window
s and Surface
s.
Here's what that looks like:
use std::cell::OnceCell;
struct Window;
#[allow(dead_code)]
struct Surface<'a> {
window: &'a Window,
}
impl<'a> Surface<'a> {
fn new(window: &'a Window) -> Self {
Self { window }
}
}
struct CommonOwner<'a> {
v: Vec<(Window, OnceCell<Surface<'a>>)>,
}
impl<'a> CommonOwner<'a> {
fn new() -> Self {
Self { v: vec![] }
}
fn create_window(&mut self) -> i32 /* id */ {
self.v.push((Window, OnceCell::new()));
(self.v.len() - 1) as i32
}
fn create_surface(&self, id: i32) {
let (w, c) = &self.v[id as usize];
let s = Surface::new(w);
c.set(s);
}
}
This does not work. The compiler is complaining:
error: lifetime may not live long enough
--> <source>:32:17
|
20 | impl<'a> CommonOwner<'a> {
| -- lifetime `'a` defined here
...
30 | fn create_surface(&self, id: i32) {
| - let's call the lifetime of this reference `'1`
31 | let (w, c) = &self.v[id as usize];
32 | let s = Surface::new(w);
| ^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'a`
First of all: I don't get this error. What does it mean? CommonOwner has a lifetime of 'a
, and &self
is obviously a CommonOwner<'a>
. Why would the compiler think that there is two different lifetimes here? I can't wrap my head around this.
The straightforward fix is of course, to change the signature of create_surface
to include the lifetime:
fn create_surface(&'a self, id: i32)
.
But here's my second problem: In my case, create_surface
comes from a trait which I don't control, so I cannot add a lifetime to &self
without triggering a lifetime mismatch error with the trait. I also can't find a way to wrap the call away, because the lifetime always keeps bubbling up to the entry point controlled by the trait (which makes sense, I guess). But now I'm stuck and don't know what would be a sensible way to resolve this.
I'm figuring the self-referential nature of the CommonOwner
is probably the root of the problem here, but I don't know how one would model such a scenario idiomatically in Rust.