bot_engine/compat.rs
1//! Platform compatibility layer for WASM and native targets.
2//!
3//! Provides unified APIs for spawn and sleep that work on both:
4//! - Native (tokio runtime) - enabled by `native` feature
5//! - WASM (browser event loop via wasm-bindgen-futures) - enabled by `wasm` feature
6//!
7//! Note: When both features are enabled, native takes precedence.
8
9use std::future::Future;
10use std::time::Duration;
11
12/// Spawn an async task.
13/// - Native: Uses tokio::spawn (multi-threaded)
14/// - WASM: Uses wasm_bindgen_futures::spawn_local (single-threaded)
15#[cfg(feature = "native")]
16pub fn spawn<F>(fut: F)
17where
18 F: Future<Output = ()> + Send + 'static,
19{
20 tokio::spawn(fut);
21}
22
23#[cfg(all(feature = "wasm", not(feature = "native")))]
24pub fn spawn<F>(fut: F)
25where
26 F: Future<Output = ()> + 'static,
27{
28 wasm_bindgen_futures::spawn_local(fut);
29}
30
31/// Async sleep.
32/// - Native: Uses tokio::time::sleep
33/// - WASM: Uses gloo_timers::future::TimeoutFuture
34#[cfg(feature = "native")]
35pub async fn sleep(duration: Duration) {
36 tokio::time::sleep(duration).await;
37}
38
39#[cfg(all(feature = "wasm", not(feature = "native")))]
40pub async fn sleep(duration: Duration) {
41 gloo_timers::future::TimeoutFuture::new(duration.as_millis() as u32).await;
42}
43
44/// No-op sleep for backtesting (instant return).
45/// Use this in backtest mode to skip real delays.
46pub async fn sleep_noop(_duration: Duration) {
47 // Instant return - no actual delay
48}
49
50/// Get current timestamp in milliseconds.
51/// - Native: Uses std::time
52/// - WASM: Uses js_sys::Date
53#[cfg(feature = "native")]
54pub fn now_ms() -> i64 {
55 std::time::SystemTime::now()
56 .duration_since(std::time::UNIX_EPOCH)
57 .unwrap()
58 .as_millis() as i64
59}
60
61#[cfg(all(feature = "wasm", not(feature = "native")))]
62pub fn now_ms() -> i64 {
63 js_sys::Date::now() as i64
64}
65
66/// Yield to the event loop without a timer delay.
67/// - Native: Uses tokio::task::yield_now (cooperative scheduling)
68/// - WASM: Uses Promise.resolve() microtask (much faster than setTimeout)
69///
70/// This is crucial for backtesting - allows browser to stay responsive
71/// without the ~4ms+ overhead of setTimeout timers.
72#[cfg(feature = "native")]
73pub async fn yield_now() {
74 tokio::task::yield_now().await;
75}
76
77#[cfg(all(feature = "wasm", not(feature = "native")))]
78pub async fn yield_now() {
79 // Create a resolved promise - this schedules a microtask which is MUCH faster
80 // than setTimeout (which has minimum ~4ms in browsers)
81 use wasm_bindgen::JsValue;
82 let promise = js_sys::Promise::resolve(&JsValue::NULL);
83 let _ = wasm_bindgen_futures::JsFuture::from(promise).await;
84}