use crate::Instant;
use crate::pal::{Platform, PlatformFacade, TimeSource, TimeSourceFacade};
#[derive(Clone, Debug)]
pub struct Clock {
inner: TimeSourceFacade,
}
impl Clock {
#[must_use]
pub fn new() -> Self {
#[cfg(all(any(target_os = "linux", windows), not(miri)))]
return Self::from_pal(PlatformFacade::real());
#[cfg(any(miri, not(any(target_os = "linux", windows))))]
return Self::from_pal(PlatformFacade::rust());
}
#[must_use]
#[expect(
clippy::needless_pass_by_value,
reason = "semantically correct, even if not necessary"
)]
pub(crate) fn from_pal(pal: PlatformFacade) -> Self {
Self {
inner: pal.new_time_source(),
}
}
#[must_use]
#[inline]
pub fn now(&mut self) -> Instant {
self.inner.now().into()
}
}
impl Default for Clock {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
use std::panic::{RefUnwindSafe, UnwindSafe};
use super::*;
static_assertions::assert_impl_all!(Clock: Clone, Send, UnwindSafe, RefUnwindSafe);
#[test]
fn now_is_approximately_now() {
let mut clock = Clock::new();
let instant = clock.now();
let rust_now = std::time::Instant::now();
let instant_as_rust_instant: std::time::Instant = instant.into();
assert!(
instant_as_rust_instant
.saturating_duration_since(rust_now)
.as_millis()
< 100
);
assert!(
rust_now
.saturating_duration_since(instant_as_rust_instant)
.as_millis()
< 100
);
}
#[test]
fn consecutive_instants_are_approximately_equal() {
let mut clock = Clock::new();
let instant1 = clock.now();
let instant2 = clock.now();
assert!(instant1.elapsed(&mut clock).as_millis() < 100);
assert!(instant2.elapsed(&mut clock).as_millis() < 100);
let elapsed = instant2.saturating_duration_since(instant1);
assert!(elapsed.as_millis() < 100);
let rust_instant1: std::time::Instant = instant1.into();
let rust_instant2: std::time::Instant = instant2.into();
let rust_elapsed = rust_instant2.duration_since(rust_instant1);
assert!(rust_elapsed.as_millis() < 100);
}
#[test]
fn default_behaves_like_new() {
let mut clock_new = Clock::new();
let mut clock_default = Clock::default();
_ = clock_new.now();
_ = clock_default.now();
}
#[test]
fn clock_can_be_cloned() {
let mut clock1 = Clock::new();
let instant1 = clock1.now();
let mut clock2 = clock1.clone();
let instant2 = clock2.now();
assert!(instant1.elapsed(&mut clock1).as_millis() < 100);
assert!(instant2.elapsed(&mut clock2).as_millis() < 100);
let diff = if instant2 > instant1 {
instant2.saturating_duration_since(instant1)
} else {
instant1.saturating_duration_since(instant2)
};
assert!(diff.as_millis() < 100);
}
}