Skip to content

Commit

Permalink
feat: add a way to fuse futures
Browse files Browse the repository at this point in the history
Co-authored-by: glendc <[email protected]>
Co-authored-by: John Nunley <[email protected]>
  • Loading branch information
3 people authored May 11, 2024
1 parent cdf5d64 commit da2f2a2
Showing 1 changed file with 60 additions and 0 deletions.
60 changes: 60 additions & 0 deletions src/future.rs
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,66 @@ where
}
}

/// Fuse a future such that `poll` will never again be called once it has
/// completed. This method can be used to turn any `Future` into a
/// `FusedFuture`.
///
/// Normally, once a future has returned `Poll::Ready` from `poll`,
/// any further calls could exhibit bad behavior such as blocking
/// forever, panicking, never returning, etc. If it is known that `poll`
/// may be called too often then this method can be used to ensure that it
/// has defined semantics.
///
/// If a `fuse`d future is `poll`ed after having returned `Poll::Ready`
/// previously, it will return `Poll::Pending`, from `poll` again (and will
/// continue to do so for all future calls to `poll`).
///
/// This combinator will drop the underlying future as soon as it has been
/// completed to ensure resources are reclaimed as soon as possible.
pub fn fuse<F>(future: F) -> Fuse<F>
where
F: Future + Sized,
{
Fuse::new(future)
}

pin_project! {
/// [`Future`] for the [`fuse`] method.
#[derive(Debug)]
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Fuse<Fut> {
#[pin]
inner: Option<Fut>,
}
}

impl<Fut> Fuse<Fut> {
fn new(f: Fut) -> Self {
Self { inner: Some(f) }
}
}

impl<Fut: Future> Future for Fuse<Fut> {
type Output = Fut::Output;

fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Fut::Output> {
match self
.as_mut()
.project()
.inner
.as_pin_mut()
.map(|f| f.poll(cx))
{
Some(Poll::Ready(output)) => {
self.project().inner.set(None);
Poll::Ready(output)
}

Some(Poll::Pending) | None => Poll::Pending,
}
}
}

/// Returns the result of the future that completes first, with no preference if both are ready.
///
/// Each time [`Race`] is polled, the two inner futures are polled in random order. Therefore, no
Expand Down

0 comments on commit da2f2a2

Please sign in to comment.