I'm trying to create a basic wrapper around a mesh to work with wgpu (more will be added later β abstracting this is justified), but I'm having some trouble with the lifetimes. This is what I have right now:
|
76 | pub fn render<'a, 'b>(&'a self, render_pass: &'b mut RenderPass<'b>) where 'b: 'a{
| -------- ----------------------
| |
| these two types are declared with different lifetimes...
77 | render_pass.set_vertex_buffer(0, &self.buffer, 0, 0);
| ^^^^^^^^^^^^^^^^^ ...but data from `self` flows into `render_pass` here
The error seems to be saying that the code is malformed since render_pass can store data from self, and that self may be dropped first, but the where 'b: 'a part would seem to contradict that, since it (I think) says that render_pass's lifetime is smaller than that of self's. What's goign on here (is rustc's borrow checker unable to verify an otherwise valid program as I suspect)? How can I fix it?
I think youβve got the relationship here backwards. This means that ββb outlives βaβ, so youβre releasing the shared access to self before releasing your exclusive access to render_pass.
When I switch the lifetime inheritance in the function's where clause, the function itself compiles fine, but use of it isn't possible, even when render_pass's lifetime is much shorter than the lifetime of the self reference. The call takes place in a block inside a function that takes &mut self, which has my RenderableMesh instance as a membe. The lifetime of the render_pass is the inner block, so its lifetime is clearly contained by the lifetime of the &mut self reference to my outer function, thus the code should compile, but it gives me this error:
|
171 | self.mesh.render(&mut render_pass);
| ^^^^^^^^^^^^^^^^ borrowed value does not live long enough
172 | }
| -
| |
| `render_pass` dropped here while still borrowed
| borrow might be used here, when `render_pass` is dropped and runs the `Drop` code for type `wgpu::RenderPass`
I can almost guarantee the problem is &'b mut RenderPass<'b>.
&'b Foo<'b> (a reference to a thing with the same lifetime inside it) is suspicious enough to pay close attention to. But &'b mut Foo<'b> (same thing but with a mutable reference) is virtually always a mistake. The reason they're different has to do with variance and, fair warning, when the answer to your question contains the word "variance" you're probably going to have a bad time. I'll link to this SO question if you have an hour to kill. The upshot is that taking a &'b mut RenderPass<'b> means that the RenderPass is borrowed for its entire lifetime, and it can't be used anymore. You need to let the compiler choose different lifetimes.