use futures::{future::FusedFuture, FutureExt};
use futures_timer::Delay;
use std::{
future::Future,
pin::Pin,
task::{Context, Poll, Waker},
time::Duration,
};
enum Inner {
Infinite {
waker: Option<Waker>,
delay: Option<Delay>,
},
Finite(Delay),
}
pub struct MaybeInfDelay(Inner);
impl MaybeInfDelay {
pub fn new(duration: Option<Duration>) -> Self {
match duration {
Some(duration) => Self(Inner::Finite(Delay::new(duration))),
None => Self(Inner::Infinite { waker: None, delay: None }),
}
}
pub fn reset(&mut self, duration: Option<Duration>) {
match duration {
Some(duration) => match &mut self.0 {
Inner::Infinite { waker, delay } => {
let mut delay = match delay.take() {
Some(mut delay) => {
delay.reset(duration);
delay
},
None => Delay::new(duration),
};
if let Some(waker) = waker.take() {
let mut cx = Context::from_waker(&waker);
match delay.poll_unpin(&mut cx) {
Poll::Pending => (), Poll::Ready(_) => waker.wake(),
}
}
self.0 = Inner::Finite(delay);
},
Inner::Finite(delay) => delay.reset(duration),
},
None => {
self.0 = match std::mem::replace(
&mut self.0,
Inner::Infinite { waker: None, delay: None },
) {
Inner::Finite(delay) => Inner::Infinite { waker: None, delay: Some(delay) },
infinite => infinite,
}
},
}
}
}
impl Future for MaybeInfDelay {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match &mut self.0 {
Inner::Infinite { waker, .. } => {
*waker = Some(cx.waker().clone());
Poll::Pending
},
Inner::Finite(delay) => delay.poll_unpin(cx),
}
}
}
impl FusedFuture for MaybeInfDelay {
fn is_terminated(&self) -> bool {
matches!(self.0, Inner::Infinite { .. })
}
}