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_async_std {
43 ($($item:item)*) => {
44 $(
45 #[cfg(feature = "async-std")]
46 #[cfg_attr(docsrs, doc(cfg(feature = "async-std")))]
47 $item
48 )*
49 };
50 (@no_doc_cfg $($item:item)*) => {
51 $(
52 #[cfg(feature = "async-std")]
53 $item
54 )*
55 };
56}
57
58#[macro_export]
60macro_rules! cfg_tokio {
61 ($($item:item)*) => {
62 $(
63 #[cfg(feature = "tokio")]
64 #[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
65 $item
66 )*
67 };
68 (@no_doc_cfg $($item:item)*) => {
69 $(
70 #[cfg(feature = "tokio")]
71 $item
72 )*
73 };
74}
75
76#[macro_export]
78macro_rules! cfg_smol {
79 ($($item:item)*) => {
80 $(
81 #[cfg(feature = "smol")]
82 #[cfg_attr(docsrs, doc(cfg(feature = "smol")))]
83 $item
84 )*
85 };
86 (@no_doc_cfg $($item:item)*) => {
87 $(
88 #[cfg(feature = "smol")]
89 $item
90 )*
91 };
92}
93
94#[macro_export]
96macro_rules! cfg_unix {
97 ($($item:item)*) => {
98 $(
99 #[cfg(feature = "unix")]
100 #[cfg_attr(docsrs, doc(cfg(feature = "unix")))]
101 $item
102 )*
103 };
104 (@no_doc_cfg $($item:item)*) => {
105 $(
106 #[cfg(feature = "unix")]
107 $item
108 )*
109 };
110}
111
112#[macro_export]
114macro_rules! cfg_windows {
115 ($($item:item)*) => {
116 $(
117 #[cfg(feature = "windows")]
118 #[cfg_attr(docsrs, doc(cfg(feature = "windows")))]
119 $item
120 )*
121 };
122 (@no_doc_cfg $($item:item)*) => {
123 $(
124 #[cfg(feature = "windows")]
125 $item
126 )*
127 };
128}
129
130#[macro_export]
132macro_rules! cfg_linux {
133 ($($item:item)*) => {
134 $(
135 #[cfg(target_os = "linux")]
136 #[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
137 $item
138 )*
139 };
140 (@no_doc_cfg $($item:item)*) => {
141 $(
142 #[cfg(target_os = "linux")]
143 $item
144 )*
145 };
146}
147
148#[macro_use]
149mod spawner;
150
151#[cfg(feature = "tokio")]
155#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
156pub mod tokio;
157
158#[cfg(feature = "async-std")]
162#[cfg_attr(docsrs, doc(cfg(feature = "async-std")))]
163pub mod async_std;
164
165#[cfg(feature = "smol")]
169#[cfg_attr(docsrs, doc(cfg(feature = "smol")))]
170pub mod smol;
171
172#[cfg(feature = "wasm")]
176#[cfg_attr(docsrs, doc(cfg(feature = "wasm")))]
177pub mod wasm;
178
179#[cfg(feature = "async-io")]
184#[cfg_attr(docsrs, doc(cfg(feature = "async-io")))]
185pub mod async_io;
186
187pub use spawner::*;
188
189pub trait Yielder {
191 fn yield_now() -> impl Future<Output = ()> + Send;
193
194 fn yield_now_local() -> impl Future<Output = ()>;
196}
197
198pub trait RuntimeLite: Sized + Unpin + Copy + Send + Sync + 'static {
200 type Spawner: AsyncSpawner;
202 type LocalSpawner: AsyncLocalSpawner;
204 type BlockingSpawner: AsyncBlockingSpawner;
206
207 cfg_time_with_docsrs!(
208 type Instant: time::Instant;
210
211 type AfterSpawner: AsyncAfterSpawner<Instant = Self::Instant>;
213
214 type Interval: time::AsyncInterval<Instant = Self::Instant>;
216
217 type LocalInterval: time::AsyncLocalInterval<Instant = Self::Instant>;
219
220 type Sleep: time::AsyncSleep<Instant = Self::Instant>;
222
223 type LocalSleep: time::AsyncLocalSleep<Instant = Self::Instant>;
225
226 type Delay<F>: time::AsyncDelay<F, Instant = Self::Instant>
228 where
229 F: Future + Send;
230
231 type LocalDelay<F>: time::AsyncLocalDelay<F, Instant = Self::Instant>
233 where
234 F: Future;
235
236 type Timeout<F>: time::AsyncTimeout<F, Instant = Self::Instant>
238 where
239 F: Future + Send;
240
241 type LocalTimeout<F>: time::AsyncLocalTimeout<F, Instant = Self::Instant>
243 where
244 F: Future;
245 );
246
247 fn new() -> Self;
249
250 fn name() -> &'static str;
254
255 fn fqname() -> &'static str;
259
260 fn spawn<F>(future: F) -> <Self::Spawner as AsyncSpawner>::JoinHandle<F::Output>
262 where
263 F::Output: Send + 'static,
264 F: Future + Send + 'static,
265 {
266 <Self::Spawner as AsyncSpawner>::spawn(future)
267 }
268
269 fn spawn_detach<F>(future: F)
271 where
272 F::Output: Send + 'static,
273 F: Future + Send + 'static,
274 {
275 <Self::Spawner as AsyncSpawner>::spawn_detach(future);
276 }
277
278 fn spawn_local<F>(future: F) -> <Self::LocalSpawner as AsyncLocalSpawner>::JoinHandle<F::Output>
280 where
281 F: Future + 'static,
282 F::Output: 'static,
283 {
284 <Self::LocalSpawner as AsyncLocalSpawner>::spawn_local(future)
285 }
286
287 fn spawn_local_detach<F>(future: F)
289 where
290 F: Future + 'static,
291 F::Output: 'static,
292 {
293 <Self::LocalSpawner as AsyncLocalSpawner>::spawn_local_detach(future)
294 }
295
296 fn spawn_blocking<F, R>(f: F) -> <Self::BlockingSpawner as AsyncBlockingSpawner>::JoinHandle<R>
298 where
299 F: FnOnce() -> R + Send + 'static,
300 R: Send + 'static,
301 {
302 <Self::BlockingSpawner as AsyncBlockingSpawner>::spawn_blocking(f)
303 }
304
305 fn spawn_blocking_detach<F, R>(f: F)
307 where
308 F: FnOnce() -> R + Send + 'static,
309 R: Send + 'static,
310 {
311 <Self::BlockingSpawner as AsyncBlockingSpawner>::spawn_blocking_detach(f);
312 }
313
314 fn block_on<F: Future>(f: F) -> F::Output;
316
317 fn yield_now() -> impl Future<Output = ()> + Send;
319
320 cfg_time_with_docsrs!(
321 fn now() -> Self::Instant {
323 <Self::Instant as time::Instant>::now()
324 }
325
326 fn spawn_after<F>(
328 duration: core::time::Duration,
329 future: F,
330 ) -> <Self::AfterSpawner as AsyncAfterSpawner>::JoinHandle<F::Output>
331 where
332 F::Output: Send + 'static,
333 F: Future + Send + 'static,
334 {
335 <Self::AfterSpawner as AsyncAfterSpawner>::spawn_after(duration, future)
336 }
337
338 fn spawn_after_at<F>(
340 at: Self::Instant,
341 future: F,
342 ) -> <Self::AfterSpawner as AsyncAfterSpawner>::JoinHandle<F::Output>
343 where
344 F::Output: Send + 'static,
345 F: Future + Send + 'static,
346 {
347 <Self::AfterSpawner as AsyncAfterSpawner>::spawn_after_at(at, future)
348 }
349
350 fn interval(interval: core::time::Duration) -> Self::Interval;
353
354 fn interval_at(start: Self::Instant, period: core::time::Duration) -> Self::Interval;
357
358 fn interval_local(interval: core::time::Duration) -> Self::LocalInterval;
361
362 fn interval_local_at(start: Self::Instant, period: core::time::Duration)
365 -> Self::LocalInterval;
366
367 fn sleep(duration: core::time::Duration) -> Self::Sleep;
370
371 fn sleep_until(instant: Self::Instant) -> Self::Sleep;
374
375 fn sleep_local(duration: core::time::Duration) -> Self::LocalSleep;
378
379 fn sleep_local_until(instant: Self::Instant) -> Self::LocalSleep;
382
383 fn delay<F>(duration: core::time::Duration, fut: F) -> Self::Delay<F>
389 where
390 F: Future + Send;
391
392 fn delay_local<F>(duration: core::time::Duration, fut: F) -> Self::LocalDelay<F>
399 where
400 F: Future;
401
402 fn delay_at<F>(deadline: Self::Instant, fut: F) -> Self::Delay<F>
407 where
408 F: Future + Send;
409
410 fn delay_local_at<F>(deadline: Self::Instant, fut: F) -> Self::LocalDelay<F>
416 where
417 F: Future;
418
419 fn timeout<F>(duration: core::time::Duration, future: F) -> Self::Timeout<F>
423 where
424 F: Future + Send;
425
426 fn timeout_at<F>(deadline: Self::Instant, future: F) -> Self::Timeout<F>
430 where
431 F: Future + Send;
432
433 fn timeout_local<F>(duration: core::time::Duration, future: F) -> Self::LocalTimeout<F>
438 where
439 F: Future;
440
441 fn timeout_local_at<F>(deadline: Self::Instant, future: F) -> Self::LocalTimeout<F>
446 where
447 F: Future;
448 );
449}
450
451#[cfg(all(any(test, feature = "test"), feature = "std"))]
453#[cfg_attr(docsrs, doc(cfg(any(test, feature = "test"))))]
454pub mod tests {
455 use core::sync::atomic::{AtomicUsize, Ordering};
456
457 use std::{sync::Arc, time::Duration};
458
459 use super::{AfterHandle, RuntimeLite};
460
461 pub async fn spawn_after_unittest<R: RuntimeLite>() {
463 let ctr = Arc::new(AtomicUsize::new(1));
464 let ctr1 = ctr.clone();
465 let handle = R::spawn_after(Duration::from_secs(1), async move {
466 ctr1.fetch_add(1, Ordering::SeqCst);
467 });
468
469 R::sleep(Duration::from_millis(500)).await;
470 assert_eq!(ctr.load(Ordering::SeqCst), 1);
471
472 handle.await.unwrap();
473 assert_eq!(ctr.load(Ordering::SeqCst), 2);
474 }
475
476 pub async fn spawn_after_cancel_unittest<R: RuntimeLite>() {
480 let ctr = Arc::new(AtomicUsize::new(1));
481 let ctr1 = ctr.clone();
482 let handle = R::spawn_after(Duration::from_secs(1), async move {
483 ctr1.fetch_add(1, Ordering::SeqCst);
484 });
485
486 R::sleep(Duration::from_millis(500)).await;
487 assert_eq!(ctr.load(Ordering::SeqCst), 1);
488
489 let o = handle.cancel().await;
490 assert!(o.is_none());
491 assert_eq!(ctr.load(Ordering::SeqCst), 1);
492 }
493
494 pub async fn spawn_after_drop_unittest<R: RuntimeLite>() {
498 let ctr = Arc::new(AtomicUsize::new(1));
499 let ctr1 = ctr.clone();
500 drop(R::spawn_after(Duration::from_secs(1), async move {
501 ctr1.fetch_add(1, Ordering::SeqCst);
502 }));
503
504 R::sleep(Duration::from_millis(500)).await;
505 assert_eq!(ctr.load(Ordering::SeqCst), 1);
506
507 R::sleep(Duration::from_millis(600)).await;
508 assert_eq!(ctr.load(Ordering::SeqCst), 2);
509 }
510
511 pub async fn spawn_after_abort_unittest<R: RuntimeLite>() {
515 let ctr = Arc::new(AtomicUsize::new(1));
516 let ctr1 = ctr.clone();
517 let handle = R::spawn_after(Duration::from_secs(1), async move {
518 ctr1.fetch_add(1, Ordering::SeqCst);
519 });
520
521 R::sleep(Duration::from_millis(500)).await;
522 assert_eq!(ctr.load(Ordering::SeqCst), 1);
523
524 handle.abort();
525 R::sleep(Duration::from_millis(600)).await;
526 assert_eq!(ctr.load(Ordering::SeqCst), 1);
527 }
528
529 pub async fn spawn_after_reset_to_pass_unittest<R: RuntimeLite>() {
533 let ctr = Arc::new(AtomicUsize::new(1));
534 let ctr1 = ctr.clone();
535 let handle = R::spawn_after(Duration::from_secs(1), async move {
536 ctr1.fetch_add(1, Ordering::SeqCst);
537 });
538
539 R::sleep(Duration::from_millis(500)).await;
540 assert_eq!(ctr.load(Ordering::SeqCst), 1);
541
542 handle.reset(Duration::from_millis(250));
543 R::sleep(Duration::from_millis(10)).await;
544 assert_eq!(ctr.load(Ordering::SeqCst), 2);
545 }
546
547 pub async fn spawn_after_reset_to_future_unittest<R: RuntimeLite>() {
551 let ctr = Arc::new(AtomicUsize::new(1));
552 let ctr1 = ctr.clone();
553 let handle = R::spawn_after(Duration::from_secs(1), async move {
554 ctr1.fetch_add(1, Ordering::SeqCst);
555 });
556
557 R::sleep(Duration::from_millis(500)).await;
558 assert_eq!(ctr.load(Ordering::SeqCst), 1);
559
560 handle.reset(Duration::from_millis(1250)); R::sleep(Duration::from_millis(750 + 10)).await; assert_eq!(ctr.load(Ordering::SeqCst), 2);
563 }
564}