Skip to main content

async_rs/
lib.rs

1#![deny(missing_docs, missing_debug_implementations, unsafe_code)]
2#![warn(unreachable_pub, unused_qualifications, unused_lifetimes)]
3#![warn(
4    clippy::must_use_candidate,
5    clippy::unwrap_in_result,
6    clippy::panic_in_result_fn
7)]
8#![allow(clippy::manual_async_fn)]
9
10//! A Rust async runtime abstraction library.
11//!
12//! Provides a unified [`Runtime`] type and [`traits`] such as [`Executor`](traits::Executor),
13//! [`Reactor`](traits::Reactor), and [`AsyncToSocketAddrs`](traits::AsyncToSocketAddrs) that
14//! abstract over Tokio, smol, and async-global-executor. Features enable implementations and may
15//! be combined. Applications choose a runtime when constructing [`Runtime`]; library crates can
16//! use generic trait bounds to remain runtime-agnostic.
17//!
18//! # Feature flags
19//!
20//! | Flag | Notes |
21//! |------|-------|
22//! | `tokio` *(default)* | Tokio runtime |
23//! | `smol` | smol executor |
24//! | `async-global-executor` | Executor; combine with `async-io` for `AGERuntime` |
25//! | `async-io` | async-io reactor (required by `smol`) |
26//! | `hickory-dns` | Hickory DNS resolver (tokio only) |
27//!
28//! [`NoopRuntime`] is always available without a feature flag.
29//!
30//! An owned Tokio runtime uses nonblocking shutdown when its final owner is dropped while a Tokio
31//! handle is current. This includes a plain `Handle::enter()` scope, so `spawn_blocking` work can
32//! continue after the drop returns. Await work that must finish before dropping the final owner.
33//! On a plain thread, leave the `Handle::enter()` scope first or call
34//! `TokioRuntime::shutdown_blocking()` to wait. The method returns the runtime if another clone
35//! still owns it or it is called from a Tokio task, including a `spawn_blocking` task. Call it
36//! from an ordinary thread, not a runtime worker or an active async executor.
37//!
38//! # Example
39//!
40//! ```rust
41//! # #[cfg(feature="tokio")]
42//! # {
43//! use async_rs::{Runtime, TokioRuntime, traits::*};
44//! use std::{io, time::Duration};
45//!
46//! async fn get_a(rt: &TokioRuntime) -> io::Result<u32> {
47//!     rt.spawn_blocking(|| Ok(12)).await
48//! }
49//!
50//! async fn get_b(rt: &TokioRuntime) -> io::Result<u32> {
51//!     rt.spawn(async { Ok(30) }).await
52//! }
53//!
54//! async fn tokio_main(rt: &TokioRuntime) -> io::Result<()> {
55//!     let a = get_a(rt).await?;
56//!     let b = get_b(rt).await?;
57//!     rt.sleep(Duration::from_millis(500)).await;
58//!     assert_eq!(a + b, 42);
59//!     Ok(())
60//! }
61//!
62//! fn main() -> io::Result<()> {
63//!     let rt = Runtime::tokio()?;
64//!     rt.block_on(tokio_main(&rt))
65//! }
66//! # }
67//! ```
68//!
69//! Note that the `io::Result` above is the *task's own* output: awaiting a
70//! [`Task`](util::Task) leaves no room to report that the task itself failed,
71//! so a task which panicked resumes its panic in the awaiting task, and
72//! awaiting one which was canceled, or whose runtime went away, panics too.
73
74mod runtime;
75pub use runtime::*;
76
77pub mod traits;
78
79mod implementors;
80pub use implementors::*;
81
82pub mod util;
83
84mod sys;