use std::task::Poll;
#[cfg(not(target_family = "wasm"))]
pub type Instant = std::time::Instant;
#[cfg(target_family = "wasm")]
pub type Instant = web_async::time::Instant;
pub trait Timer {
fn set(&mut self, at: Option<Instant>);
fn poll(&mut self, waiter: &kio::Waiter) -> Poll<()>;
}
pub trait Timers: Clone {
type Timer: Timer;
fn timer(&self) -> Self::Timer;
fn now(&self) -> Instant;
}
pub struct Deadline<R: Timers> {
at: Option<Instant>,
timer: R::Timer,
}
impl<R: Timers> Deadline<R> {
pub fn new(runtime: &R) -> Self {
Self {
at: None,
timer: runtime.timer(),
}
}
pub fn at(runtime: &R, at: Instant) -> Self {
let mut deadline = Self::new(runtime);
deadline.set(Some(at));
deadline
}
pub fn after(runtime: &R, duration: std::time::Duration) -> Self {
let mut deadline = Self::new(runtime);
deadline.set(runtime.now().checked_add(duration));
deadline
}
pub fn set(&mut self, at: Option<Instant>) {
if self.at == at {
return;
}
self.at = at;
self.timer.set(at);
}
pub fn deadline(&self) -> Option<Instant> {
self.at
}
pub fn poll(&mut self, waiter: &kio::Waiter) -> Poll<()> {
if self.at.is_none() {
return Poll::Pending;
}
self.timer.poll(waiter)
}
}
impl<R: Timers> std::fmt::Debug for Deadline<R> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Deadline").field("at", &self.at).finish()
}
}
#[cfg(test)]
mod test;
#[cfg(test)]
pub use test::Test;
#[cfg(all(test, not(target_family = "wasm")))]
pub(crate) mod tokio_test {
use std::{pin::Pin, task::Poll};
use super::{Instant, Timer};
#[derive(Clone, Default)]
pub(crate) struct Tokio;
impl Tokio {
pub fn new() -> Self {
Self
}
}
impl super::Timers for Tokio {
type Timer = TokioTimer;
fn timer(&self) -> Self::Timer {
TokioTimer { at: None, sleep: None }
}
fn now(&self) -> Instant {
tokio::time::Instant::now().into_std()
}
}
pub(crate) struct TokioTimer {
at: Option<Instant>,
sleep: Option<Pin<Box<tokio::time::Sleep>>>,
}
impl Timer for TokioTimer {
fn set(&mut self, at: Option<Instant>) {
self.at = at;
if let (Some(at), Some(sleep)) = (at, &mut self.sleep) {
sleep.as_mut().reset(tokio::time::Instant::from_std(at));
}
}
fn poll(&mut self, waiter: &kio::Waiter) -> Poll<()> {
let Some(at) = self.at else { return Poll::Pending };
let sleep = self
.sleep
.get_or_insert_with(|| Box::pin(tokio::time::sleep_until(tokio::time::Instant::from_std(at))));
if sleep.is_elapsed() {
return Poll::Ready(());
}
waiter.poll_future(sleep.as_mut())
}
}
}