blob: f671a0cc5d7996cdcc67e9a619ba05b1291b6623 [file] [log] [blame]
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! An Executor and future combinators based on operations that block on file descriptors.
//!
//! This crate is meant to be used with the `futures-rs` crate that provides further combinators
//! and utility functions to combine and manage futures. All futures will run until they block on a
//! file descriptor becoming readable or writable. Facilities are provided to register future
//! wakers based on such events.
//!
//! # Running top-level futures.
//!
//! Use helper functions based the desired behavior of your application.
//!
//! ## Completing one of several futures.
//!
//! If there are several top level tasks that should run until any one completes, use the "select"
//! family of executor constructors. These return an [`Executor`](trait.Executor.html) whose `run`
//! function will return when the first future completes. The uncompleted futures will also be
//! returned so they can be run further or otherwise cleaned up. These functions are inspired by
//! the `select_all` function from futures-rs, but built to be run inside an FD based executor and
//! to poll only when necessary. See the docs for [`select2`](fn.select2.html),
//! [`select3`](fn.select3.html), [`select4`](fn.select4.html), and [`select5`](fn.select5.html).
//!
//! ## Completing all of several futures.
//!
//! If there are several top level tasks that all need to be completed, use the "complete" family
//! of executor constructors. These return an [`Executor`](trait.Executor.html) whose `run`
//! function will return only once all the futures passed to it have completed. These functions are
//! inspired by the `join_all` function from futures-rs, but built to be run inside an FD based
//! executor and to poll only when necessary. See the docs for [`complete2`](fn.complete2.html),
//! [`complete3`](fn.complete3.html), [`complete4`](fn.complete4.html), and
//! [`complete5`](fn.complete5.html).
//!
//! ## Many futures all returning `()`
//!
//! It there are futures that produce side effects and return `()`, the
//! [`empty_executor`](fn.empty_executor.html) function provides an Executor that runs futures
//! returning `()`. Futures are added using the [`add_future`](fn.add_future.html) function.
//!
//! # Implementing new FD-based futures.
//!
//! When building futures to be run in an `FdExecutor` framework, use the following helper
//! functions to perform common tasks:
//!
//! [`add_read_waker`](fn.add_read_waker.html) - Used to associate a provided FD becoming readable
//! with the future being woken. Used before returning Poll::Pending from a future that waits until
//! an FD is writable.
//!
//! [`add_write_waker`](fn.add_write_waker.html) - Used to associate a provided FD becoming
//! writable with the future being woken. Used before returning Poll::Pending from a future that
//! waits until an FD is readable.
//!
//! [`add_future`](fn.add_future.html) - Used to add a new future to the top-level list of running
//! futures.
mod complete;
mod executor;
pub mod fd_executor;
mod select;
mod waker;
pub use executor::Executor;
pub use select::SelectResult;
use executor::UnitFutures;
use fd_executor::{FdExecutor, Result};
use std::future::Future;
/// Creates an empty FdExecutor that can have futures returning `()` added via
/// [`add_future`](fn.add_future.html).
///
/// # Example
///
/// ```
/// use cros_async::{empty_executor, Executor};
/// use cros_async::fd_executor::add_future;
/// use futures::future::pending;
///
/// let fut = async { () };
/// let mut ex = empty_executor().expect("Failed to create executor");
///
/// add_future(Box::pin(fut));
/// ex.run();
/// ```
pub fn empty_executor() -> Result<impl Executor> {
FdExecutor::new(UnitFutures::new())
}
// Select helpers to run until any future completes.
/// Creates an executor that runs the two given futures until one completes, returning a tuple
/// containing the result of the finished future and the still pending future.
///
/// # Example
///
/// ```
/// use cros_async::{empty_executor, Executor, select2, SelectResult};
/// use cros_async::fd_executor::add_future;
/// use futures::future::pending;
/// use futures::pin_mut;
///
/// let first = async {5};
/// let second = async {let () = pending().await;};
/// pin_mut!(first);
/// pin_mut!(second);
/// match select2(first, second) {
/// Ok((SelectResult::Finished(5), SelectResult::Pending(_second))) => (),
/// _ => panic!("Select didn't return the first future"),
/// };
/// ```
pub fn select2<F1: Future + Unpin, F2: Future + Unpin>(
f1: F1,
f2: F2,
) -> Result<(SelectResult<F1>, SelectResult<F2>)> {
FdExecutor::new(select::Select2::new(f1, f2)).and_then(|mut f| f.run())
}
/// Creates an executor that runs the three given futures until one or more completes, returning a
/// tuple containing the result of the finished future(s) and the still pending future(s).
///
/// # Example
///
/// ```
/// use cros_async::{empty_executor, Executor, select3, SelectResult};
/// use cros_async::fd_executor::add_future;
/// use futures::future::pending;
/// use futures::pin_mut;
///
/// let first = async {4};
/// let second = async {let () = pending().await;};
/// let third = async {5};
/// pin_mut!(first);
/// pin_mut!(second);
/// pin_mut!(third);
/// match select3(first, second, third) {
/// Ok((SelectResult::Finished(4),
/// SelectResult::Pending(_second),
/// SelectResult::Finished(5))) => (),
/// _ => panic!("Select didn't return the futures"),
/// };
/// ```
pub fn select3<F1: Future + Unpin, F2: Future + Unpin, F3: Future + Unpin>(
f1: F1,
f2: F2,
f3: F3,
) -> Result<(SelectResult<F1>, SelectResult<F2>, SelectResult<F3>)> {
FdExecutor::new(select::Select3::new(f1, f2, f3)).and_then(|mut f| f.run())
}
/// Creates an executor that runs the four given futures until one or more completes, returning a
/// tuple containing the result of the finished future(s) and the still pending future(s).
///
/// # Example
///
/// ```
/// use cros_async::{empty_executor, Executor, select4, SelectResult};
/// use cros_async::fd_executor::add_future;
/// use futures::future::pending;
/// use futures::pin_mut;
///
/// let first = async {4};
/// let second = async {let () = pending().await;};
/// let third = async {5};
/// let fourth = async {let () = pending().await;};
/// pin_mut!(first);
/// pin_mut!(second);
/// pin_mut!(third);
/// pin_mut!(fourth);
/// match select4(first, second, third, fourth) {
/// Ok((SelectResult::Finished(4), SelectResult::Pending(_second),
/// SelectResult::Finished(5), SelectResult::Pending(_fourth))) => (),
/// _ => panic!("Select didn't return the futures"),
/// };
/// ```
pub fn select4<F1: Future + Unpin, F2: Future + Unpin, F3: Future + Unpin, F4: Future + Unpin>(
f1: F1,
f2: F2,
f3: F3,
f4: F4,
) -> Result<(
SelectResult<F1>,
SelectResult<F2>,
SelectResult<F3>,
SelectResult<F4>,
)> {
FdExecutor::new(select::Select4::new(f1, f2, f3, f4)).and_then(|mut f| f.run())
}
/// Creates an executor that runs the five given futures until one or more completes, returning a
/// tuple containing the result of the finished future(s) and the still pending future(s).
///
/// # Example
///
/// ```
/// use cros_async::{empty_executor, Executor, select5, SelectResult};
/// use cros_async::fd_executor::add_future;
/// use futures::future::pending;
/// use futures::pin_mut;
///
/// let first = async {4};
/// let second = async {let () = pending().await;};
/// let third = async {5};
/// let fourth = async {let () = pending().await;};
/// let fifth = async {6};
/// pin_mut!(first);
/// pin_mut!(second);
/// pin_mut!(third);
/// pin_mut!(fourth);
/// pin_mut!(fifth);
/// match select5(first, second, third, fourth, fifth) {
/// Ok((SelectResult::Finished(4), SelectResult::Pending(_second),
/// SelectResult::Finished(5), SelectResult::Pending(_fourth),
/// SelectResult::Finished(6))) => (),
/// _ => panic!("Select didn't return the futures"),
/// };
/// ```
pub fn select5<
F1: Future + Unpin,
F2: Future + Unpin,
F3: Future + Unpin,
F4: Future + Unpin,
F5: Future + Unpin,
>(
f1: F1,
f2: F2,
f3: F3,
f4: F4,
f5: F5,
) -> Result<(
SelectResult<F1>,
SelectResult<F2>,
SelectResult<F3>,
SelectResult<F4>,
SelectResult<F5>,
)> {
FdExecutor::new(select::Select5::new(f1, f2, f3, f4, f5)).and_then(|mut f| f.run())
}
// Combination helpers to run until all futures are complete.
/// Creates an executor that runs the two given futures to completion, returning a tuple of the
/// outputs each yields.
///
/// # Example
///
/// ```
/// use cros_async::{empty_executor, Executor, complete2};
/// use futures::pin_mut;
///
/// let first = async {5};
/// let second = async {6};
/// pin_mut!(first);
/// pin_mut!(second);
/// assert_eq!(complete2(first, second).unwrap_or((0,0)), (5,6));
/// ```
pub fn complete2<F1: Future + Unpin, F2: Future + Unpin>(
f1: F1,
f2: F2,
) -> Result<(F1::Output, F2::Output)> {
FdExecutor::new(complete::Complete2::new(f1, f2)).and_then(|mut f| f.run())
}
/// Creates an executor that runs the three given futures to completion, returning a tuple of the
/// outputs each yields.
///
/// # Example
///
/// ```
/// use cros_async::{empty_executor, Executor, complete3};
/// use futures::pin_mut;
///
/// let first = async {5};
/// let second = async {6};
/// let third = async {7};
/// pin_mut!(first);
/// pin_mut!(second);
/// pin_mut!(third);
/// assert_eq!(complete3(first, second, third).unwrap_or((0,0,0)), (5,6,7));
/// ```
pub fn complete3<F1: Future + Unpin, F2: Future + Unpin, F3: Future + Unpin>(
f1: F1,
f2: F2,
f3: F3,
) -> Result<(F1::Output, F2::Output, F3::Output)> {
FdExecutor::new(complete::Complete3::new(f1, f2, f3)).and_then(|mut f| f.run())
}
/// Creates an executor that runs the four given futures to completion, returning a tuple of the
/// outputs each yields.
///
/// # Example
///
/// ```
/// use cros_async::{empty_executor, Executor, complete4};
/// use futures::pin_mut;
///
/// let first = async {5};
/// let second = async {6};
/// let third = async {7};
/// let fourth = async {8};
/// pin_mut!(first);
/// pin_mut!(second);
/// pin_mut!(third);
/// pin_mut!(fourth);
/// assert_eq!(complete4(first, second, third, fourth).unwrap_or((0,0,0,0)), (5,6,7,8));
/// ```
pub fn complete4<F1: Future + Unpin, F2: Future + Unpin, F3: Future + Unpin, F4: Future + Unpin>(
f1: F1,
f2: F2,
f3: F3,
f4: F4,
) -> Result<(F1::Output, F2::Output, F3::Output, F4::Output)> {
FdExecutor::new(complete::Complete4::new(f1, f2, f3, f4)).and_then(|mut f| f.run())
}
/// Creates an executor that runs the five given futures to completion, returning a tuple of the
/// outputs each yields.
///
/// # Example
///
/// ```
/// use cros_async::{empty_executor, Executor, complete5};
/// use futures::pin_mut;
///
/// let first = async {5};
/// let second = async {6};
/// let third = async {7};
/// let fourth = async {8};
/// let fifth = async {9};
/// pin_mut!(first);
/// pin_mut!(second);
/// pin_mut!(third);
/// pin_mut!(fourth);
/// pin_mut!(fifth);
/// assert_eq!(complete5(first, second, third, fourth, fifth).unwrap_or((0,0,0,0,0)),
/// (5,6,7,8,9));
/// ```
pub fn complete5<
F1: Future + Unpin,
F2: Future + Unpin,
F3: Future + Unpin,
F4: Future + Unpin,
F5: Future + Unpin,
>(
f1: F1,
f2: F2,
f3: F3,
f4: F4,
f5: F5,
) -> Result<(F1::Output, F2::Output, F3::Output, F4::Output, F5::Output)> {
FdExecutor::new(complete::Complete5::new(f1, f2, f3, f4, f5)).and_then(|mut f| f.run())
}