wgpu/util/
mutex.rs

1//! Provides a [`Mutex`] for internal use based on what features are available.
2
3cfg_if::cfg_if! {
4    if #[cfg(feature = "parking_lot")] {
5        use parking_lot::Mutex as MutexInner;
6    } else if #[cfg(std)] {
7        use std::sync::Mutex as MutexInner;
8    } else {
9        use core::cell::RefCell as MutexInner;
10    }
11}
12
13pub(crate) struct Mutex<T: ?Sized> {
14    inner: MutexInner<T>,
15}
16
17impl<T: ?Sized> core::fmt::Debug for Mutex<T>
18where
19    MutexInner<T>: core::fmt::Debug,
20{
21    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
22        <MutexInner<T> as core::fmt::Debug>::fmt(&self.inner, f)
23    }
24}
25
26impl<T: Default> Default for Mutex<T> {
27    fn default() -> Self {
28        Self::new(<T as Default>::default())
29    }
30}
31
32impl<T> Mutex<T> {
33    pub const fn new(value: T) -> Self {
34        Self {
35            inner: MutexInner::new(value),
36        }
37    }
38}
39
40impl<T: ?Sized> Mutex<T> {
41    pub fn lock(&self) -> impl core::ops::DerefMut<Target = T> + '_ {
42        cfg_if::cfg_if! {
43            if #[cfg(feature = "parking_lot")] {
44                self.inner.lock()
45            } else if #[cfg(std)] {
46                self.inner.lock().unwrap_or_else(std::sync::PoisonError::into_inner)
47            } else {
48                loop {
49                    let Ok(lock) = self.inner.try_borrow_mut() else {
50                        // Without `std` all we can do is spin until the current lock is released
51                        core::hint::spin_loop();
52                        continue;
53                    };
54
55                    break lock;
56                }
57            }
58        }
59    }
60}