bevy_render/renderer/
wgpu_wrapper.rs

1/// A wrapper to safely make `wgpu` types Send / Sync on web with atomics enabled.
2///
3/// On web with `atomics` enabled the inner value can only be accessed
4/// or dropped on the `wgpu` thread or else a panic will occur.
5/// On other platforms the wrapper simply contains the wrapped value.
6#[derive(Debug, Clone)]
7pub struct WgpuWrapper<T>(
8    #[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))] T,
9    #[cfg(all(target_arch = "wasm32", target_feature = "atomics"))] send_wrapper::SendWrapper<T>,
10);
11
12// SAFETY: SendWrapper is always Send + Sync.
13#[cfg(all(target_arch = "wasm32", target_feature = "atomics"))]
14#[expect(unsafe_code, reason = "Blanket-impl Send requires unsafe.")]
15unsafe impl<T> Send for WgpuWrapper<T> {}
16#[cfg(all(target_arch = "wasm32", target_feature = "atomics"))]
17#[expect(unsafe_code, reason = "Blanket-impl Sync requires unsafe.")]
18unsafe impl<T> Sync for WgpuWrapper<T> {}
19
20impl<T> WgpuWrapper<T> {
21    /// Constructs a new instance of `WgpuWrapper` which will wrap the specified value.
22    pub fn new(t: T) -> Self {
23        #[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))]
24        return Self(t);
25        #[cfg(all(target_arch = "wasm32", target_feature = "atomics"))]
26        return Self(send_wrapper::SendWrapper::new(t));
27    }
28
29    /// Unwraps the value.
30    pub fn into_inner(self) -> T {
31        #[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))]
32        return self.0;
33        #[cfg(all(target_arch = "wasm32", target_feature = "atomics"))]
34        return self.0.take();
35    }
36}
37
38impl<T> core::ops::Deref for WgpuWrapper<T> {
39    type Target = T;
40
41    fn deref(&self) -> &Self::Target {
42        &self.0
43    }
44}
45
46impl<T> core::ops::DerefMut for WgpuWrapper<T> {
47    fn deref_mut(&mut self) -> &mut Self::Target {
48        &mut self.0
49    }
50}