pub trait Clock {
fn delta(&mut self) -> f32;
}
#[cfg(feature = "std")]
pub struct WallClock {
last: std::time::Instant,
}
#[cfg(feature = "std")]
impl WallClock {
pub fn new() -> Self {
Self {
last: std::time::Instant::now(),
}
}
}
#[cfg(feature = "std")]
impl Default for WallClock {
fn default() -> Self {
Self::new()
}
}
#[cfg(feature = "std")]
impl Clock for WallClock {
fn delta(&mut self) -> f32 {
let now = std::time::Instant::now();
let dt = now.duration_since(self.last).as_secs_f32();
self.last = now;
dt
}
}
#[cfg(feature = "std")]
impl core::fmt::Debug for WallClock {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("WallClock")
.field("last", &self.last)
.finish()
}
}
#[derive(Debug, Clone)]
pub struct ManualClock {
pending_dt: f32,
}
impl ManualClock {
pub fn new() -> Self {
Self { pending_dt: 0.0 }
}
pub fn advance(&mut self, dt: f32) {
self.pending_dt += dt;
}
}
impl Default for ManualClock {
fn default() -> Self {
Self::new()
}
}
impl Clock for ManualClock {
fn delta(&mut self) -> f32 {
let dt = self.pending_dt;
self.pending_dt = 0.0;
dt
}
}
#[derive(Debug, Clone)]
pub struct MockClock {
step: f32,
}
impl MockClock {
pub fn new(step_seconds: f32) -> Self {
Self { step: step_seconds }
}
}
impl Clock for MockClock {
fn delta(&mut self) -> f32 {
self.step
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mock_clock_returns_fixed_dt() {
let mut clock = MockClock::new(1.0 / 60.0);
for _ in 0..100 {
let dt = clock.delta();
assert!((dt - 1.0 / 60.0).abs() < 1e-7);
}
}
#[test]
fn manual_clock_accumulates() {
let mut clock = ManualClock::new();
clock.advance(0.1);
clock.advance(0.2);
let dt = clock.delta();
assert!((dt - 0.3).abs() < 1e-6);
}
#[test]
fn manual_clock_resets_after_delta() {
let mut clock = ManualClock::new();
clock.advance(0.5);
let _ = clock.delta();
let dt = clock.delta();
assert!((dt - 0.0).abs() < 1e-6);
}
#[cfg(feature = "std")]
#[test]
fn wall_clock_returns_positive() {
let mut clock = WallClock::new();
std::thread::sleep(std::time::Duration::from_millis(10));
let dt = clock.delta();
assert!(dt > 0.0);
}
}