use core::{fmt, pin::Pin, task::Poll, time::Duration};
use s2n_quic_core::{
ensure, time,
time::{timer, timer::Provider},
};
use tracing::trace;
#[macro_use]
mod macros;
#[cfg(any(test, feature = "testing"))]
pub mod bach;
#[cfg(feature = "tokio")]
pub mod tokio;
pub use time::clock::Cached;
pub use time::Timestamp;
use crate::either::Either;
pub type SleepHandle = Pin<Box<dyn Sleep>>;
pub trait Clock: 'static + Send + Sync + fmt::Debug + time::Clock {
fn sleep(&self, amount: Duration) -> (SleepHandle, Timestamp);
fn timer(&self) -> Timer
where
Self: Sized,
{
Timer::new(self)
}
}
impl<A, B> Clock for Either<A, B>
where
A: Clock,
B: Clock,
{
fn sleep(&self, amount: Duration) -> (SleepHandle, Timestamp) {
match self {
Either::A(a) => a.sleep(amount),
Either::B(b) => b.sleep(amount),
}
}
}
impl<A, B> time::Clock for Either<A, B>
where
A: time::Clock,
B: time::Clock,
{
fn get_time(&self) -> Timestamp {
match self {
Either::A(a) => a.get_time(),
Either::B(b) => b.get_time(),
}
}
}
pub trait Sleep: Clock + core::future::Future<Output = ()> {
fn update(self: Pin<&mut Self>, target: Timestamp);
}
pub struct Timer {
target: timer::Timer,
sleep: Pin<Box<dyn Sleep>>,
}
impl fmt::Debug for Timer {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Timer")
.field("target", &self.target)
.finish()
}
}
impl Timer {
#[inline]
pub fn new(clock: &dyn Clock) -> Self {
const INITIAL_TIMEOUT: Duration = Duration::from_secs(1);
Self::new_with_timeout(clock, INITIAL_TIMEOUT)
}
#[inline]
pub fn new_with_timeout(clock: &dyn Clock, timeout: Duration) -> Self {
let (sleep, target) = clock.sleep(timeout);
let mut timer = timer::Timer::default();
timer.set(target);
Self {
target: timer,
sleep,
}
}
#[inline]
pub fn cancel(&mut self) {
trace!(cancel = ?self.target);
self.target.cancel();
}
pub async fn sleep(&mut self, target: Timestamp) {
use time::clock::Timer;
self.update(target);
core::future::poll_fn(|cx| self.poll_ready(cx)).await
}
}
impl time::clock::Timer for Timer {
#[inline]
fn poll_ready(&mut self, cx: &mut core::task::Context) -> Poll<()> {
ensure!(self.target.is_armed(), Poll::Ready(()));
let res = self.sleep.as_mut().poll(cx);
if res.is_ready() {
self.target.cancel();
}
res
}
#[inline]
fn update(&mut self, target: Timestamp) {
ensure!(self.target.next_expiration() != Some(target));
self.sleep.as_mut().update(target);
self.target.set(target);
}
}
impl timer::Provider for Timer {
fn timers<Q: timer::Query>(&self, query: &mut Q) -> timer::Result {
self.target.timers(query)
}
}