1#[cfg(not(target_arch = "wasm32"))]
16pub use parking_lot::{
17 Condvar, Mutex, MutexGuard, Once, RwLock, RwLockReadGuard, RwLockWriteGuard,
18};
19
20#[cfg(target_arch = "wasm32")]
25mod wasm_sync {
26 use std::ops::{Deref, DerefMut};
27 use std::sync::{
28 Mutex as StdMutex, MutexGuard as StdMutexGuard, Once as StdOnce, PoisonError,
29 RwLock as StdRwLock, RwLockReadGuard as StdRwReadGuard,
30 RwLockWriteGuard as StdRwWriteGuard,
31 };
32
33 pub struct Mutex<T: ?Sized>(StdMutex<T>);
36
37 impl<T> Mutex<T> {
38 pub const fn new(val: T) -> Self {
39 Self(StdMutex::new(val))
40 }
41
42 pub fn into_inner(self) -> T {
43 self.0.into_inner().unwrap_or_else(PoisonError::into_inner)
44 }
45 }
46
47 impl<T: ?Sized> Mutex<T> {
48 pub fn lock(&self) -> MutexGuard<'_, T> {
49 MutexGuard(self.0.lock().unwrap_or_else(PoisonError::into_inner))
50 }
51
52 pub fn try_lock(&self) -> Option<MutexGuard<'_, T>> {
53 self.0.try_lock().ok().map(MutexGuard)
54 }
55
56 pub fn is_locked(&self) -> bool {
57 self.0.try_lock().is_err()
58 }
59
60 pub fn get_mut(&mut self) -> &mut T {
61 self.0.get_mut().unwrap_or_else(PoisonError::into_inner)
62 }
63 }
64
65 impl<T: Default> Default for Mutex<T> {
66 fn default() -> Self {
67 Self::new(T::default())
68 }
69 }
70
71 impl<T: std::fmt::Debug + ?Sized> std::fmt::Debug for Mutex<T> {
72 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73 match self.try_lock() {
74 Some(guard) => f.debug_struct("Mutex").field("data", &&*guard).finish(),
75 None => f.debug_struct("Mutex").field("data", &"<locked>").finish(),
76 }
77 }
78 }
79
80 pub struct MutexGuard<'a, T: ?Sized>(StdMutexGuard<'a, T>);
81
82 impl<T: ?Sized> Deref for MutexGuard<'_, T> {
83 type Target = T;
84 fn deref(&self) -> &T {
85 &self.0
86 }
87 }
88
89 impl<T: ?Sized> DerefMut for MutexGuard<'_, T> {
90 fn deref_mut(&mut self) -> &mut T {
91 &mut self.0
92 }
93 }
94
95 pub struct RwLock<T: ?Sized>(StdRwLock<T>);
98
99 impl<T> RwLock<T> {
100 pub const fn new(val: T) -> Self {
101 Self(StdRwLock::new(val))
102 }
103
104 pub fn into_inner(self) -> T {
105 self.0.into_inner().unwrap_or_else(PoisonError::into_inner)
106 }
107 }
108
109 impl<T: ?Sized> RwLock<T> {
110 pub fn read(&self) -> RwLockReadGuard<'_, T> {
111 RwLockReadGuard(self.0.read().unwrap_or_else(PoisonError::into_inner))
112 }
113
114 pub fn try_read(&self) -> Option<RwLockReadGuard<'_, T>> {
115 self.0.try_read().ok().map(RwLockReadGuard)
116 }
117
118 pub fn write(&self) -> RwLockWriteGuard<'_, T> {
119 RwLockWriteGuard(self.0.write().unwrap_or_else(PoisonError::into_inner))
120 }
121
122 pub fn try_write(&self) -> Option<RwLockWriteGuard<'_, T>> {
123 self.0.try_write().ok().map(RwLockWriteGuard)
124 }
125
126 pub fn get_mut(&mut self) -> &mut T {
127 self.0.get_mut().unwrap_or_else(PoisonError::into_inner)
128 }
129 }
130
131 impl<T: Default> Default for RwLock<T> {
132 fn default() -> Self {
133 Self::new(T::default())
134 }
135 }
136
137 impl<T: std::fmt::Debug + ?Sized> std::fmt::Debug for RwLock<T> {
138 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
139 match self.try_read() {
140 Some(guard) => f.debug_struct("RwLock").field("data", &&*guard).finish(),
141 None => f.debug_struct("RwLock").field("data", &"<locked>").finish(),
142 }
143 }
144 }
145
146 pub struct RwLockReadGuard<'a, T: ?Sized>(StdRwReadGuard<'a, T>);
147
148 impl<T: ?Sized> Deref for RwLockReadGuard<'_, T> {
149 type Target = T;
150 fn deref(&self) -> &T {
151 &self.0
152 }
153 }
154
155 pub struct RwLockWriteGuard<'a, T: ?Sized>(StdRwWriteGuard<'a, T>);
156
157 impl<T: ?Sized> Deref for RwLockWriteGuard<'_, T> {
158 type Target = T;
159 fn deref(&self) -> &T {
160 &self.0
161 }
162 }
163
164 impl<T: ?Sized> DerefMut for RwLockWriteGuard<'_, T> {
165 fn deref_mut(&mut self) -> &mut T {
166 &mut self.0
167 }
168 }
169
170 pub struct Once(StdOnce);
173
174 impl Once {
175 pub const fn new() -> Self {
176 Self(StdOnce::new())
177 }
178
179 pub fn call_once(&self, f: impl FnOnce()) {
180 self.0.call_once(f);
181 }
182
183 pub fn is_completed(&self) -> bool {
184 self.0.is_completed()
185 }
186 }
187
188 impl Default for Once {
189 fn default() -> Self {
190 Self::new()
191 }
192 }
193
194 pub struct Condvar(std::sync::Condvar);
197
198 impl Condvar {
199 pub const fn new() -> Self {
200 Self(std::sync::Condvar::new())
201 }
202
203 pub fn notify_one(&self) {
204 self.0.notify_one();
205 }
206
207 pub fn notify_all(&self) {
208 self.0.notify_all();
209 }
210
211 pub fn wait<T>(&self, guard: &mut MutexGuard<'_, T>) {
217 let _ = (&self.0, guard);
218 }
219 }
220
221 impl Default for Condvar {
222 fn default() -> Self {
223 Self::new()
224 }
225 }
226
227 impl std::fmt::Debug for Condvar {
228 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
229 f.write_str("Condvar")
230 }
231 }
232}
233
234#[cfg(target_arch = "wasm32")]
235pub use wasm_sync::{Condvar, Mutex, MutexGuard, Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
236
237#[cfg(not(target_arch = "wasm32"))]
242pub use std::time::{Duration, Instant};
243
244#[cfg(target_arch = "wasm32")]
245pub use std::time::Duration;
246
247#[cfg(target_arch = "wasm32")]
248use std::sync::atomic::{AtomicU64, Ordering};
249
250#[cfg(target_arch = "wasm32")]
258#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
259pub struct Instant(Duration);
260
261#[cfg(target_arch = "wasm32")]
262static WASM_INSTANT_TICKS_MS: AtomicU64 = AtomicU64::new(0);
263
264#[cfg(target_arch = "wasm32")]
265impl Instant {
266 pub fn now() -> Self {
267 Self(Duration::from_millis(
268 WASM_INSTANT_TICKS_MS.fetch_add(1, Ordering::Relaxed),
269 ))
270 }
271
272 pub fn elapsed(&self) -> Duration {
273 Self::now().saturating_duration_since(*self)
274 }
275
276 pub fn duration_since(self, earlier: Self) -> Duration {
277 self.0.checked_sub(earlier.0).unwrap_or(Duration::ZERO)
278 }
279
280 pub fn saturating_duration_since(self, earlier: Self) -> Duration {
281 self.duration_since(earlier)
282 }
283
284 pub fn checked_duration_since(self, earlier: Self) -> Option<Duration> {
285 self.0.checked_sub(earlier.0)
286 }
287
288 pub fn checked_add(self, duration: Duration) -> Option<Self> {
289 self.0.checked_add(duration).map(Self)
290 }
291
292 pub fn checked_sub(self, duration: Duration) -> Option<Self> {
293 self.0.checked_sub(duration).map(Self)
294 }
295}
296
297#[cfg(target_arch = "wasm32")]
298impl std::ops::Add<Duration> for Instant {
299 type Output = Self;
300
301 fn add(self, rhs: Duration) -> Self::Output {
302 Self(self.0 + rhs)
303 }
304}
305
306#[cfg(target_arch = "wasm32")]
307impl std::ops::AddAssign<Duration> for Instant {
308 fn add_assign(&mut self, rhs: Duration) {
309 self.0 += rhs;
310 }
311}
312
313#[cfg(target_arch = "wasm32")]
314impl std::ops::Sub<Duration> for Instant {
315 type Output = Self;
316
317 fn sub(self, rhs: Duration) -> Self::Output {
318 Self(self.0.checked_sub(rhs).unwrap_or(Duration::ZERO))
319 }
320}
321
322#[cfg(target_arch = "wasm32")]
323impl std::ops::SubAssign<Duration> for Instant {
324 fn sub_assign(&mut self, rhs: Duration) {
325 self.0 = self.0.checked_sub(rhs).unwrap_or(Duration::ZERO);
326 }
327}
328
329#[cfg(target_arch = "wasm32")]
330impl std::ops::Sub<Instant> for Instant {
331 type Output = Duration;
332
333 fn sub(self, rhs: Instant) -> Self::Output {
334 self.duration_since(rhs)
335 }
336}
337
338#[cfg(not(target_arch = "wasm32"))]
343pub fn current_thread_id() -> u64 {
344 let id = std::thread::current().id();
348 let s = format!("{id:?}");
349 s.trim_start_matches("ThreadId(")
350 .trim_end_matches(')')
351 .parse::<u64>()
352 .unwrap_or(0)
353}
354
355#[cfg(target_arch = "wasm32")]
356pub fn current_thread_id() -> u64 {
357 0 }
359
360#[cfg(test)]
365mod tests {
366 use super::*;
367
368 #[test]
369 fn mutex_lock_unlock() {
370 let m = Mutex::new(42);
371 {
372 let mut g = m.lock();
373 assert_eq!(*g, 42);
374 *g = 99;
375 }
376 assert_eq!(*m.lock(), 99);
377 }
378
379 #[test]
380 fn mutex_try_lock_when_unlocked() {
381 let m = Mutex::new(1);
382 assert!(m.try_lock().is_some());
383 }
384
385 #[test]
386 fn rwlock_read_write() {
387 let rw = RwLock::new(String::from("hello"));
388 {
389 let r = rw.read();
390 assert_eq!(&*r, "hello");
391 }
392 {
393 let mut w = rw.write();
394 w.push_str(" world");
395 }
396 assert_eq!(&*rw.read(), "hello world");
397 }
398
399 #[test]
400 fn once_calls_once() {
401 let once = Once::new();
402 let mut count = 0;
403 once.call_once(|| count += 1);
404 once.call_once(|| count += 1);
405 assert_eq!(count, 1);
406 }
407
408 #[test]
409 fn thread_id_returns_value() {
410 let id = current_thread_id();
411 let _ = id;
413 }
414
415 #[test]
416 fn mutex_default() {
417 let m: Mutex<i32> = Mutex::default();
418 assert_eq!(*m.lock(), 0);
419 }
420
421 #[test]
422 fn mutex_into_inner() {
423 let m = Mutex::new(vec![1, 2, 3]);
424 let v = m.into_inner();
425 assert_eq!(v, vec![1, 2, 3]);
426 }
427
428 #[test]
429 fn condvar_notify_noop() {
430 let cv = Condvar::new();
431 cv.notify_one();
432 cv.notify_all();
433 }
434
435 #[test]
436 fn rwlock_into_inner() {
437 let rw = RwLock::new(42);
438 assert_eq!(rw.into_inner(), 42);
439 }
440
441 #[cfg(target_arch = "wasm32")]
442 #[test]
443 fn once_is_completed() {
444 let once = Once::new();
445 assert!(!once.is_completed());
446 once.call_once(|| {});
447 assert!(once.is_completed());
448 }
449}