diff options
author | Jesse Luehrs <doy@tozt.net> | 2019-10-24 05:46:43 -0400 |
---|---|---|
committer | Jesse Luehrs <doy@tozt.net> | 2019-10-24 05:52:11 -0400 |
commit | f6d4219c8edb60741d5a5596b097ebb9722d04fc (patch) | |
tree | 3de3b0e957b8d5c24a3f50ab9a0b72803d7444b7 | |
parent | a20cae5670f20902379a7098d54e2a9c78b864cd (diff) | |
download | component-future-f6d4219c8edb60741d5a5596b097ebb9722d04fc.tar.gz component-future-f6d4219c8edb60741d5a5596b097ebb9722d04fc.zip |
add docs
-rw-r--r-- | src/lib.rs | 199 |
1 files changed, 185 insertions, 14 deletions
@@ -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( |