Skip to main content

kithara_platform/sync/
mutex.rs

1use std::ops::{Deref, DerefMut};
2
3#[cfg(not(target_arch = "wasm32"))]
4use parking_lot::Mutex as ParkingLotMutex;
5
6#[cfg(not(target_arch = "wasm32"))]
7pub struct Mutex<T>(ParkingLotMutex<T>);
8
9#[cfg(not(target_arch = "wasm32"))]
10impl<T> Mutex<T> {
11    #[inline]
12    pub fn new(value: T) -> Self {
13        Self(ParkingLotMutex::new(value))
14    }
15
16    #[inline]
17    pub fn lock_sync(&self) -> MutexGuard<'_, T> {
18        MutexGuard(self.0.lock())
19    }
20
21    /// Try to acquire the lock without blocking.
22    ///
23    /// # Errors
24    ///
25    /// Returns [`NotAvailable`] if the mutex is already held.
26    #[inline]
27    pub fn try_lock(&self) -> Result<MutexGuard<'_, T>, NotAvailable> {
28        self.0.try_lock().map(MutexGuard).ok_or(NotAvailable)
29    }
30}
31
32#[cfg(not(target_arch = "wasm32"))]
33impl<T: Default> Default for Mutex<T> {
34    fn default() -> Self {
35        Self::new(T::default())
36    }
37}
38
39#[cfg(not(target_arch = "wasm32"))]
40pub struct MutexGuard<'a, T>(pub(super) parking_lot::MutexGuard<'a, T>);
41
42#[cfg(not(target_arch = "wasm32"))]
43impl<T> Deref for MutexGuard<'_, T> {
44    type Target = T;
45
46    #[inline]
47    fn deref(&self) -> &T {
48        &self.0
49    }
50}
51
52#[cfg(not(target_arch = "wasm32"))]
53impl<T> DerefMut for MutexGuard<'_, T> {
54    #[inline]
55    fn deref_mut(&mut self) -> &mut T {
56        &mut self.0
57    }
58}
59
60#[cfg(target_arch = "wasm32")]
61use wasm_safe_thread::Mutex as WasmMutex;
62
63#[cfg(target_arch = "wasm32")]
64pub struct Mutex<T>(WasmMutex<T>);
65
66#[cfg(target_arch = "wasm32")]
67impl<T> Mutex<T> {
68    #[inline]
69    pub fn new(value: T) -> Self {
70        Self(WasmMutex::new(value))
71    }
72
73    #[inline]
74    pub fn lock_sync(&self) -> MutexGuard<'_, T> {
75        MutexGuard(self.0.lock_sync())
76    }
77
78    /// Try to acquire the lock without blocking.
79    ///
80    /// # Errors
81    ///
82    /// Returns [`NotAvailable`] if the mutex is already held.
83    #[inline]
84    pub fn try_lock(&self) -> Result<MutexGuard<'_, T>, NotAvailable> {
85        self.0.try_lock().map(MutexGuard).map_err(|_| NotAvailable)
86    }
87}
88
89#[cfg(target_arch = "wasm32")]
90impl<T: Default> Default for Mutex<T> {
91    fn default() -> Self {
92        Self::new(T::default())
93    }
94}
95
96#[cfg(target_arch = "wasm32")]
97// SAFETY: browser is single-threaded; a `Mutex` value never crosses threads.
98unsafe impl<T> Send for Mutex<T> {}
99#[cfg(target_arch = "wasm32")]
100// SAFETY: same — no concurrent access on the single browser thread.
101unsafe impl<T> Sync for Mutex<T> {}
102
103#[cfg(target_arch = "wasm32")]
104pub struct MutexGuard<'a, T>(pub(super) wasm_safe_thread::guard::Guard<'a, T>);
105
106#[cfg(target_arch = "wasm32")]
107impl<T> Deref for MutexGuard<'_, T> {
108    type Target = T;
109
110    #[inline]
111    fn deref(&self) -> &T {
112        &self.0
113    }
114}
115
116#[cfg(target_arch = "wasm32")]
117impl<T> DerefMut for MutexGuard<'_, T> {
118    #[inline]
119    fn deref_mut(&mut self) -> &mut T {
120        &mut self.0
121    }
122}
123
124/// `try_lock()` failed because the mutex is already held.
125#[derive(Debug, Clone, Copy, PartialEq, Eq)]
126pub struct NotAvailable;
127
128impl std::fmt::Display for NotAvailable {
129    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130        f.write_str("mutex is already locked")
131    }
132}
133
134impl std::error::Error for NotAvailable {}