use std::{
ops::{Add, AddAssign, Sub},
time::{Duration, SystemTimeError},
};
use ordered_float::NotNan;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Instant(
NotNan<f64>,
);
impl std::fmt::Debug for Instant {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Instant").field(&*self.0).finish()
}
}
impl Sub for Instant {
type Output = Duration;
fn sub(self, rhs: Self) -> Self::Output {
Duration::from_nanos(((*self.0 - *rhs.0).max(0.0) * 1e6) as _)
}
}
impl Add<Duration> for Instant {
type Output = Self;
fn add(self, rhs: Duration) -> Self::Output {
Self(self.0 + rhs.as_nanos() as f64 / 1e6)
}
}
impl AddAssign<Duration> for Instant {
fn add_assign(&mut self, rhs: Duration) {
*self = *self + rhs;
}
}
impl Sub<Duration> for Instant {
type Output = Self;
fn sub(self, rhs: Duration) -> Self::Output {
Self(self.0 - rhs.as_nanos() as f64 / 1e6)
}
}
impl Instant {
#[cfg(not(test))]
pub fn now() -> Self {
let perf = web_sys::window().unwrap().performance().unwrap();
Self(NotNan::new(perf.now()).unwrap())
}
#[cfg(test)]
pub fn now() -> Self {
Self(Default::default())
}
pub fn elapsed(&self) -> Duration {
Self::now().duration_since(*self)
}
#[inline]
pub fn duration_since(&self, earlier: Self) -> Duration {
Duration::from_nanos(((*self.0 - *earlier.0).max(0.0) * 1e6) as _)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SystemTime(NotNan<f64>);
impl Add<Duration> for SystemTime {
type Output = SystemTime;
fn add(self, rhs: Duration) -> Self::Output {
Self(self.0 + rhs.as_millis() as f64)
}
}
impl Sub<Duration> for SystemTime {
type Output = SystemTime;
fn sub(self, rhs: Duration) -> Self::Output {
Self(self.0 - rhs.as_millis() as f64)
}
}
impl SystemTime {
pub const UNIX_EPOCH: Self = SystemTime(unsafe { NotNan::new_unchecked(0.0) });
pub fn now() -> Self {
Self(NotNan::new(js_sys::Date::now()).unwrap())
}
pub fn duration_since(&self, earlier: Self) -> Result<Duration, SystemTimeError> {
Ok(Duration::from_nanos(
((*self.0 - *earlier.0).max(0.0) * 1e6) as _,
))
}
}