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;