diff --git a/Cargo.toml b/Cargo.toml index 7c4613b..569dfb3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,6 @@ docs = ["attributes", "unstable"] unstable = ["default", "broadcaster"] attributes = ["async-attributes"] std = [ - "async-macros", "crossbeam-utils", "futures-core", "futures-io", @@ -51,7 +50,6 @@ std = [ [dependencies] async-attributes = { version = "1.1.1", optional = true } -async-macros = { version = "2.0.0", optional = true } async-task = { version = "1.0.0", optional = true } broadcaster = { version = "0.2.6", optional = true, default-features = false, features = ["default-channels"] } crossbeam-channel = { version = "0.4.0", optional = true } diff --git a/src/future/future/join.rs b/src/future/future/join.rs index 0febcad..4a508ce 100644 --- a/src/future/future/join.rs +++ b/src/future/future/join.rs @@ -1,6 +1,6 @@ use std::pin::Pin; -use async_macros::MaybeDone; +use crate::future::MaybeDone; use pin_project_lite::pin_project; use crate::task::{Context, Poll}; diff --git a/src/future/future/race.rs b/src/future/future/race.rs index ed034f0..82165a0 100644 --- a/src/future/future/race.rs +++ b/src/future/future/race.rs @@ -1,7 +1,7 @@ use std::future::Future; use std::pin::Pin; -use async_macros::MaybeDone; +use crate::future::MaybeDone; use pin_project_lite::pin_project; use crate::task::{Context, Poll}; diff --git a/src/future/future/try_join.rs b/src/future/future/try_join.rs index f166724..5277ae3 100644 --- a/src/future/future/try_join.rs +++ b/src/future/future/try_join.rs @@ -1,6 +1,6 @@ use std::pin::Pin; -use async_macros::MaybeDone; +use crate::future::MaybeDone; use pin_project_lite::pin_project; use crate::task::{Context, Poll}; diff --git a/src/future/future/try_race.rs b/src/future/future/try_race.rs index d0ca4a9..4519957 100644 --- a/src/future/future/try_race.rs +++ b/src/future/future/try_race.rs @@ -1,6 +1,6 @@ use std::pin::Pin; -use async_macros::MaybeDone; +use crate::future::MaybeDone; use pin_project_lite::pin_project; use crate::task::{Context, Poll}; diff --git a/src/future/maybe_done.rs b/src/future/maybe_done.rs new file mode 100644 index 0000000..7a3a7fa --- /dev/null +++ b/src/future/maybe_done.rs @@ -0,0 +1,79 @@ +//! A type that wraps a future to keep track of its completion status. +//! +//! This implementation was taken from the original `macro_rules` `join/try_join` +//! macros in the `futures-preview` crate. + +use std::future::Future; +use std::mem; +use std::pin::Pin; +use std::task::{Context, Poll}; + +use futures_core::ready; + +/// A future that may have completed. +#[derive(Debug)] +pub(crate) enum MaybeDone { + /// A not-yet-completed future + Future(Fut), + + /// The output of the completed future + Done(Fut::Output), + + /// The empty variant after the result of a [`MaybeDone`] has been + /// taken using the [`take`](MaybeDone::take) method. + Gone, +} + +impl MaybeDone { + /// Create a new instance of `MaybeDone`. + pub(crate) fn new(future: Fut) -> MaybeDone { + Self::Future(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. + #[inline] + pub(crate) fn output(self: Pin<&Self>) -> Option<&Fut::Output> { + let this = self.get_ref(); + match this { + MaybeDone::Done(res) => Some(res), + _ => None, + } + } + + /// Attempt to take the output of a `MaybeDone` without driving it + /// towards completion. + #[inline] + pub(crate) fn take(self: Pin<&mut Self>) -> Option { + unsafe { + let this = self.get_unchecked_mut(); + match this { + MaybeDone::Done(_) => {} + MaybeDone::Future(_) | MaybeDone::Gone => return None, + }; + if let MaybeDone::Done(output) = mem::replace(this, MaybeDone::Gone) { + Some(output) + } else { + unreachable!() + } + } + } +} + +impl Future for MaybeDone { + type Output = (); + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let res = unsafe { + 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"), + } + }; + self.set(MaybeDone::Done(res)); + Poll::Ready(()) + } +} diff --git a/src/future/mod.rs b/src/future/mod.rs index 8b51a6a..9936276 100644 --- a/src/future/mod.rs +++ b/src/future/mod.rs @@ -63,5 +63,7 @@ cfg_default! { cfg_unstable! { pub use into_future::IntoFuture; + pub(crate) use maybe_done::MaybeDone; mod into_future; + mod maybe_done; } diff --git a/src/task/mod.rs b/src/task/mod.rs index e66ed0d..a73d5d2 100644 --- a/src/task/mod.rs +++ b/src/task/mod.rs @@ -121,10 +121,9 @@ cfg_std! { #[doc(inline)] pub use std::task::{Context, Poll, Waker}; - #[doc(inline)] - pub use async_macros::ready; - + pub use ready::ready; pub use yield_now::yield_now; + mod ready; mod yield_now; } diff --git a/src/task/ready.rs b/src/task/ready.rs new file mode 100644 index 0000000..aca04aa --- /dev/null +++ b/src/task/ready.rs @@ -0,0 +1,4 @@ +/// Extracts the successful type of a `Poll`. +/// +/// This macro bakes in propagation of `Pending` signals by returning early. +pub use futures_core::ready;