1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// Copyright 2021 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! An Executor and various primitives for running asynchronous code.
//!
//! This crate is meant to be used with the `futures-rs` crate that provides further combinators
//! and utility functions to combine and manage futures.
//!
//! # Running top-level futures.
//!
//! If there is only one top-level future to run, use the [`Executor::run_until`] method.
//!
//! # Implementations
//!
//! There are currently two paths for asynchronous IO: epoll and io_uring. The io_uring backend may
//! be disabled at compile time. When io_uring support is enabled, the framework performs a runtime
//! check to determine the backend to use.
//!
//! The backend selection should be transparent to the users of this crate.
//!
//! # Concrete async types
//!
//! This crate provides asynchronous versions of various IO types, like [`File`] and [`Event`].
//! Users should use these high-level types to perform asynchronous IO operations.
//!
//! # Thread pools
//!
//! The [`Executor`] supports driving futures simultaneously from multiple threads. To use a thread
//! pool, simply spawn the desired number of threads and call [`Executor::run`] or
//! [`Executor::run_until`] on each thread. Futures spawned via [`Executor::spawn`] may then run on
//! any of the threads in the thread pool.
//!
//! # Global executor
//!
//! This crate deliberately doesn't define a global executor. Instead all methods are implemented
//! directly on the [`Executor`] type. Users who want to use a single global executor for their
//! whole program can easily do so:
//!
//! ```
//! use cros_async::Executor;
//! use once_cell::sync::Lazy;
//! static GLOBAL_EXECUTOR: Lazy<Executor> = Lazy::new(Executor::new);
//!
//! let val = GLOBAL_EXECUTOR.run_until(async { 11 + 23 }).unwrap();
//! assert_eq!(val, 34);
//! ```
//!
//! # Dealing with `!Send` futures
//!
//! Almost all the functions of the async types in this crate are `!Send`. This status is
//! infectious: when one of these futures are `await`ed from another future, that future also
//! becomes `!Send`, which can be quite inconvenient. One way to isolate the `!Send` future is to
//! use [`Executor::spawn_local`] with a [`oneshot::channel`](futures::channel::oneshot::channel):
//!
//! ```
//! use std::mem::size_of;
//!
//! use futures::channel::oneshot::channel;
//! use cros_async::{Executor, File};
//!
//! async fn outer_future_implements_send(ex: Executor, f: File) -> u64 {
//!     let (tx, rx) = channel();
//!     let mut buf = 0x77u64.to_ne_bytes();
//!     ex.spawn_local(async move {
//!         let res = f.read(&mut buf, None).await;
//!         let _ = tx.send((res, buf));
//!     }).detach();
//!
//!     let (res, buf) = rx.await.expect("task canceled after detach()");
//!     assert_eq!(res.unwrap(), size_of::<u64>());
//!     u64::from_ne_bytes(buf)
//! }
//!
//! let ex = Executor::new();
//! let f = File::open("/dev/zero").unwrap();
//!
//! // `spawn` requires that the future implements `Send`.
//! let task = ex.spawn(outer_future_implements_send(ex.clone(), f));
//!
//! let val = ex.run_until(task).unwrap();
//! assert_eq!(val, 0);
//! ```
//!
//! A cancelable version of the inner future can be implemented using
//! [`abortable`](futures::future::abortable). However keep in mind that on backends like io_uring,
//! cancelling the future may not cancel the underlying IO operation.

#![cfg(unix)]

mod blocking;
mod enter;
mod event;
mod executor;
mod file;
mod iobuf;
pub mod sync;
mod timer;

#[cfg_attr(unix, path = "unix/mod.rs")]
mod sys;

pub use blocking::block_on;
pub use blocking::BlockingPool;
pub use event::Event;
pub use executor::Executor;
pub use file::File;
pub use iobuf::AsIoBufs;
pub use iobuf::OwnedIoBuf;
#[cfg(unix)]
pub use sys::Descriptor;
#[cfg(unix)]
pub use sys::SeqPacket as UnixSeqPacket;
#[cfg(unix)]
pub use sys::SeqPacketListener as UnixSeqPacketListener;
pub use timer::with_deadline;
pub use timer::TimedOut;
pub use timer::Timer;