1use core::future::Future;
9use core::time::Duration;
10
11#[cfg(not(target_arch = "wasm32"))]
16pub trait MaybeSend: Send {}
17
18#[cfg(not(target_arch = "wasm32"))]
19impl<T: Send + ?Sized> MaybeSend for T {}
20
21#[cfg(target_arch = "wasm32")]
26pub trait MaybeSend {}
27
28#[cfg(target_arch = "wasm32")]
29impl<T: ?Sized> MaybeSend for T {}
30
31pub trait Runtime {
33 fn spawn<F>(&self, future: F)
35 where
36 F: Future<Output = ()> + MaybeSend + 'static;
37
38 fn sleep(&self, duration: Duration) -> impl Future<Output = ()> + MaybeSend;
40}
41
42#[cfg(feature = "rt-tokio")]
43pub use self::tokio::TokioRuntime;
44
45#[cfg(all(feature = "rt-wasm", target_arch = "wasm32"))]
46pub use self::wasm::WasmRuntime;
47
48#[cfg(feature = "rt-tokio")]
49mod tokio {
50 use core::future::Future;
51 use core::time::Duration;
52
53 use super::{MaybeSend, Runtime};
54
55 #[derive(Clone, Debug)]
57 pub struct TokioRuntime {
58 handle: ::tokio::runtime::Handle,
59 }
60
61 impl TokioRuntime {
62 #[must_use]
68 pub fn current() -> Self {
69 Self::from_handle(::tokio::runtime::Handle::current())
70 }
71
72 #[must_use]
74 pub fn from_handle(handle: ::tokio::runtime::Handle) -> Self {
75 Self { handle }
76 }
77 }
78
79 impl Runtime for TokioRuntime {
80 fn spawn<F>(&self, future: F)
81 where
82 F: Future<Output = ()> + MaybeSend + 'static,
83 {
84 drop(self.handle.spawn(future));
85 }
86
87 fn sleep(&self, duration: Duration) -> impl Future<Output = ()> + MaybeSend {
88 let _guard = self.handle.enter();
89 ::tokio::time::sleep(duration)
90 }
91 }
92
93 #[cfg(test)]
94 mod tests {
95 use core::time::Duration;
96
97 use super::{Runtime, TokioRuntime};
98
99 #[tokio::test]
100 async fn spawn_runs_the_future() {
101 let (tx, rx) = ::tokio::sync::oneshot::channel();
102 TokioRuntime::current().spawn(async move {
103 tx.send(42).expect("receiver alive");
104 });
105 assert_eq!(rx.await.expect("task ran"), 42);
106 }
107
108 #[tokio::test(start_paused = true)]
109 async fn sleep_waits_for_the_duration() {
110 let start = ::tokio::time::Instant::now();
111 TokioRuntime::current().sleep(Duration::from_secs(5)).await;
112 assert!(start.elapsed() >= Duration::from_secs(5));
113 }
114 }
115}
116
117#[cfg(all(feature = "rt-wasm", target_arch = "wasm32"))]
118mod wasm {
119 use core::future::Future;
120 use core::time::Duration;
121
122 use super::{MaybeSend, Runtime};
123
124 #[derive(Clone, Copy, Debug, Default)]
126 pub struct WasmRuntime;
127
128 impl Runtime for WasmRuntime {
129 fn spawn<F>(&self, future: F)
130 where
131 F: Future<Output = ()> + MaybeSend + 'static,
132 {
133 wasm_bindgen_futures::spawn_local(future);
134 }
135
136 fn sleep(&self, duration: Duration) -> impl Future<Output = ()> + MaybeSend {
137 gloo_timers::future::sleep(duration)
138 }
139 }
140}