clawft_core/runtime.rs
1//! Async runtime abstraction.
2//!
3//! Provides platform-agnostic wrappers for time and async sync primitives.
4//! On native, delegates to tokio. On browser WASM, uses futures-util /
5//! js_sys equivalents.
6
7// ── now ───────────────────────────────────────────────────────────────
8
9/// Get current time as milliseconds since epoch.
10///
11/// Safe on both native and browser WASM.
12#[cfg(feature = "native")]
13pub fn now_millis() -> u64 {
14 std::time::SystemTime::now()
15 .duration_since(std::time::UNIX_EPOCH)
16 .map(|d| d.as_millis() as u64)
17 .unwrap_or(0)
18}
19
20/// Get current time as milliseconds since epoch (browser).
21#[cfg(feature = "browser")]
22pub fn now_millis() -> u64 {
23 js_sys::Date::now() as u64
24}
25
26/// Fallback when neither native nor browser is selected.
27#[cfg(not(any(feature = "native", feature = "browser")))]
28pub fn now_millis() -> u64 {
29 0
30}
31
32// ── Async Mutex re-export ─────────────────────────────────────────────
33
34/// Re-export the appropriate async Mutex.
35///
36/// On native: `tokio::sync::Mutex` (Send-safe).
37/// On browser: `futures_util::lock::Mutex` (single-threaded WASM).
38#[cfg(feature = "native")]
39pub use tokio::sync::Mutex;
40
41#[cfg(not(feature = "native"))]
42pub use futures_util::lock::Mutex;
43
44// ── Async RwLock re-export ────────────────────────────────────────────
45
46/// Re-export the appropriate async RwLock.
47///
48/// On native: `tokio::sync::RwLock`.
49/// On browser: A thin wrapper around `std::sync::RwLock` with async methods.
50#[cfg(feature = "native")]
51pub use tokio::sync::RwLock;
52
53// For browser, provide a minimal async-compatible RwLock wrapper
54// using std::sync::RwLock. In single-threaded WASM, contention is impossible
55// so the sync lock never blocks.
56#[cfg(not(feature = "native"))]
57pub mod rw_lock_wrapper {
58 use std::ops::{Deref, DerefMut};
59
60 /// Async-compatible RwLock for single-threaded WASM.
61 ///
62 /// Wraps `std::sync::RwLock` and provides `.read().await` / `.write().await`
63 /// methods that return the same guard types, making it a drop-in replacement
64 /// for `tokio::sync::RwLock` on browser targets.
65 pub struct RwLock<T>(std::sync::RwLock<T>);
66
67 impl<T> RwLock<T> {
68 /// Create a new RwLock.
69 pub fn new(value: T) -> Self {
70 Self(std::sync::RwLock::new(value))
71 }
72
73 /// Acquire a read lock (async-compatible, resolves immediately on WASM).
74 pub async fn read(&self) -> RwLockReadGuard<'_, T> {
75 RwLockReadGuard(self.0.read().expect("RwLock poisoned"))
76 }
77
78 /// Acquire a write lock (async-compatible, resolves immediately on WASM).
79 pub async fn write(&self) -> RwLockWriteGuard<'_, T> {
80 RwLockWriteGuard(self.0.write().expect("RwLock poisoned"))
81 }
82 }
83
84 /// Read guard for the async RwLock wrapper.
85 pub struct RwLockReadGuard<'a, T>(std::sync::RwLockReadGuard<'a, T>);
86
87 impl<T> Deref for RwLockReadGuard<'_, T> {
88 type Target = T;
89 fn deref(&self) -> &T {
90 &self.0
91 }
92 }
93
94 /// Write guard for the async RwLock wrapper.
95 pub struct RwLockWriteGuard<'a, T>(std::sync::RwLockWriteGuard<'a, T>);
96
97 impl<T> Deref for RwLockWriteGuard<'_, T> {
98 type Target = T;
99 fn deref(&self) -> &T {
100 &self.0
101 }
102 }
103
104 impl<T> DerefMut for RwLockWriteGuard<'_, T> {
105 fn deref_mut(&mut self) -> &mut T {
106 &mut self.0
107 }
108 }
109}
110
111#[cfg(not(feature = "native"))]
112pub use rw_lock_wrapper::RwLock;