use core::cell::Cell;
use core::time::Duration;
pub trait Clock {
fn now(&self) -> Instant;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Instant(u64);
impl Instant {
#[must_use]
pub const fn from_nanos(nanos: u64) -> Self {
Self(nanos)
}
#[must_use]
pub const fn as_nanos(self) -> u64 {
self.0
}
#[must_use]
pub const fn checked_duration_since(self, earlier: Self) -> Option<Duration> {
if self.0 >= earlier.0 {
Some(Duration::from_nanos(self.0 - earlier.0))
} else {
None
}
}
#[must_use]
pub fn checked_add(self, duration: Duration) -> Option<Self> {
let nanos = u128::from(self.0).checked_add(duration.as_nanos())?;
let nanos_u64 = u64::try_from(nanos).ok()?;
Some(Self(nanos_u64))
}
#[must_use]
pub fn checked_sub(self, duration: Duration) -> Option<Self> {
let nanos = u128::from(self.0).checked_sub(duration.as_nanos())?;
let nanos_u64 = u64::try_from(nanos).ok()?;
Some(Self(nanos_u64))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Deadline {
at: Instant,
}
impl Deadline {
#[must_use]
pub const fn at(at: Instant) -> Self {
Self { at }
}
#[must_use]
pub const fn instant(self) -> Instant {
self.at
}
#[must_use]
pub const fn is_expired(self, now: Instant) -> bool {
now.as_nanos() >= self.at.as_nanos()
}
}
#[derive(Debug)]
pub struct ManualClock {
now: Cell<Instant>,
}
impl ManualClock {
#[must_use]
pub const fn new(start: Instant) -> Self {
Self {
now: Cell::new(start),
}
}
pub fn set(&self, now: Instant) {
self.now.set(now);
}
pub fn advance(&self, by: Duration) {
let next = self
.now
.get()
.checked_add(by)
.unwrap_or_else(|| Instant::from_nanos(u64::MAX));
self.now.set(next);
}
}
impl Clock for ManualClock {
fn now(&self) -> Instant {
self.now.get()
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
#[derive(Debug, Clone)]
pub struct SystemClock {
origin: std::time::Instant,
}
#[cfg(feature = "std")]
impl SystemClock {
#[must_use]
pub fn new() -> Self {
Self {
origin: std::time::Instant::now(),
}
}
}
#[cfg(feature = "std")]
impl Default for SystemClock {
fn default() -> Self {
Self::new()
}
}
#[cfg(feature = "std")]
impl Clock for SystemClock {
fn now(&self) -> Instant {
let nanos = self.origin.elapsed().as_nanos().min(u128::from(u64::MAX));
let nanos_u64 = u64::try_from(nanos).map_or(u64::MAX, |nanos| nanos);
Instant::from_nanos(nanos_u64)
}
}