#![warn(clippy::pedantic)] #![warn(clippy::nursery)] #![allow(clippy::type_complexity)] pub enum Async { // 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. 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. 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. NothingToDo, } pub type Poll = Result, Error>; #[macro_export] macro_rules! try_ready { ($e:expr) => { match $e { Ok(futures::Async::Ready(t)) => t, Ok(futures::Async::NotReady) => { return Ok($crate::Async::NotReady) } Err(e) => return Err(From::from(e)), } }; } pub fn poll_future( future: &mut T, poll_fns: &'static [&'static dyn for<'a> Fn( &'a mut T, ) -> Poll], ) -> futures::Poll where T: futures::future::Future, { loop { let mut not_ready = false; let mut did_work = false; for f in poll_fns { match f(future)? { Async::Ready(e) => return Ok(futures::Async::Ready(e)), Async::NotReady => not_ready = true, Async::NothingToDo => {} Async::DidWork => did_work = true, } } if !did_work { if not_ready { return Ok(futures::Async::NotReady); } else { unreachable!() } } } } pub fn poll_stream( stream: &mut T, poll_fns: &'static [&'static dyn for<'a> Fn( &'a mut T, ) -> Poll< Option, Error, >], ) -> futures::Poll, Error> where T: futures::stream::Stream, { loop { let mut not_ready = false; let mut did_work = false; for f in poll_fns { match f(stream)? { Async::Ready(e) => return Ok(futures::Async::Ready(e)), Async::NotReady => not_ready = true, Async::NothingToDo => {} Async::DidWork => did_work = true, } } if !did_work { if not_ready { return Ok(futures::Async::NotReady); } else { unreachable!() } } } }