aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2019-10-23 11:33:53 -0400
committerJesse Luehrs <doy@tozt.net>2019-10-24 01:06:22 -0400
commit4f2e13a8008e11d9498fcb38f5315b51aa908a66 (patch)
tree2db8eaba95b519c2f7a48b258093c0c65828684b
parent953b259ccc797df4f486171bb3466503f5851325 (diff)
downloadcomponent-future-4f2e13a8008e11d9498fcb38f5315b51aa908a66.tar.gz
component-future-4f2e13a8008e11d9498fcb38f5315b51aa908a66.zip
copy over the basic implementation from teleterm
-rw-r--r--.rustfmt.toml1
-rw-r--r--Cargo.toml3
-rw-r--r--src/lib.rs112
3 files changed, 109 insertions, 7 deletions
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 <doy@tozt.net>"]
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<Item> {
+ // 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<Item, Error> = Result<Async<Item>, 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<T, Item, Error>(
+ future: &mut T,
+ poll_fns: &'static [&'static dyn for<'a> Fn(
+ &'a mut T,
+ ) -> Poll<Item, Error>],
+) -> futures::Poll<Item, Error>
+where
+ T: futures::future::Future<Item = Item, Error = Error>,
+{
+ 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<T, Item, Error>(
+ stream: &mut T,
+ poll_fns: &'static [&'static dyn for<'a> Fn(
+ &'a mut T,
+ ) -> Poll<
+ Option<Item>,
+ Error,
+ >],
+) -> futures::Poll<Option<Item>, Error>
+where
+ T: futures::stream::Stream<Item = Item, Error = Error>,
+{
+ 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!()
+ }
+ }
}
}