Why does RwLockReadGuard not live long enough?

I am trying to render something with wgpu with this simplefied methods:

fn render<'a>(&'a self, engine: &'a GameEngine, render_pass: &mut RenderPass<'a>, device: &Device, queue: &Queue) {
   let w = self.world.read().unwrap();
   w.render(engine,render_pass,device,queue);
}

The world render method is baseclly the same:

pub fn render<'a>(&'a self, engine: &'a GameEngine, render_pass: &mut RenderPass<'a>, device: &Device, queue: &Queue) {

}

But it doesn't work because of lifetime errors:

              w.render(engine,render_pass,device,queue);
|             ^--------------------------------------------------------------------------------------
|             |
|             borrowed value does not live long enough
|             argument requires that `w` is borrowed for `'a`

It seems like that the RwLock read() has a wrong lifetime or something I don't really now. I hope you can help me.

That's because you have &'a self, which requires self to live at least as long as &'a GameEngine, but the borrow guard has been created later, in a smaller scope, so it can't live as long as &'a GameEngine.

Lifetime annotations are meant to describe what the code actually does, not what you want Rust to do. Rust can't make anything live longer. Either you have to change the code to match what the annotations say, or remove the annotations that require things to live longer.

The error is in using a lifetime annotation on self. It's almost always a mistake. Just remove the extra annotations: &self and &GameEngine, and the inferred defaults will let you use self (i.e. the lock guard) that hasn't been created in the same scope as GameEngine and RenderPass data.

2 Likes

Thank you , I understand that but only with these lifetime annotations the code is working, because if I remove them this error arises:

these two types are declared with different lifetimes...
...but data from `engine` flows into `render_pass` here

This is the problem. If I remove the annotations this code doesn't work.

Sounds like you needed to remove the lifetime annotation only from &self. You should've left it there for &'a GameEngine and &mut RenderPass<'a>

1 Like

Thank you but this doesn't work eithere. Here is how my system works:

I have a scene with a render method:

fn render<'a>(&'a self, engine: &'a GameEngine, render_pass: &mut RenderPass<'a>, device: &Device, queue: &Queue){
    engine.sprite_renderer.render(render_pass,&self.camera)
}

The render method for sprite renderer is this:

pub fn render<'a>(&'a self,render_pass:&mut RenderPass<'a>,camera:&'a Camera) {
    //RENDER METHOD
}

So I am not only using data from engine but also data from self (the camera), which both flow into render_pass.
Because of this I need the &'a self annotation.
But with &'a self the RwLock scope is not the same.
I will probably have to overthink this system.

I currently doing it like this:

let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
                        label: Some("Render Encoder"),
                    });
{
    let mut render_pass = encoder.begin_render_pass(..........);
    scene.render(&mut engine,&mut render_pass,&device,&queue);
}

I can probably create the renderpass inside of the scene.render() method and not ouside, so that the scope is not different for the RwLock.

This has worked. I am creating the RenderPass now in the render method of Scene.

1 Like