From e0910be8fb85d6578d46be83e5fc4ff26fc874f1 Mon Sep 17 00:00:00 2001 From: "Abhishek C. Sharma" Date: Sun, 3 Nov 2019 11:34:49 +0530 Subject: [PATCH 1/3] Added Future::flatten --- src/future/future.rs | 27 +++++++++++++++++++++ src/future/future/flatten.rs | 46 ++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 src/future/future/flatten.rs diff --git a/src/future/future.rs b/src/future/future.rs index fe68517..1b88430 100644 --- a/src/future/future.rs +++ b/src/future/future.rs @@ -1,9 +1,12 @@ cfg_unstable! { mod delay; + mod flatten; use std::time::Duration; use delay::DelayFuture; + use flatten::FlattenFuture; + use crate::future::IntoFuture; } extension_trait! { @@ -129,6 +132,30 @@ extension_trait! { { DelayFuture::new(self, dur) } + + /// Flatten out the execution of this future when the result itself + /// can be converted into another future. + /// + /// # Examples + /// + /// ``` + /// # async_std::task::block_on(async { + /// use async_std::prelude::*; + /// + /// let nested_future = async { async { 1 } }; + /// let future = nested_future.flatten(); + /// assert_eq!(future.await, 1); + /// # }) + /// ``` + #[cfg_attr(feature = "docs", doc(cfg(unstable)))] + #[cfg(any(feature = "unstable", feature = "docs"))] + fn flatten(self) -> FlattenFuture::Future> + where + Self: Future + Sized, + Self::Output: IntoFuture + { + FlattenFuture::new(self) + } } impl Future for Box { diff --git a/src/future/future/flatten.rs b/src/future/future/flatten.rs new file mode 100644 index 0000000..27ee228 --- /dev/null +++ b/src/future/future/flatten.rs @@ -0,0 +1,46 @@ +use futures_core::ready; +use std::pin::Pin; + +use crate::future::Future; +use crate::future::IntoFuture; +use crate::task::{Context, Poll}; + +#[doc(hidden)] +#[derive(Debug)] +pub enum FlattenFuture { + First(Fut1), + Second(Fut2), + Empty, +} + +impl FlattenFuture { + pub fn new(future: Fut1) -> FlattenFuture { + FlattenFuture::First(future) + } +} + +impl Future for FlattenFuture::Future> +where + Fut1: Future, + Fut1::Output: IntoFuture, +{ + type Output = ::Output; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let this = unsafe { self.get_unchecked_mut() }; + loop { + match this { + FlattenFuture::First(fut1) => { + let fut2 = ready!(unsafe { Pin::new_unchecked(fut1) }.poll(cx)).into_future(); + *this = FlattenFuture::Second(fut2); + } + FlattenFuture::Second(fut2) => { + let v = ready!(unsafe { Pin::new_unchecked(fut2) }.poll(cx)); + *this = FlattenFuture::Empty; + return Poll::Ready(v); + } + FlattenFuture::Empty => unreachable!(), + } + } + } +} From a3e68704bc0f4f55a188e97b6c3d41cac50992a9 Mon Sep 17 00:00:00 2001 From: "Abhishek C. Sharma" Date: Mon, 4 Nov 2019 13:58:14 +0530 Subject: [PATCH 2/3] Wrap state enum in public struct --- src/future/future/flatten.rs | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/future/future/flatten.rs b/src/future/future/flatten.rs index 27ee228..7b05614 100644 --- a/src/future/future/flatten.rs +++ b/src/future/future/flatten.rs @@ -5,9 +5,13 @@ use crate::future::Future; use crate::future::IntoFuture; use crate::task::{Context, Poll}; -#[doc(hidden)] #[derive(Debug)] -pub enum FlattenFuture { +pub struct FlattenFuture { + state: State, +} + +#[derive(Debug)] +enum State { First(Fut1), Second(Fut2), Empty, @@ -15,7 +19,9 @@ pub enum FlattenFuture { impl FlattenFuture { pub fn new(future: Fut1) -> FlattenFuture { - FlattenFuture::First(future) + FlattenFuture { + state: State::First(future), + } } } @@ -27,19 +33,19 @@ where type Output = ::Output; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let this = unsafe { self.get_unchecked_mut() }; + let Self { state } = unsafe { self.get_unchecked_mut() }; loop { - match this { - FlattenFuture::First(fut1) => { + match state { + State::First(fut1) => { let fut2 = ready!(unsafe { Pin::new_unchecked(fut1) }.poll(cx)).into_future(); - *this = FlattenFuture::Second(fut2); + *state = State::Second(fut2); } - FlattenFuture::Second(fut2) => { + State::Second(fut2) => { let v = ready!(unsafe { Pin::new_unchecked(fut2) }.poll(cx)); - *this = FlattenFuture::Empty; + *state = State::Empty; return Poll::Ready(v); } - FlattenFuture::Empty => unreachable!(), + State::Empty => panic!("polled a completed future"), } } } From d7afcada76c8a49c411350c36beb5af41e1f36a0 Mon Sep 17 00:00:00 2001 From: "Abhishek C. Sharma" Date: Mon, 4 Nov 2019 15:19:47 +0530 Subject: [PATCH 3/3] Fixed ambiguous associated types --- src/future/future/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/future/future/mod.rs b/src/future/future/mod.rs index 0f3ab28..8e6e90a 100644 --- a/src/future/future/mod.rs +++ b/src/future/future/mod.rs @@ -153,10 +153,10 @@ extension_trait! { /// ``` #[cfg_attr(feature = "docs", doc(cfg(unstable)))] #[cfg(any(feature = "unstable", feature = "docs"))] - fn flatten(self) -> FlattenFuture::Future> + fn flatten(self) -> impl Future::Output as IntoFuture>::Output> [FlattenFuture::Output as IntoFuture>::Future>] where Self: Future + Sized, - Self::Output: IntoFuture + ::Output: IntoFuture { FlattenFuture::new(self) }