aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2019-10-24 05:46:43 -0400
committerJesse Luehrs <doy@tozt.net>2019-10-24 05:52:11 -0400
commitf6d4219c8edb60741d5a5596b097ebb9722d04fc (patch)
tree3de3b0e957b8d5c24a3f50ab9a0b72803d7444b7 /src
parenta20cae5670f20902379a7098d54e2a9c78b864cd (diff)
downloadcomponent-future-f6d4219c8edb60741d5a5596b097ebb9722d04fc.tar.gz
component-future-f6d4219c8edb60741d5a5596b097ebb9722d04fc.zip
add docs
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs199
1 files changed, 185 insertions, 14 deletions
diff --git a/src/lib.rs b/src/lib.rs
index a4e483e..cf21031 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,34 +1,145 @@
+//! This crate implements the inner future protocol documented in [the tokio
+//! docs](https://tokio.rs/docs/futures/getting_asynchronous/).
+//!
+//! # Overview
+//!
+//! If you are implementing a complicated future or stream which contains many
+//! inner futures and streams, it can be difficult to keep track of when
+//! looping is necessary, when it is safe to return `NotReady`, etc. This
+//! provides an interface similar to the existing `poll` interface for futures
+//! and streams, but extended to include additional state about how the inner
+//! future or stream affected the outer future or stream's state. This allows
+//! you to easily split your `poll` implementation into multiple methods, and
+//! ensure that they interact properly.
+//!
+//! # Synopsis
+//!
+//! ```
+//! enum OutputEvent {
+//! // ...
+//! }
+//!
+//! struct Server {
+//! // ...
+//! # some_future: Box<
+//! # dyn futures::future::Future<Item = OutputEvent, Error = String>
+//! # + Send,
+//! # >,
+//! # other_future: Option<
+//! # Box<
+//! # dyn futures::future::Future<Item = OutputEvent, Error = String>
+//! # + Send,
+//! # >,
+//! # >,
+//! }
+//!
+//! impl Server {
+//! fn process_thing(&self, thing: OutputEvent) {
+//! // ...
+//! }
+//!
+//! fn process_other_thing(&self, thing: OutputEvent) -> OutputEvent {
+//! // ...
+//! # unimplemented!()
+//! }
+//! }
+//!
+//! impl Server {
+//! const POLL_FNS:
+//! &'static [&'static dyn for<'a> Fn(
+//! &'a mut Self,
+//! )
+//! -> component_future::Poll<
+//! Option<OutputEvent>,
+//! String,
+//! >] = &[&Self::poll_thing, &Self::poll_other_thing];
+//!
+//! fn poll_thing(
+//! &mut self,
+//! ) -> component_future::Poll<Option<OutputEvent>, String> {
+//! let thing = component_future::try_ready!(self.some_future.poll());
+//! self.process_thing(thing);
+//! Ok(component_future::Async::DidWork)
+//! }
+//!
+//! fn poll_other_thing(
+//! &mut self,
+//! ) -> component_future::Poll<Option<OutputEvent>, String> {
+//! if let Some(other_future) = &mut self.other_future {
+//! let other_thing = component_future::try_ready!(
+//! other_future.poll()
+//! );
+//! let processed_thing = self.process_other_thing(other_thing);
+//! self.other_future.take();
+//! Ok(component_future::Async::Ready(Some(processed_thing)))
+//! }
+//! else {
+//! Ok(component_future::Async::NothingToDo)
+//! }
+//! }
+//! }
+//!
+//! impl futures::stream::Stream for Server {
+//! type Item = OutputEvent;
+//! type Error = String;
+//!
+//! fn poll(&mut self) -> futures::Poll<Option<Self::Item>, Self::Error> {
+//! component_future::poll_stream(self, Self::POLL_FNS)
+//! }
+//! }
+//! ```
+
#![warn(clippy::pedantic)]
#![warn(clippy::nursery)]
#![allow(clippy::type_complexity)]
+/// Return type of a component of a future or stream, indicating whether a
+/// value is ready, or if not, what actions were taken.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Async<Item> {
- // we have a value for the main loop to return immediately.
+ /// We have a value for the main loop to return immediately.
Ready(Item),
- // one of our inner futures returned futures::Async::NotReady. if all
- // of our other components return either NothingToDo or NotReady, then our
- // overall future should return NotReady and wait to be polled again.
+ /// One of our inner futures returned `futures::Async::NotReady`. If all
+ /// of our other components return either `NothingToDo` or `NotReady`,
+ /// then our overall future should return `NotReady` and wait to be polled
+ /// again.
NotReady,
- // we did some work (moved our internal state closer to being ready to
- // return a value), but we aren't ready to return a value yet. we should
- // re-run all of the poll functions to see if the state modification made
- // any of them also able to make progress.
+ /// We did some work (moved our internal state closer to being ready to
+ /// return a value), but we aren't ready to return a value yet. We should
+ /// re-run all of the poll functions to see if the state modification made
+ /// any of them also able to make progress.
DidWork,
- // we didn't poll any inner futures or otherwise change our internal state
- // at all, so rerunning is unlikely to make progress. if all components
- // return either NothingToDo or NotReady (and at least one returned
- // NotReady), then we should just return NotReady and wait to be polled
- // again. it is an error (panic) for all component poll methods to return
- // NothingToDo.
+ /// We didn't poll any inner futures or otherwise change our internal
+ /// state at all, so rerunning is unlikely to make progress. If all
+ /// components return either `NothingToDo` or `NotReady` (and at least one
+ /// returns `NotReady`), then we should just return `NotReady` and wait to
+ /// be polled again. It is an error (panic) for all component poll methods
+ /// to return `NothingToDo`.
NothingToDo,
}
+/// Each component poll method should return a value of this type.
+///
+/// * `Ok(Async::Ready(t))` means that the overall future or stream is ready
+/// to return a value.
+/// * `Ok(Async::NotReady)` means that a poll method called by one of the
+/// component futures or streams returned `NotReady`, and so it's safe for
+/// the overall future or stream to also return `NotReady`.
+/// * `Ok(Async::DidWork)` means that the overall future made progress by
+/// updating its internal state, but isn't yet ready to return a value.
+/// * `Ok(Async::NothingToDo)` means that no work was done at all.
+/// * `Err(e)` means that the overall future or stream is ready to return an
+/// error.
pub type Poll<Item, Error> = Result<Async<Item>, Error>;
+/// A macro for extracting the successful type of a `futures::Poll<T, E>` and
+/// turning it into a `component_future::Poll<T, E>`.
+///
+/// This macro propagates both errors and `NotReady` values by returning
+/// early.
#[macro_export]
macro_rules! try_ready {
($e:expr) => {
@@ -42,6 +153,36 @@ macro_rules! try_ready {
};
}
+/// The body of a `futures::future::Future::poll` method.
+///
+/// It will repeatedly call the given component poll functions until none of
+/// them returns `Ok(Async::Ready(t))`, `Ok(Async::DidWork)`, or `Err(e)` and
+/// at least one of them returns `Ok(Async::NotReady)`.
+///
+/// # Panics
+///
+/// Panics if all component poll methods return `Ok(Async::NothingToDo)`.
+///
+/// # Examples
+///
+/// ```
+/// # use futures::future::Future;
+/// # struct Foo;
+/// # impl Foo {
+/// # const POLL_FNS:
+/// # &'static [&'static dyn for<'a> Fn(
+/// # &'a mut Self,
+/// # ) -> component_future::Poll<(), ()>] = &[];
+/// # }
+/// impl Future for Foo {
+/// type Item = ();
+/// type Error = ();
+///
+/// fn poll(&mut self) -> futures::Poll<Self::Item, Self::Error> {
+/// component_future::poll_future(self, Self::POLL_FNS)
+/// }
+/// }
+/// ```
pub fn poll_future<T, Item, Error>(
future: &mut T,
poll_fns: &'static [&'static dyn for<'a> Fn(
@@ -74,6 +215,36 @@ where
}
}
+/// The body of a `futures::stream::Stream::poll` method.
+///
+/// It will repeatedly call the given component poll functions until none of
+/// them returns `Ok(Async::Ready(t))`, `Ok(Async::DidWork)`, or `Err(e)` and
+/// at least one of them returns `Ok(Async::NotReady)`.
+///
+/// # Panics
+///
+/// Panics if all component poll methods return `Ok(Async::NothingToDo)`.
+///
+/// # Examples
+///
+/// ```
+/// # use futures::stream::Stream;
+/// # struct Foo;
+/// # impl Foo {
+/// # const POLL_FNS:
+/// # &'static [&'static dyn for<'a> Fn(
+/// # &'a mut Self,
+/// # ) -> component_future::Poll<Option<()>, ()>] = &[];
+/// # }
+/// impl Stream for Foo {
+/// type Item = ();
+/// type Error = ();
+///
+/// fn poll(&mut self) -> futures::Poll<Option<Self::Item>, Self::Error> {
+/// component_future::poll_stream(self, Self::POLL_FNS)
+/// }
+/// }
+/// ```
pub fn poll_stream<T, Item, Error>(
stream: &mut T,
poll_fns: &'static [&'static dyn for<'a> Fn(