diff --git a/src/future/future/flatten.rs b/src/future/future/flatten.rs new file mode 100644 index 00000000..7b056142 --- /dev/null +++ b/src/future/future/flatten.rs @@ -0,0 +1,52 @@ +use futures_core::ready; +use std::pin::Pin; + +use crate::future::Future; +use crate::future::IntoFuture; +use crate::task::{Context, Poll}; + +#[derive(Debug)] +pub struct FlattenFuture { + state: State, +} + +#[derive(Debug)] +enum State { + First(Fut1), + Second(Fut2), + Empty, +} + +impl FlattenFuture { + pub fn new(future: Fut1) -> FlattenFuture { + FlattenFuture { + state: State::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 Self { state } = unsafe { self.get_unchecked_mut() }; + loop { + match state { + State::First(fut1) => { + let fut2 = ready!(unsafe { Pin::new_unchecked(fut1) }.poll(cx)).into_future(); + *state = State::Second(fut2); + } + State::Second(fut2) => { + let v = ready!(unsafe { Pin::new_unchecked(fut2) }.poll(cx)); + *state = State::Empty; + return Poll::Ready(v); + } + State::Empty => panic!("polled a completed future"), + } + } + } +} diff --git a/src/future/future/mod.rs b/src/future/future/mod.rs index 548cccb8..3a666e8a 100644 --- a/src/future/future/mod.rs +++ b/src/future/future/mod.rs @@ -1,11 +1,14 @@ cfg_unstable! { mod delay; + mod flatten; mod race; mod try_race; use std::time::Duration; use delay::DelayFuture; + use flatten::FlattenFuture; + use crate::future::IntoFuture; use race::Race; use try_race::TryRace; } @@ -150,6 +153,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) -> impl Future::Output as IntoFuture>::Output> [FlattenFuture::Output as IntoFuture>::Future>] + where + Self: Future + Sized, + ::Output: IntoFuture + { + FlattenFuture::new(self) + } + #[doc = r#" Waits for one of two similarly-typed futures to complete.