From 4f2e13a8008e11d9498fcb38f5315b51aa908a66 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Wed, 23 Oct 2019 11:33:53 -0400 Subject: copy over the basic implementation from teleterm --- .rustfmt.toml | 1 + Cargo.toml | 3 +- src/lib.rs | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 109 insertions(+), 7 deletions(-) create mode 100644 .rustfmt.toml diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 0000000..bcad605 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1 @@ +max_width = 78 diff --git a/Cargo.toml b/Cargo.toml index aee64b6..0a9f315 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,5 @@ version = "0.1.0" authors = ["Jesse Luehrs "] edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] +futures = "0.1" diff --git a/src/lib.rs b/src/lib.rs index 31e1bb2..e49a5fb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,109 @@ -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); +#![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!() + } + } } } -- cgit v1.2.3