In the following minimal code example, a MutexGuard
is used for accessing a BindGroup
that is sure to exist longer than the lifetime of the RenderPass
. However, this is obviously not known to the Rust compiler, resulting in a lifetime error.
For context: both RenderPass
and BindGroup
stem from the wgpu crate. Thus, it is not possible for me to simply adjust their method parameters.
The RenderPass
is created every frame, whereas the TextureManager
is only created once the program starts.
The TextureManager
keeps the reference to the BindGroup
as Arc<Mutex<…>>
in order to manipulate it from multiple threads.
use core::marker::PhantomData;
use std::ops::Deref;
use std::sync::{Arc, Mutex};
fn main() {
let texture_manager = TextureManager {
active_bind_group: Arc::new(Mutex::new(None)),
};
texture_manager.activate_texture(0);
let mut render_pass = RenderPass::new();
step(&mut render_pass, &texture_manager);
}
fn step<'pass>(render_pass: &mut RenderPass<'pass>, texture_manager: &'pass TextureManager) {
let guard = texture_manager.active_bind_group.lock().unwrap();
if let Some(bind_group) = guard.deref() {
render_pass.set_bind_group(bind_group);
}
}
struct TextureManager {
active_bind_group: Arc<Mutex<Option<BindGroup>>>,
// textures: Arc<Mutex<Vec<Texture>>>,
}
impl TextureManager {
// Only uses &self instead of &mut self for providing immutable interface
// so that a `Arc<TextureManager>` suffices for use in multithreaded code
fn activate_texture(&self, index: usize) {
// let texture = textures.lock().unwrap()[index];
// update bind group using the texture
*self.active_bind_group.lock().unwrap() = Some(BindGroup);
}
}
struct BindGroup;
struct RenderPass<'pass> {
phantom: PhantomData<&'pass ()>,
}
impl<'pass> RenderPass<'pass> {
fn new() -> Self {
Self {
phantom: PhantomData,
}
}
fn set_bind_group(&mut self, bind_group: &'pass BindGroup) {}
}
The resulting error:
error[E0597]: `guard` does not live long enough
--> src/main.rs:18:31
|
16 | fn step<'pass>(render_pass: &mut RenderPass<'pass>, texture_manager: &'pass TextureManager) {
| ----- lifetime `'pass` defined here
17 | let guard = texture_manager.active_bind_group.lock().unwrap();
| ----- binding `guard` declared here
18 | if let Some(bind_group) = guard.deref() {
| ^^^^^^^^^^^^^
| |
| borrowed value does not live long enough
| argument requires that `guard` is borrowed for `'pass`
...
21 | }
| - `guard` dropped here while still borrowed
I understand the origin of the error: the MutexGuard
only lives for the scope of the step
method. As soon as it is dropped, a reference to the original value can no longer be ensured.
Still, I haven't found any solution as to how to solve this problem.
Are there potentially different constructs than Mutex
to use in this scenario?