Skip to main content

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;