241 lines
6.8 KiB
Rust
241 lines
6.8 KiB
Rust
use std::cmp::Ordering;
|
|
use std::ops::{Add, AddAssign, Sub, SubAssign};
|
|
use std::time::Duration;
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Hash)]
|
|
pub struct Instant(Duration);
|
|
|
|
impl Ord for Instant {
|
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
self.partial_cmp(other)
|
|
.expect("an instant should never be NaN or Inf.")
|
|
}
|
|
}
|
|
impl Eq for Instant {}
|
|
|
|
impl Instant {
|
|
#[inline]
|
|
pub fn now() -> Self {
|
|
Instant(duration_from_f64(now()))
|
|
}
|
|
|
|
#[inline]
|
|
pub fn duration_since(&self, earlier: Instant) -> Duration {
|
|
assert!(
|
|
earlier.0 <= self.0,
|
|
"`earlier` cannot be later than `self`."
|
|
);
|
|
self.0 - earlier.0
|
|
}
|
|
|
|
#[inline]
|
|
pub fn elapsed(&self) -> Duration {
|
|
Self::now().duration_since(*self)
|
|
}
|
|
|
|
/// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as
|
|
/// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
|
|
/// otherwise.
|
|
#[inline]
|
|
pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
|
|
self.0.checked_add(duration).map(Instant)
|
|
}
|
|
|
|
/// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as
|
|
/// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
|
|
/// otherwise.
|
|
#[inline]
|
|
pub fn checked_sub(&self, duration: Duration) -> Option<Instant> {
|
|
self.0.checked_sub(duration).map(Instant)
|
|
}
|
|
|
|
/// Returns the amount of time elapsed from another instant to this one, or None if that
|
|
/// instant is later than this one.
|
|
#[inline]
|
|
pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
|
|
if earlier.0 > self.0 {
|
|
None
|
|
} else {
|
|
Some(self.0 - earlier.0)
|
|
}
|
|
}
|
|
|
|
/// Returns the amount of time elapsed from another instant to this one, or zero duration if
|
|
/// that instant is later than this one.
|
|
#[inline]
|
|
pub fn saturating_duration_since(&self, earlier: Instant) -> Duration {
|
|
self.checked_duration_since(earlier).unwrap_or_default()
|
|
}
|
|
}
|
|
|
|
impl Add<Duration> for Instant {
|
|
type Output = Self;
|
|
|
|
#[inline]
|
|
fn add(self, rhs: Duration) -> Self {
|
|
Instant(self.0 + rhs)
|
|
}
|
|
}
|
|
|
|
impl AddAssign<Duration> for Instant {
|
|
#[inline]
|
|
fn add_assign(&mut self, rhs: Duration) {
|
|
self.0 += rhs
|
|
}
|
|
}
|
|
|
|
impl Sub<Duration> for Instant {
|
|
type Output = Self;
|
|
|
|
#[inline]
|
|
fn sub(self, rhs: Duration) -> Self {
|
|
Instant(self.0 - rhs)
|
|
}
|
|
}
|
|
|
|
impl Sub<Instant> for Instant {
|
|
type Output = Duration;
|
|
|
|
#[inline]
|
|
fn sub(self, rhs: Instant) -> Duration {
|
|
self.duration_since(rhs)
|
|
}
|
|
}
|
|
|
|
impl SubAssign<Duration> for Instant {
|
|
#[inline]
|
|
fn sub_assign(&mut self, rhs: Duration) {
|
|
self.0 -= rhs
|
|
}
|
|
}
|
|
|
|
fn duration_from_f64(millis: f64) -> Duration {
|
|
Duration::from_millis(millis.trunc() as u64)
|
|
+ Duration::from_nanos((millis.fract() * 1.0e6) as u64)
|
|
}
|
|
|
|
#[cfg(all(feature = "stdweb", not(feature = "wasm-bindgen")))]
|
|
#[allow(unused_results)] // Needed because the js macro triggers it.
|
|
pub fn now() -> f64 {
|
|
use stdweb::unstable::TryInto;
|
|
|
|
// https://developer.mozilla.org/en-US/docs/Web/API/Performance/now
|
|
#[cfg(not(feature = "inaccurate"))]
|
|
let v = js! { return performance.now(); };
|
|
#[cfg(feature = "inaccurate")]
|
|
let v = js! { return Date.now(); };
|
|
v.try_into().unwrap()
|
|
}
|
|
|
|
#[cfg(feature = "wasm-bindgen")]
|
|
pub fn now() -> f64 {
|
|
#[cfg(not(feature = "inaccurate"))]
|
|
let now = {
|
|
use wasm_bindgen_rs::prelude::*;
|
|
use wasm_bindgen_rs::JsCast;
|
|
js_sys::Reflect::get(&js_sys::global(), &JsValue::from_str("performance"))
|
|
.expect("failed to get performance from global object")
|
|
.unchecked_into::<web_sys::Performance>()
|
|
.now()
|
|
};
|
|
#[cfg(feature = "inaccurate")]
|
|
let now = js_sys::Date::now();
|
|
now
|
|
}
|
|
|
|
// The JS now function is in a module so it won't have to be renamed
|
|
#[cfg(not(any(feature = "wasm-bindgen", feature = "stdweb")))]
|
|
mod js {
|
|
extern "C" {
|
|
#[cfg(not(target_os = "emscripten"))]
|
|
pub fn now() -> f64;
|
|
#[cfg(target_os = "emscripten")]
|
|
pub fn _emscripten_get_now() -> f64;
|
|
}
|
|
}
|
|
// Make the unsafe extern function "safe" so it can be called like the other 'now' functions
|
|
#[cfg(not(any(feature = "wasm-bindgen", feature = "stdweb")))]
|
|
pub fn now() -> f64 {
|
|
#[cfg(not(target_os = "emscripten"))]
|
|
return unsafe { js::now() };
|
|
#[cfg(target_os = "emscripten")]
|
|
return unsafe { js::_emscripten_get_now() };
|
|
}
|
|
|
|
/// Returns the number of millisecods elapsed since January 1, 1970 00:00:00 UTC.
|
|
#[cfg(any(feature = "wasm-bindgen", feature = "stdweb"))]
|
|
fn get_time() -> f64 {
|
|
#[cfg(feature = "wasm-bindgen")]
|
|
return js_sys::Date::now();
|
|
#[cfg(all(feature = "stdweb", not(feature = "wasm-bindgen")))]
|
|
{
|
|
let v = js! { return Date.now(); };
|
|
return v.try_into().unwrap();
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
|
|
pub struct SystemTime(f64);
|
|
|
|
impl SystemTime {
|
|
pub const UNIX_EPOCH: SystemTime = SystemTime(0.0);
|
|
|
|
pub fn now() -> SystemTime {
|
|
cfg_if::cfg_if! {
|
|
if #[cfg(any(feature = "wasm-bindgen", feature = "stdweb"))] {
|
|
SystemTime(get_time())
|
|
} else {
|
|
SystemTime(now())
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn duration_since(&self, earlier: SystemTime) -> Result<Duration, ()> {
|
|
let dur_ms = self.0 - earlier.0;
|
|
if dur_ms < 0.0 {
|
|
return Err(());
|
|
}
|
|
Ok(Duration::from_millis(dur_ms as u64))
|
|
}
|
|
|
|
pub fn elapsed(&self) -> Result<Duration, ()> {
|
|
self.duration_since(SystemTime::now())
|
|
}
|
|
|
|
pub fn checked_add(&self, duration: Duration) -> Option<SystemTime> {
|
|
Some(*self + duration)
|
|
}
|
|
|
|
pub fn checked_sub(&self, duration: Duration) -> Option<SystemTime> {
|
|
Some(*self - duration)
|
|
}
|
|
}
|
|
|
|
impl Add<Duration> for SystemTime {
|
|
type Output = SystemTime;
|
|
|
|
fn add(self, other: Duration) -> SystemTime {
|
|
SystemTime(self.0 + other.as_millis() as f64)
|
|
}
|
|
}
|
|
|
|
impl Sub<Duration> for SystemTime {
|
|
type Output = SystemTime;
|
|
|
|
fn sub(self, other: Duration) -> SystemTime {
|
|
SystemTime(self.0 - other.as_millis() as f64)
|
|
}
|
|
}
|
|
|
|
impl AddAssign<Duration> for SystemTime {
|
|
fn add_assign(&mut self, rhs: Duration) {
|
|
*self = *self + rhs;
|
|
}
|
|
}
|
|
|
|
impl SubAssign<Duration> for SystemTime {
|
|
fn sub_assign(&mut self, rhs: Duration) {
|
|
*self = *self - rhs;
|
|
}
|
|
}
|