Skip to main content

telltale_runtime/util/
sync.rs

1//! Platform-specific synchronization primitives
2//!
3//! This module provides cross-platform abstractions for synchronization primitives
4//! that work on both native (tokio) and WASM targets.
5//!
6//! On native targets, we use tokio's async synchronization primitives.
7//! On WASM, we use std::sync primitives (which work because WASM is single-threaded)
8//! and futures::channel for message passing.
9
10use cfg_if::cfg_if;
11
12cfg_if! {
13    if #[cfg(target_arch = "wasm32")] {
14        pub use futures::channel::mpsc;
15        pub use std::sync::{Mutex, RwLock};
16    } else {
17        pub use tokio::sync::{mpsc, Mutex, RwLock};
18    }
19}
20
21/// Helper macro for acquiring a read lock.
22///
23/// On native targets, this awaits the async lock.
24/// On WASM, this uses the blocking (but single-threaded safe) lock.
25///
26/// # Lock Poisoning (WASM only)
27///
28/// On WASM targets, lock poisoning is recovered by taking the inner guard.
29/// This avoids panic-only behavior in adapter/runtime helpers.
30///
31/// # Example
32///
33/// ```ignore
34/// let guard = read_lock!(self.data);
35/// println!("{:?}", *guard);
36/// ```
37#[macro_export]
38macro_rules! read_lock {
39    ($lock:expr) => {{
40        cfg_if::cfg_if! {
41            if #[cfg(target_arch = "wasm32")] {
42                match $lock.read() {
43                    Ok(guard) => guard,
44                    Err(poisoned) => poisoned.into_inner(),
45                }
46            } else {
47                $lock.read().await
48            }
49        }
50    }};
51}
52
53/// Helper macro for acquiring a write lock.
54///
55/// On native targets, this awaits the async lock.
56/// On WASM, this uses the blocking (but single-threaded safe) lock.
57///
58/// # Lock Poisoning (WASM only)
59///
60/// On WASM targets, lock poisoning is recovered by taking the inner guard.
61/// This avoids panic-only behavior in adapter/runtime helpers.
62///
63/// # Example
64///
65/// ```ignore
66/// let mut guard = write_lock!(self.data);
67/// *guard = new_value;
68/// ```
69#[macro_export]
70macro_rules! write_lock {
71    ($lock:expr) => {{
72        cfg_if::cfg_if! {
73            if #[cfg(target_arch = "wasm32")] {
74                match $lock.write() {
75                    Ok(guard) => guard,
76                    Err(poisoned) => poisoned.into_inner(),
77                }
78            } else {
79                $lock.write().await
80            }
81        }
82    }};
83}
84
85/// Helper macro for acquiring a mutex lock.
86///
87/// On native targets, this awaits the async lock.
88/// On WASM, this uses the blocking (but single-threaded safe) lock.
89///
90/// # Lock Poisoning (WASM only)
91///
92/// On WASM targets, lock poisoning is recovered by taking the inner guard.
93/// This avoids panic-only behavior in adapter/runtime helpers.
94///
95/// # Example
96///
97/// ```ignore
98/// let guard = mutex_lock!(self.state);
99/// process(&*guard);
100/// ```
101#[macro_export]
102macro_rules! mutex_lock {
103    ($lock:expr) => {{
104        cfg_if::cfg_if! {
105            if #[cfg(target_arch = "wasm32")] {
106                match $lock.lock() {
107                    Ok(guard) => guard,
108                    Err(poisoned) => poisoned.into_inner(),
109                }
110            } else {
111                $lock.lock().await
112            }
113        }
114    }};
115}
116
117// Re-export macros for use within the crate
118pub use crate::mutex_lock;
119pub use crate::read_lock;
120pub use crate::write_lock;