pollable_map/futures/
optional.rsuse futures::future::FusedFuture;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll, Waker};
pub struct OptionalFuture<F> {
future: Option<F>,
waker: Option<Waker>,
}
impl<F: Unpin> Unpin for OptionalFuture<F> {}
impl<F> Default for OptionalFuture<F> {
fn default() -> Self {
Self {
future: None,
waker: None,
}
}
}
impl<F> OptionalFuture<F>
where
F: Future + Send + Unpin + 'static,
{
pub fn new(future: F) -> Self {
Self {
future: Some(future),
waker: None,
}
}
pub fn take(&mut self) -> Option<F> {
let fut = self.future.take();
if let Some(waker) = self.waker.take() {
waker.wake();
}
fut
}
pub fn is_some(&self) -> bool {
self.future.is_some()
}
pub fn is_none(&self) -> bool {
self.future.is_none()
}
pub fn as_ref(&self) -> Option<&F> {
self.future.as_ref()
}
pub fn as_mut(&mut self) -> Option<&mut F> {
self.future.as_mut()
}
pub fn replace(&mut self, future: F) -> Option<F> {
let fut = self.future.replace(future);
if let Some(waker) = self.waker.take() {
waker.wake();
}
fut
}
}
impl<F> Future for OptionalFuture<F>
where
F: Future + Send + Unpin + 'static,
{
type Output = F::Output;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let Some(future) = self.future.as_mut() else {
self.waker.replace(cx.waker().clone());
return Poll::Pending;
};
match Pin::new(future).poll(cx) {
Poll::Ready(output) => {
self.future.take();
Poll::Ready(output)
}
Poll::Pending => {
self.waker.replace(cx.waker().clone());
Poll::Pending
}
}
}
}
impl<F: Future> FusedFuture for OptionalFuture<F>
where
F: Future + Send + Unpin + 'static,
{
fn is_terminated(&self) -> bool {
self.future.is_none()
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_optional_future() {
let mut future = OptionalFuture::new(futures::future::ready(0));
assert!(future.is_some());
let waker = futures::task::noop_waker_ref();
let val = Pin::new(&mut future).poll(&mut Context::from_waker(waker));
assert_eq!(val, Poll::Ready(0));
assert!(future.is_none());
}
#[test]
fn reusable_optional_future() {
let mut future = OptionalFuture::new(futures::future::ready(0));
assert!(future.is_some());
let waker = futures::task::noop_waker_ref();
let val = Pin::new(&mut future).poll(&mut Context::from_waker(waker));
assert_eq!(val, Poll::Ready(0));
assert!(future.is_none());
future.replace(futures::future::ready(1));
assert!(future.is_some());
let val = Pin::new(&mut future).poll(&mut Context::from_waker(waker));
assert_eq!(val, Poll::Ready(1));
assert!(future.is_none());
}
}