use std::sync::Arc;
use std::time::Duration;
use std::time::Instant;
use crate::MonotonicClock;
use crate::MonotonicInstant;
use crate::StdMonotonicClock;
use crate::TimeError;
use crate::Timer;
use crate::TimerFuture;
use crate::timer::internal::std_timer_future::StdTimerFuture;
use crate::timer::internal::std_timer_scheduler::StdTimerScheduler;
use crate::timer::internal::std_timer_waiter::StdTimerWaiter;
pub struct StdTimer {
clock: StdMonotonicClock,
scheduler: Arc<StdTimerScheduler>,
}
impl StdTimer {
#[must_use]
#[inline]
pub fn new() -> Self {
let clock = StdMonotonicClock::new();
Self::from_clock(&clock)
}
#[must_use]
#[inline]
pub fn from_clock(clock: &StdMonotonicClock) -> Self {
Self {
clock: clock.same_domain_handle(),
scheduler: StdTimerScheduler::shared(),
}
}
fn native_deadline(&self, deadline: MonotonicInstant) -> Result<Instant, TimeError> {
deadline.validate_domain(self.clock.domain())?;
self.clock
.origin()
.checked_add(deadline.elapsed_since_origin())
.ok_or(TimeError::InstantOverflow)
}
#[inline]
fn schedule(&self, deadline: Instant, now: Instant) -> Result<TimerFuture, TimeError> {
if deadline <= now {
return Ok(Box::pin(std::future::ready(Ok(()))));
}
let waiter = Arc::new(StdTimerWaiter::new());
let waiter_id = self.scheduler.register(deadline, Arc::clone(&waiter))?;
Ok(Box::pin(StdTimerFuture::new(
Arc::clone(&self.scheduler),
waiter_id,
waiter,
)))
}
}
impl Default for StdTimer {
fn default() -> Self {
Self::new()
}
}
impl std::fmt::Debug for StdTimer {
#[inline]
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter
.debug_struct("StdTimer")
.field("clock", &self.clock)
.finish_non_exhaustive()
}
}
impl Timer for StdTimer {
#[inline(always)]
fn clock(&self) -> &dyn MonotonicClock {
&self.clock
}
fn at(&self, deadline: MonotonicInstant) -> Result<TimerFuture, TimeError> {
let deadline = self.native_deadline(deadline)?;
self.schedule(deadline, Instant::now())
}
fn after(&self, duration: Duration) -> Result<TimerFuture, TimeError> {
let now = Instant::now();
let deadline = now.checked_add(duration).ok_or(TimeError::InstantOverflow)?;
self.schedule(deadline, now)
}
}