Skip to main content

web_async/
lock.rs

1use std::fmt;
2use std::ops::{Deref, DerefMut};
3
4// It's a cosmetic wrapper around Arc<Mutex<T>> on native platforms.
5// On WASM, it uses Rc<RefCell<T>> instead.
6// On native, uses parking_lot::Mutex which has better performance and deadlock detection.
7pub struct Lock<T> {
8	#[cfg(any(not(target_arch = "wasm32"), target_os = "wasi"))]
9	inner: std::sync::Arc<parking_lot::Mutex<T>>,
10
11	#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
12	inner: std::rc::Rc<std::cell::RefCell<T>>,
13}
14
15#[cfg(any(not(target_arch = "wasm32"), target_os = "wasi"))]
16impl<T> Lock<T> {
17	pub fn new(value: T) -> Self {
18		Self {
19			inner: std::sync::Arc::new(parking_lot::Mutex::new(value)),
20		}
21	}
22
23	pub fn is_clone(&self, other: &Self) -> bool {
24		std::sync::Arc::ptr_eq(&self.inner, &other.inner)
25	}
26}
27
28impl<T> Lock<T> {
29	pub fn lock(&self) -> LockGuard<'_, T> {
30		LockGuard::new(&self.inner)
31	}
32
33	pub fn downgrade(&self) -> LockWeak<T> {
34		LockWeak::new(&self.inner)
35	}
36}
37
38#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
39impl<T> Lock<T> {
40	pub fn new(value: T) -> Self {
41		Self {
42			inner: std::rc::Rc::new(std::cell::RefCell::new(value)),
43		}
44	}
45
46	pub fn is_clone(&self, other: &Self) -> bool {
47		std::rc::Rc::ptr_eq(&self.inner, &other.inner)
48	}
49}
50
51impl<T: Default> Default for Lock<T> {
52	fn default() -> Self {
53		Self::new(T::default())
54	}
55}
56
57impl<T> Clone for Lock<T> {
58	fn clone(&self) -> Self {
59		Self {
60			inner: self.inner.clone(),
61		}
62	}
63}
64
65impl<T: fmt::Debug> fmt::Debug for Lock<T> {
66	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67		self.inner.fmt(f)
68	}
69}
70
71pub struct LockGuard<'a, T> {
72	#[cfg(any(not(target_arch = "wasm32"), target_os = "wasi"))]
73	inner: parking_lot::MutexGuard<'a, T>,
74
75	#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
76	inner: std::cell::RefMut<'a, T>,
77}
78
79#[cfg(any(not(target_arch = "wasm32"), target_os = "wasi"))]
80impl<'a, T> LockGuard<'a, T> {
81	fn new(inner: &'a std::sync::Arc<parking_lot::Mutex<T>>) -> Self {
82		Self { inner: inner.lock() }
83	}
84}
85
86#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
87impl<'a, T> LockGuard<'a, T> {
88	fn new(inner: &'a std::rc::Rc<std::cell::RefCell<T>>) -> Self {
89		Self {
90			inner: inner.borrow_mut(),
91		}
92	}
93}
94
95impl<T> Deref for LockGuard<'_, T> {
96	type Target = T;
97
98	fn deref(&self) -> &Self::Target {
99		&self.inner
100	}
101}
102
103impl<T> DerefMut for LockGuard<'_, T> {
104	fn deref_mut(&mut self) -> &mut Self::Target {
105		&mut self.inner
106	}
107}
108
109impl<T: fmt::Debug> fmt::Debug for LockGuard<'_, T> {
110	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111		self.inner.fmt(f)
112	}
113}
114
115pub struct LockWeak<T> {
116	#[cfg(any(not(target_arch = "wasm32"), target_os = "wasi"))]
117	inner: std::sync::Weak<parking_lot::Mutex<T>>,
118
119	#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
120	inner: std::rc::Weak<std::cell::RefCell<T>>,
121}
122
123#[cfg(any(not(target_arch = "wasm32"), target_os = "wasi"))]
124impl<T> LockWeak<T> {
125	fn new(inner: &std::sync::Arc<parking_lot::Mutex<T>>) -> Self {
126		Self {
127			inner: std::sync::Arc::downgrade(inner),
128		}
129	}
130}
131
132#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
133impl<T> LockWeak<T> {
134	fn new(inner: &std::rc::Rc<std::cell::RefCell<T>>) -> Self {
135		Self {
136			inner: std::rc::Rc::downgrade(inner),
137		}
138	}
139}
140
141impl<T> LockWeak<T> {
142	pub fn upgrade(&self) -> Option<Lock<T>> {
143		Some(Lock {
144			inner: self.inner.upgrade()?,
145		})
146	}
147}
148
149impl<T> Clone for LockWeak<T> {
150	fn clone(&self) -> Self {
151		Self {
152			inner: self.inner.clone(),
153		}
154	}
155}