1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(feature = "std"), no_std)]
3#![forbid(unsafe_code)]
4#![deny(warnings, missing_docs)]
5#![cfg_attr(docsrs, feature(doc_cfg))]
6#![cfg_attr(docsrs, allow(unused_attributes))]
7
8#[cfg(all(feature = "alloc", not(feature = "std")))]
9extern crate alloc as std;
10
11#[cfg(feature = "std")]
12extern crate std;
13
14macro_rules! cfg_time_with_docsrs {
15 ($($item:item)*) => {
16 $(
17 #[cfg(feature = "time")]
18 #[cfg_attr(docsrs, doc(cfg(feature = "time")))]
19 $item
20 )*
21 };
22}
23
24macro_rules! cfg_time {
25 ($($item:item)*) => {
26 $(
27 #[cfg(feature = "time")]
28 $item
29 )*
30 };
31}
32
33use core::future::Future;
34
35cfg_time_with_docsrs!(
36 pub mod time;
38);
39
40#[macro_export]
42macro_rules! cfg_tokio {
43 ($($item:item)*) => {
44 $(
45 #[cfg(feature = "tokio")]
46 #[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
47 $item
48 )*
49 };
50 (@no_doc_cfg $($item:item)*) => {
51 $(
52 #[cfg(feature = "tokio")]
53 $item
54 )*
55 };
56}
57
58#[macro_export]
60macro_rules! cfg_smol {
61 ($($item:item)*) => {
62 $(
63 #[cfg(feature = "smol")]
64 #[cfg_attr(docsrs, doc(cfg(feature = "smol")))]
65 $item
66 )*
67 };
68 (@no_doc_cfg $($item:item)*) => {
69 $(
70 #[cfg(feature = "smol")]
71 $item
72 )*
73 };
74}
75
76#[macro_export]
78macro_rules! cfg_unix {
79 ($($item:item)*) => {
80 $(
81 #[cfg(feature = "unix")]
82 #[cfg_attr(docsrs, doc(cfg(feature = "unix")))]
83 $item
84 )*
85 };
86 (@no_doc_cfg $($item:item)*) => {
87 $(
88 #[cfg(feature = "unix")]
89 $item
90 )*
91 };
92}
93
94#[macro_export]
96macro_rules! cfg_windows {
97 ($($item:item)*) => {
98 $(
99 #[cfg(feature = "windows")]
100 #[cfg_attr(docsrs, doc(cfg(feature = "windows")))]
101 $item
102 )*
103 };
104 (@no_doc_cfg $($item:item)*) => {
105 $(
106 #[cfg(feature = "windows")]
107 $item
108 )*
109 };
110}
111
112#[macro_export]
114macro_rules! cfg_linux {
115 ($($item:item)*) => {
116 $(
117 #[cfg(target_os = "linux")]
118 #[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
119 $item
120 )*
121 };
122 (@no_doc_cfg $($item:item)*) => {
123 $(
124 #[cfg(target_os = "linux")]
125 $item
126 )*
127 };
128}
129
130#[macro_use]
131mod spawner;
132
133#[cfg(feature = "tokio")]
137#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
138pub mod tokio;
139
140#[cfg(feature = "smol")]
144#[cfg_attr(docsrs, doc(cfg(feature = "smol")))]
145pub mod smol;
146
147#[cfg(feature = "wasm")]
151#[cfg_attr(docsrs, doc(cfg(feature = "wasm")))]
152pub mod wasm;
153
154#[cfg(feature = "async-io")]
158#[cfg_attr(docsrs, doc(cfg(feature = "async-io")))]
159pub mod async_io;
160
161pub use spawner::*;
162
163pub trait Yielder {
165 fn yield_now() -> impl Future<Output = ()> + Send;
167
168 fn yield_now_local() -> impl Future<Output = ()>;
170}
171
172pub trait RuntimeLite: Sized + Unpin + Copy + Send + Sync + 'static {
174 type Spawner: AsyncSpawner;
176 type LocalSpawner: AsyncLocalSpawner;
178 type BlockingSpawner: AsyncBlockingSpawner;
180
181 cfg_time_with_docsrs!(
182 type Instant: time::Instant;
184
185 type AfterSpawner: AsyncAfterSpawner<Instant = Self::Instant>;
187
188 type Interval: time::AsyncInterval<Instant = Self::Instant>;
190
191 type LocalInterval: time::AsyncLocalInterval<Instant = Self::Instant>;
193
194 type Sleep: time::AsyncSleep<Instant = Self::Instant>;
196
197 type LocalSleep: time::AsyncLocalSleep<Instant = Self::Instant>;
199
200 type Delay<F>: time::AsyncDelay<F, Instant = Self::Instant>
202 where
203 F: Future + Send;
204
205 type LocalDelay<F>: time::AsyncLocalDelay<F, Instant = Self::Instant>
207 where
208 F: Future;
209
210 type Timeout<F>: time::AsyncTimeout<F, Instant = Self::Instant>
212 where
213 F: Future + Send;
214
215 type LocalTimeout<F>: time::AsyncLocalTimeout<F, Instant = Self::Instant>
217 where
218 F: Future;
219 );
220
221 fn new() -> Self;
223
224 fn name() -> &'static str;
228
229 fn fqname() -> &'static str;
233
234 fn spawn<F>(future: F) -> <Self::Spawner as AsyncSpawner>::JoinHandle<F::Output>
236 where
237 F::Output: Send + 'static,
238 F: Future + Send + 'static,
239 {
240 <Self::Spawner as AsyncSpawner>::spawn(future)
241 }
242
243 fn spawn_detach<F>(future: F)
245 where
246 F::Output: Send + 'static,
247 F: Future + Send + 'static,
248 {
249 <Self::Spawner as AsyncSpawner>::spawn_detach(future);
250 }
251
252 fn spawn_local<F>(future: F) -> <Self::LocalSpawner as AsyncLocalSpawner>::JoinHandle<F::Output>
254 where
255 F: Future + 'static,
256 F::Output: 'static,
257 {
258 <Self::LocalSpawner as AsyncLocalSpawner>::spawn_local(future)
259 }
260
261 fn spawn_local_detach<F>(future: F)
263 where
264 F: Future + 'static,
265 F::Output: 'static,
266 {
267 <Self::LocalSpawner as AsyncLocalSpawner>::spawn_local_detach(future)
268 }
269
270 fn spawn_blocking<F, R>(f: F) -> <Self::BlockingSpawner as AsyncBlockingSpawner>::JoinHandle<R>
272 where
273 F: FnOnce() -> R + Send + 'static,
274 R: Send + 'static,
275 {
276 <Self::BlockingSpawner as AsyncBlockingSpawner>::spawn_blocking(f)
277 }
278
279 fn spawn_blocking_detach<F, R>(f: F)
281 where
282 F: FnOnce() -> R + Send + 'static,
283 R: Send + 'static,
284 {
285 <Self::BlockingSpawner as AsyncBlockingSpawner>::spawn_blocking_detach(f);
286 }
287
288 fn block_on<F: Future>(f: F) -> F::Output;
290
291 fn yield_now() -> impl Future<Output = ()> + Send;
293
294 cfg_time_with_docsrs!(
295 fn now() -> Self::Instant {
297 <Self::Instant as time::Instant>::now()
298 }
299
300 fn spawn_after<F>(
302 duration: core::time::Duration,
303 future: F,
304 ) -> <Self::AfterSpawner as AsyncAfterSpawner>::JoinHandle<F::Output>
305 where
306 F::Output: Send + 'static,
307 F: Future + Send + 'static,
308 {
309 <Self::AfterSpawner as AsyncAfterSpawner>::spawn_after(duration, future)
310 }
311
312 fn spawn_after_at<F>(
314 at: Self::Instant,
315 future: F,
316 ) -> <Self::AfterSpawner as AsyncAfterSpawner>::JoinHandle<F::Output>
317 where
318 F::Output: Send + 'static,
319 F: Future + Send + 'static,
320 {
321 <Self::AfterSpawner as AsyncAfterSpawner>::spawn_after_at(at, future)
322 }
323
324 fn interval(interval: core::time::Duration) -> Self::Interval;
327
328 fn interval_at(start: Self::Instant, period: core::time::Duration) -> Self::Interval;
331
332 fn interval_local(interval: core::time::Duration) -> Self::LocalInterval;
335
336 fn interval_local_at(start: Self::Instant, period: core::time::Duration)
339 -> Self::LocalInterval;
340
341 fn sleep(duration: core::time::Duration) -> Self::Sleep;
344
345 fn sleep_until(instant: Self::Instant) -> Self::Sleep;
348
349 fn sleep_local(duration: core::time::Duration) -> Self::LocalSleep;
352
353 fn sleep_local_until(instant: Self::Instant) -> Self::LocalSleep;
356
357 fn delay<F>(duration: core::time::Duration, fut: F) -> Self::Delay<F>
363 where
364 F: Future + Send;
365
366 fn delay_local<F>(duration: core::time::Duration, fut: F) -> Self::LocalDelay<F>
373 where
374 F: Future;
375
376 fn delay_at<F>(deadline: Self::Instant, fut: F) -> Self::Delay<F>
381 where
382 F: Future + Send;
383
384 fn delay_local_at<F>(deadline: Self::Instant, fut: F) -> Self::LocalDelay<F>
390 where
391 F: Future;
392
393 fn timeout<F>(duration: core::time::Duration, future: F) -> Self::Timeout<F>
397 where
398 F: Future + Send;
399
400 fn timeout_at<F>(deadline: Self::Instant, future: F) -> Self::Timeout<F>
404 where
405 F: Future + Send;
406
407 fn timeout_local<F>(duration: core::time::Duration, future: F) -> Self::LocalTimeout<F>
412 where
413 F: Future;
414
415 fn timeout_local_at<F>(deadline: Self::Instant, future: F) -> Self::LocalTimeout<F>
420 where
421 F: Future;
422 );
423}
424
425#[cfg(all(any(test, feature = "test"), feature = "std"))]
427#[cfg_attr(docsrs, doc(cfg(any(test, feature = "test"))))]
428pub mod tests {
429 use core::sync::atomic::{AtomicUsize, Ordering};
430
431 use std::{sync::Arc, time::Duration};
432
433 use super::{AfterHandle, RuntimeLite};
434
435 pub async fn spawn_after_unittest<R: RuntimeLite>() {
437 let ctr = Arc::new(AtomicUsize::new(1));
438 let ctr1 = ctr.clone();
439 let handle = R::spawn_after(Duration::from_secs(1), async move {
440 ctr1.fetch_add(1, Ordering::SeqCst);
441 });
442
443 R::sleep(Duration::from_millis(500)).await;
444 assert_eq!(ctr.load(Ordering::SeqCst), 1);
445
446 handle.await.unwrap();
447 assert_eq!(ctr.load(Ordering::SeqCst), 2);
448 }
449
450 pub async fn spawn_after_cancel_unittest<R: RuntimeLite>() {
454 let ctr = Arc::new(AtomicUsize::new(1));
455 let ctr1 = ctr.clone();
456 let handle = R::spawn_after(Duration::from_secs(1), async move {
457 ctr1.fetch_add(1, Ordering::SeqCst);
458 });
459
460 R::sleep(Duration::from_millis(500)).await;
461 assert_eq!(ctr.load(Ordering::SeqCst), 1);
462
463 let o = handle.cancel().await;
464 assert!(o.is_none());
465 assert_eq!(ctr.load(Ordering::SeqCst), 1);
466 }
467
468 pub async fn spawn_after_drop_unittest<R: RuntimeLite>() {
472 let ctr = Arc::new(AtomicUsize::new(1));
473 let ctr1 = ctr.clone();
474 drop(R::spawn_after(Duration::from_secs(1), async move {
475 ctr1.fetch_add(1, Ordering::SeqCst);
476 }));
477
478 R::sleep(Duration::from_millis(500)).await;
479 assert_eq!(ctr.load(Ordering::SeqCst), 1);
480
481 R::sleep(Duration::from_millis(600)).await;
482 assert_eq!(ctr.load(Ordering::SeqCst), 2);
483 }
484
485 pub async fn spawn_after_abort_unittest<R: RuntimeLite>() {
489 let ctr = Arc::new(AtomicUsize::new(1));
490 let ctr1 = ctr.clone();
491 let handle = R::spawn_after(Duration::from_secs(1), async move {
492 ctr1.fetch_add(1, Ordering::SeqCst);
493 });
494
495 R::sleep(Duration::from_millis(500)).await;
496 assert_eq!(ctr.load(Ordering::SeqCst), 1);
497
498 handle.abort();
499 R::sleep(Duration::from_millis(600)).await;
500 assert_eq!(ctr.load(Ordering::SeqCst), 1);
501 }
502
503 pub async fn spawn_after_reset_to_pass_unittest<R: RuntimeLite>() {
507 let ctr = Arc::new(AtomicUsize::new(1));
508 let ctr1 = ctr.clone();
509 let handle = R::spawn_after(Duration::from_secs(1), async move {
510 ctr1.fetch_add(1, Ordering::SeqCst);
511 });
512
513 R::sleep(Duration::from_millis(500)).await;
514 assert_eq!(ctr.load(Ordering::SeqCst), 1);
515
516 handle.reset(Duration::from_millis(250));
517 R::sleep(Duration::from_millis(10)).await;
518 assert_eq!(ctr.load(Ordering::SeqCst), 2);
519 }
520
521 pub async fn spawn_after_reset_to_future_unittest<R: RuntimeLite>() {
525 let ctr = Arc::new(AtomicUsize::new(1));
526 let ctr1 = ctr.clone();
527 let handle = R::spawn_after(Duration::from_secs(1), async move {
528 ctr1.fetch_add(1, Ordering::SeqCst);
529 });
530
531 R::sleep(Duration::from_millis(500)).await;
532 assert_eq!(ctr.load(Ordering::SeqCst), 1);
533
534 handle.reset(Duration::from_millis(1250)); R::sleep(Duration::from_millis(750 + 10)).await; assert_eq!(ctr.load(Ordering::SeqCst), 2);
537 }
538}