use std::{
any::TypeId,
future::Future,
pin::Pin,
sync::Arc,
time::{Duration, Instant},
};
pub trait Timer {
fn sleep(&self, duration: Duration) -> Pin<Box<dyn Sleep>>;
fn sleep_until(&self, deadline: Instant) -> Pin<Box<dyn Sleep>>;
fn now(&self) -> Instant {
Instant::now()
}
fn reset(&self, sleep: &mut Pin<Box<dyn Sleep>>, new_deadline: Instant) {
*sleep = self.sleep_until(new_deadline);
}
}
pub trait Sleep: Send + Sync + Future<Output = ()> {
#[doc(hidden)]
fn __type_id(&self, _: private::Sealed) -> TypeId
where
Self: 'static,
{
TypeId::of::<Self>()
}
}
#[derive(Clone)]
pub struct ArcTimer(Arc<dyn Timer + Send + Sync>);
#[derive(Clone)]
pub enum Time {
Timer(ArcTimer),
Empty,
}
impl dyn Sleep {
pub fn is<T>(&self) -> bool
where
T: Sleep + 'static,
{
self.__type_id(private::Sealed {}) == TypeId::of::<T>()
}
pub fn downcast_mut_pin<T>(self: Pin<&mut Self>) -> Option<Pin<&mut T>>
where
T: Sleep + 'static,
{
if self.is::<T>() {
#[allow(unsafe_code)]
unsafe {
let inner = Pin::into_inner_unchecked(self);
Some(Pin::new_unchecked(
&mut *(&mut *inner as *mut dyn Sleep as *mut T),
))
}
} else {
None
}
}
}
impl ArcTimer {
pub(crate) fn new<T>(inner: T) -> Self
where
T: Timer + Send + Sync + 'static,
{
Self(Arc::new(inner))
}
}
impl Timer for ArcTimer {
fn sleep(&self, duration: Duration) -> Pin<Box<dyn Sleep>> {
self.0.sleep(duration)
}
fn now(&self) -> Instant {
tokio::time::Instant::now().into()
}
fn sleep_until(&self, deadline: Instant) -> Pin<Box<dyn Sleep>> {
self.0.sleep_until(deadline)
}
}
impl Time {
pub(crate) fn sleep(&self, duration: Duration) -> Pin<Box<dyn Sleep>> {
match *self {
Time::Empty => {
panic!("You must supply a timer.")
}
Time::Timer(ref t) => t.sleep(duration),
}
}
pub(crate) fn now(&self) -> Instant {
match *self {
Time::Empty => Instant::now(),
Time::Timer(ref t) => t.now(),
}
}
pub(crate) fn reset(&self, sleep: &mut Pin<Box<dyn Sleep>>, new_deadline: Instant) {
match *self {
Time::Empty => {
panic!("You must supply a timer.")
}
Time::Timer(ref t) => t.reset(sleep, new_deadline),
}
}
}
mod private {
pub struct Sealed {}
}