From 9161a9db4362e963812bdcde89dddf9838233eb8 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Mon, 16 Sep 2019 06:37:05 +0200 Subject: [PATCH 1/8] improve readability of macros Signed-off-by: Yoshua Wuyts --- src/join.rs | 14 +++++++++----- src/maybe_done.rs | 14 +++++++------- src/select.rs | 2 +- src/try_join.rs | 46 ++++++++++++++++++++++++++++------------------ src/try_select.rs | 27 +++++++++++++++------------ 5 files changed, 60 insertions(+), 43 deletions(-) diff --git a/src/join.rs b/src/join.rs index 082eded..466f319 100644 --- a/src/join.rs +++ b/src/join.rs @@ -31,17 +31,21 @@ macro_rules! join { let mut $fut = $crate::maybe_done($fut); )* $crate::utils::poll_fn(move |cx| { + use $crate::utils::future::Future; + use $crate::utils::task::Poll; + use $crate::utils::pin::Pin; + let mut all_done = true; $( - all_done &= $crate::utils::future::Future::poll( - unsafe { $crate::utils::pin::Pin::new_unchecked(&mut $fut) }, cx).is_ready(); + let fut = unsafe { Pin::new_unchecked(&mut $fut) }; + all_done &= Future::poll(fut, cx).is_ready(); )* if all_done { - $crate::utils::task::Poll::Ready(($( - unsafe { $crate::utils::pin::Pin::new_unchecked(&mut $fut) }.take_output().unwrap(), + Poll::Ready(($( + unsafe { Pin::new_unchecked(&mut $fut) }.take().unwrap(), )*)) } else { - $crate::utils::task::Poll::Pending + Poll::Pending } }).await } diff --git a/src/maybe_done.rs b/src/maybe_done.rs index 59d934f..0906be0 100644 --- a/src/maybe_done.rs +++ b/src/maybe_done.rs @@ -23,17 +23,17 @@ pub enum MaybeDone { /// The output of the completed future Done(Fut::Output), /// The empty variant after the result of a [`MaybeDone`] has been - /// taken using the [`take_output`](MaybeDone::take_output) method. + /// taken using the [`take`](MaybeDone::take) method. Gone, } impl MaybeDone { /// Returns an [`Option`] containing a mutable reference to the output of the future. /// The output of this method will be [`Some`] if and only if the inner - /// future has been completed and [`take_output`](MaybeDone::take_output) + /// future has been completed and [`take`](MaybeDone::take) /// has not yet been called. #[inline] - pub fn output_mut(self: Pin<&mut Self>) -> Option<&mut Fut::Output> { + pub fn as_mut(self: Pin<&mut Self>) -> Option<&mut Fut::Output> { unsafe { let this = self.get_unchecked_mut(); match this { @@ -45,10 +45,10 @@ impl MaybeDone { /// Returns an [`Option`] containing a reference to the output of the future. /// The output of this method will be [`Some`] if and only if the inner - /// future has been completed and [`take_output`](MaybeDone::take_output) + /// future has been completed and [`take`](MaybeDone::take) /// has not yet been called. #[inline] - pub fn output(self: Pin<&Self>) -> Option<&Fut::Output> { + pub fn as_ref(self: Pin<&Self>) -> Option<&Fut::Output> { let this = self.get_ref(); match this { MaybeDone::Done(res) => Some(res), @@ -59,7 +59,7 @@ impl MaybeDone { /// Attempt to take the output of a `MaybeDone` without driving it /// towards completion. #[inline] - pub fn take_output(self: Pin<&mut Self>) -> Option { + pub fn take(self: Pin<&mut Self>) -> Option { unsafe { let this = self.get_unchecked_mut(); match this { @@ -80,7 +80,7 @@ impl Future for MaybeDone { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let res = unsafe { - match self.as_mut().get_unchecked_mut() { + match Pin::as_mut(&mut self).get_unchecked_mut() { MaybeDone::Future(a) => ready!(Pin::new_unchecked(a).poll(cx)), MaybeDone::Done(_) => return Poll::Ready(()), MaybeDone::Gone => panic!("MaybeDone polled after value taken"), diff --git a/src/select.rs b/src/select.rs index c26df62..50b38c3 100644 --- a/src/select.rs +++ b/src/select.rs @@ -46,7 +46,7 @@ macro_rules! select { let fut = unsafe { Pin::new_unchecked(&mut $fut) }; if Future::poll(fut, cx).is_ready() { let fut = unsafe { Pin::new_unchecked(&mut $fut) }; - let output = fut.take_output().unwrap(); + let output = fut.take().unwrap(); return Poll::Ready(output); } )* diff --git a/src/try_join.rs b/src/try_join.rs index b9b8a7b..ad9fc92 100644 --- a/src/try_join.rs +++ b/src/try_join.rs @@ -43,39 +43,49 @@ macro_rules! try_join { ($($fut:ident),* $(,)?) => { { async { + use $crate::utils::future::Future; + use $crate::utils::pin::Pin; + use $crate::utils::poll_fn; + use $crate::utils::result::Result; + use $crate::utils::task::Poll; + $( // Move future into a local so that it is pinned in one place and // is no longer accessible by the end user. let mut $fut = $crate::maybe_done($fut); )* - let res: $crate::utils::result::Result<_, _> = $crate::utils::poll_fn(move |cx| { + let res: Result<_, _> = poll_fn(move |cx| { let mut all_done = true; $( - if $crate::utils::future::Future::poll( - unsafe { $crate::utils::pin::Pin::new_unchecked(&mut $fut) }, cx).is_pending() - { + let fut = unsafe { Pin::new_unchecked(&mut $fut) }; + if Future::poll(fut, cx).is_pending() { all_done = false; - } else if unsafe { $crate::utils::pin::Pin::new_unchecked(&mut $fut) }.output_mut().unwrap().is_err() { + } else if unsafe { Pin::new_unchecked(&mut $fut) }.as_mut().unwrap().is_err() { // `.err().unwrap()` rather than `.unwrap_err()` so that we don't introduce // a `T: Debug` bound. - return $crate::utils::task::Poll::Ready( - $crate::utils::result::Result::Err( - unsafe { $crate::utils::pin::Pin::new_unchecked(&mut $fut) }.take_output().unwrap().err().unwrap() - ) - ); + return Poll::Ready( + Result::Err(unsafe { Pin::new_unchecked(&mut $fut) } + .take() + .unwrap() + .err() + .unwrap() + )); } )* if all_done { - $crate::utils::task::Poll::Ready( - $crate::utils::result::Result::Ok(($( - // `.ok().unwrap()` rather than `.unwrap()` so that we don't introduce - // an `E: Debug` bound. - unsafe { $crate::utils::pin::Pin::new_unchecked(&mut $fut) }.take_output().unwrap().ok().unwrap(), - )*)) - ) + let res = ($( + // `.ok().unwrap()` rather than `.unwrap()` so that we don't introduce + // an `E: Debug` bound. + unsafe { Pin::new_unchecked(&mut $fut) } + .take() + .unwrap() + .ok() + .unwrap(), + )*); + Poll::Ready(Result::Ok(res)) } else { - $crate::utils::task::Poll::Pending + Poll::Pending } }).await; res diff --git a/src/try_select.rs b/src/try_select.rs index f453425..2c65482 100644 --- a/src/try_select.rs +++ b/src/try_select.rs @@ -19,7 +19,7 @@ /// use futures::future; /// use std::io::{Error, ErrorKind}; /// -/// let a = future::pending::>(); +/// let a = future::pending::>(); /// let b = future::ready(Err(Error::from(ErrorKind::Other))); /// let c = future::ready(Ok(1u8)); /// @@ -33,26 +33,29 @@ macro_rules! try_select { ($($fut:ident),+ $(,)?) => { { async { + use $crate::utils::future::Future; + use $crate::utils::pin::Pin; + use $crate::utils::poll_fn; + use $crate::utils::result::Result; + use $crate::utils::task::Poll; + $( // Move future into a local so that it is pinned in one place and // is no longer accessible by the end user. let mut $fut = $crate::maybe_done($fut); )* - $crate::utils::poll_fn(move |cx| { - use $crate::utils::future::Future; - use $crate::utils::task::Poll; - use $crate::utils::pin::Pin; + let res: Result<_, _> = poll_fn(move |cx| { let mut all_done = true; $( let fut = unsafe { Pin::new_unchecked(&mut $fut) }; if Future::poll(fut, cx).is_ready() { let fut = Pin::new(&$fut); - if fut.output().unwrap().is_ok() { + if fut.as_ref().unwrap().is_ok() { let fut = unsafe { Pin::new_unchecked(&mut $fut) }; - let output = fut.take_output().unwrap(); - return Poll::Ready(output); + let res = fut.take().unwrap(); + return Poll::Ready(res); } else { all_done = false; } @@ -62,20 +65,20 @@ macro_rules! try_select { )* if all_done { - // We need to iterate over all items to not get an - // "unreachable code" warning. + // We need to iterate over all items to get the last error. let mut err = None; $( if err.is_none() { let fut = unsafe { Pin::new_unchecked(&mut $fut) }; - err = Some(fut.take_output().unwrap()); + err = Some(fut.take().unwrap()); } )* return Poll::Ready(err.unwrap()); } else { Poll::Pending } - }).await + }).await; + res } } } } From 8121fb9f6fbe03e79f25b50c05929be002d612a3 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Mon, 16 Sep 2019 07:16:10 +0200 Subject: [PATCH 2/8] MaybeDone::new() Signed-off-by: Yoshua Wuyts --- src/join.rs | 2 +- src/lib.rs | 2 +- src/maybe_done.rs | 12 +++++++----- src/select.rs | 2 +- src/try_join.rs | 2 +- src/try_select.rs | 4 ++-- 6 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/join.rs b/src/join.rs index 466f319..3a793d9 100644 --- a/src/join.rs +++ b/src/join.rs @@ -28,7 +28,7 @@ macro_rules! join { $( // Move future into a local so that it is pinned in one place and // is no longer accessible by the end user. - let mut $fut = $crate::maybe_done($fut); + let mut $fut = $crate::MaybeDone::new($fut); )* $crate::utils::poll_fn(move |cx| { use $crate::utils::future::Future; diff --git a/src/lib.rs b/src/lib.rs index 6e00b26..3a6a8a7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,7 +28,7 @@ mod select; mod try_join; mod try_select; -pub use maybe_done::{maybe_done, MaybeDone}; +pub use maybe_done::MaybeDone; /// Helper re-exports for use in macros. pub mod utils { diff --git a/src/maybe_done.rs b/src/maybe_done.rs index 0906be0..60f4b9e 100644 --- a/src/maybe_done.rs +++ b/src/maybe_done.rs @@ -10,11 +10,6 @@ use core::pin::Pin; use futures_core::ready; use futures_core::task::{Context, Poll}; -/// Create a new instance of `MaybeDone`. -pub fn maybe_done(future: Fut) -> MaybeDone { - MaybeDone::Future(future) -} - /// A future that may have completed. #[derive(Debug)] pub enum MaybeDone { @@ -28,10 +23,16 @@ pub enum MaybeDone { } impl MaybeDone { + /// Create a new instance of `MaybeDone`. + pub fn new(future: Fut) -> MaybeDone { + Self::Future(future) + } + /// Returns an [`Option`] containing a mutable reference to the output of the future. /// The output of this method will be [`Some`] if and only if the inner /// future has been completed and [`take`](MaybeDone::take) /// has not yet been called. + #[allow(clippy::wrong_self_convention)] #[inline] pub fn as_mut(self: Pin<&mut Self>) -> Option<&mut Fut::Output> { unsafe { @@ -47,6 +48,7 @@ impl MaybeDone { /// The output of this method will be [`Some`] if and only if the inner /// future has been completed and [`take`](MaybeDone::take) /// has not yet been called. + #[allow(clippy::wrong_self_convention)] #[inline] pub fn as_ref(self: Pin<&Self>) -> Option<&Fut::Output> { let this = self.get_ref(); diff --git a/src/select.rs b/src/select.rs index 50b38c3..4f1ebc3 100644 --- a/src/select.rs +++ b/src/select.rs @@ -35,7 +35,7 @@ macro_rules! select { $( // Move future into a local so that it is pinned in one place and // is no longer accessible by the end user. - let mut $fut = $crate::maybe_done($fut); + let mut $fut = $crate::MaybeDone::new($fut); )* $crate::utils::poll_fn(move |cx| { use $crate::utils::future::Future; diff --git a/src/try_join.rs b/src/try_join.rs index ad9fc92..bf1fe3d 100644 --- a/src/try_join.rs +++ b/src/try_join.rs @@ -52,7 +52,7 @@ macro_rules! try_join { $( // Move future into a local so that it is pinned in one place and // is no longer accessible by the end user. - let mut $fut = $crate::maybe_done($fut); + let mut $fut = $crate::MaybeDone::new($fut); )* let res: Result<_, _> = poll_fn(move |cx| { diff --git a/src/try_select.rs b/src/try_select.rs index 2c65482..87790ea 100644 --- a/src/try_select.rs +++ b/src/try_select.rs @@ -6,7 +6,7 @@ /// /// `try_select!` is similar to [`select!`], but keeps going if a future /// resolved to an error until all futures have been resolved. In which case -/// the last error found will be returned. +/// the error of the last item in the list will be returned. /// /// This macro is only usable inside of async functions, closures, and blocks. /// @@ -42,7 +42,7 @@ macro_rules! try_select { $( // Move future into a local so that it is pinned in one place and // is no longer accessible by the end user. - let mut $fut = $crate::maybe_done($fut); + let mut $fut = $crate::MaybeDone::new($fut); )* let res: Result<_, _> = poll_fn(move |cx| { From 9efa892b8730e36b0c04d34d86d10c33d0ad135b Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Mon, 16 Sep 2019 07:26:45 +0200 Subject: [PATCH 3/8] bypass clippy wrong self convention Signed-off-by: Yoshua Wuyts --- src/maybe_done.rs | 30 ++++++++++++++++-------------- src/try_join.rs | 2 +- src/try_select.rs | 2 +- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/maybe_done.rs b/src/maybe_done.rs index 60f4b9e..6146f76 100644 --- a/src/maybe_done.rs +++ b/src/maybe_done.rs @@ -28,33 +28,33 @@ impl MaybeDone { Self::Future(future) } - /// Returns an [`Option`] containing a mutable reference to the output of the future. + /// Returns an [`Option`] containing a reference to the output of the future. /// The output of this method will be [`Some`] if and only if the inner /// future has been completed and [`take`](MaybeDone::take) /// has not yet been called. #[allow(clippy::wrong_self_convention)] #[inline] - pub fn as_mut(self: Pin<&mut Self>) -> Option<&mut Fut::Output> { - unsafe { - let this = self.get_unchecked_mut(); - match this { - MaybeDone::Done(res) => Some(res), - _ => None, - } + pub fn output(self: Pin<&Self>) -> Option<&Fut::Output> { + let this = self.get_ref(); + match this { + MaybeDone::Done(res) => Some(res), + _ => None, } } - /// Returns an [`Option`] containing a reference to the output of the future. + /// Returns an [`Option`] containing a mutable reference to the output of the future. /// The output of this method will be [`Some`] if and only if the inner /// future has been completed and [`take`](MaybeDone::take) /// has not yet been called. #[allow(clippy::wrong_self_convention)] #[inline] - pub fn as_ref(self: Pin<&Self>) -> Option<&Fut::Output> { - let this = self.get_ref(); - match this { - MaybeDone::Done(res) => Some(res), - _ => None, + pub fn output_mut(self: Pin<&mut Self>) -> Option<&mut Fut::Output> { + unsafe { + let this = self.get_unchecked_mut(); + match this { + MaybeDone::Done(res) => Some(res), + _ => None, + } } } @@ -75,6 +75,8 @@ impl MaybeDone { } } } + + // fn ok(self) -> Option {} } impl Future for MaybeDone { diff --git a/src/try_join.rs b/src/try_join.rs index bf1fe3d..4936ad0 100644 --- a/src/try_join.rs +++ b/src/try_join.rs @@ -61,7 +61,7 @@ macro_rules! try_join { let fut = unsafe { Pin::new_unchecked(&mut $fut) }; if Future::poll(fut, cx).is_pending() { all_done = false; - } else if unsafe { Pin::new_unchecked(&mut $fut) }.as_mut().unwrap().is_err() { + } else if unsafe { Pin::new_unchecked(&mut $fut) }.output_mut().unwrap().is_err() { // `.err().unwrap()` rather than `.unwrap_err()` so that we don't introduce // a `T: Debug` bound. return Poll::Ready( diff --git a/src/try_select.rs b/src/try_select.rs index 87790ea..5aeeac2 100644 --- a/src/try_select.rs +++ b/src/try_select.rs @@ -52,7 +52,7 @@ macro_rules! try_select { let fut = unsafe { Pin::new_unchecked(&mut $fut) }; if Future::poll(fut, cx).is_ready() { let fut = Pin::new(&$fut); - if fut.as_ref().unwrap().is_ok() { + if fut.output().unwrap().is_ok() { let fut = unsafe { Pin::new_unchecked(&mut $fut) }; let res = fut.take().unwrap(); return Poll::Ready(res); From 26d597b02d22203f8322e782ffe3312c4810477e Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Mon, 16 Sep 2019 09:01:50 +0200 Subject: [PATCH 4/8] Update src/maybe_done.rs Co-Authored-By: Taiki Endo --- src/maybe_done.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/maybe_done.rs b/src/maybe_done.rs index 6146f76..4b6f307 100644 --- a/src/maybe_done.rs +++ b/src/maybe_done.rs @@ -32,7 +32,6 @@ impl MaybeDone { /// The output of this method will be [`Some`] if and only if the inner /// future has been completed and [`take`](MaybeDone::take) /// has not yet been called. - #[allow(clippy::wrong_self_convention)] #[inline] pub fn output(self: Pin<&Self>) -> Option<&Fut::Output> { let this = self.get_ref(); From 04e5f5ee6dab8cb9d25b318967ab5d50852e2fd5 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Mon, 16 Sep 2019 09:21:06 +0200 Subject: [PATCH 5/8] rust nightly Signed-off-by: Yoshua Wuyts --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c70fb67..a6646cf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: rust rust: - - stable + - nightly before_script: | rustup component add rustfmt-preview && From 6997148b158acc9065d2c008bcd456a9db5dd2e9 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Mon, 16 Sep 2019 09:21:04 +0200 Subject: [PATCH 6/8] Update src/maybe_done.rs Co-Authored-By: Taiki Endo --- src/maybe_done.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/maybe_done.rs b/src/maybe_done.rs index 4b6f307..a7bc7c9 100644 --- a/src/maybe_done.rs +++ b/src/maybe_done.rs @@ -45,7 +45,6 @@ impl MaybeDone { /// The output of this method will be [`Some`] if and only if the inner /// future has been completed and [`take`](MaybeDone::take) /// has not yet been called. - #[allow(clippy::wrong_self_convention)] #[inline] pub fn output_mut(self: Pin<&mut Self>) -> Option<&mut Fut::Output> { unsafe { From 5fe130d316d362b6f6fec30087bb07cb6c41828f Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Mon, 16 Sep 2019 09:28:57 +0200 Subject: [PATCH 7/8] fix clippy Signed-off-by: Yoshua Wuyts --- .travis.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a6646cf..47fac0d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,8 +3,15 @@ rust: - nightly before_script: | - rustup component add rustfmt-preview && - rustup component add clippy-preview + rustup component add rustfmt-preview; + rustup component add clippy-preview; + if ! rustup component add rustfmt; then + target=`curl https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/rustfmt`; + echo "'rustfmt' is unavailable on the toolchain 'nightly', use the toolchain 'nightly-$target' instead"; + rustup toolchain install nightly-$target; + rustup default nightly-$target; + rustup component add rustfmt; + fi script: | cargo fmt -- --check && cargo clippy -- -D clippy && From a61e207637630ec768018df9bde80e0bdb50fdf5 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Mon, 16 Sep 2019 09:40:02 +0200 Subject: [PATCH 8/8] clippy fallback Signed-off-by: Yoshua Wuyts --- .travis.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 47fac0d..70eea46 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,8 +3,15 @@ rust: - nightly before_script: | - rustup component add rustfmt-preview; rustup component add clippy-preview; + if ! rustup component add clippy; then + target=`curl https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/clippy`; + echo "'clippy' is unavailable on the toolchain 'nightly', using the toolchain 'nightly-$target' instead"; + rustup toolchain install nightly-$target; + rustup default nightly-$target; + rustup component add clippy; + fi + rustup component add rustfmt-preview; if ! rustup component add rustfmt; then target=`curl https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/rustfmt`; echo "'rustfmt' is unavailable on the toolchain 'nightly', use the toolchain 'nightly-$target' instead";