pub struct VirtualTime {
pub paused: bool,
pub scale: f64,
pub max_delta: f64,
pub elapsed: f64,
}
impl VirtualTime {
pub fn new() -> Self {
Self {
paused: false,
scale: 1.0,
max_delta: 0.25,
elapsed: 0.0,
}
}
pub fn effective_elapsed(&self, raw: f64) -> f64 {
if self.paused {
return 0.0;
}
let clamped = raw.min(self.max_delta).max(0.0);
let scale = self.scale.clamp(0.0, 8.0);
clamped * scale
}
}
impl Default for VirtualTime {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_values() {
let vt = VirtualTime::new();
assert!(!vt.paused);
assert!((vt.scale - 1.0).abs() < f64::EPSILON);
assert!((vt.max_delta - 0.25).abs() < f64::EPSILON);
assert!((vt.elapsed - 0.0).abs() < f64::EPSILON);
}
#[test]
fn effective_elapsed_normal() {
let vt = VirtualTime::new();
let e = vt.effective_elapsed(0.1);
assert!((e - 0.1).abs() < f64::EPSILON);
}
#[test]
fn effective_elapsed_paused() {
let mut vt = VirtualTime::new();
vt.paused = true;
assert_eq!(vt.effective_elapsed(1.0), 0.0);
assert_eq!(vt.effective_elapsed(0.0), 0.0);
}
#[test]
fn effective_elapsed_scaled() {
let mut vt = VirtualTime::new();
vt.scale = 2.0;
let e = vt.effective_elapsed(0.1);
assert!((e - 0.2).abs() < f64::EPSILON);
vt.scale = 0.5;
let e = vt.effective_elapsed(0.1);
assert!((e - 0.05).abs() < f64::EPSILON);
}
#[test]
fn effective_elapsed_max_delta_clamp() {
let vt = VirtualTime::new(); let e = vt.effective_elapsed(2.0); assert!((e - 0.25).abs() < f64::EPSILON);
}
#[test]
fn effective_elapsed_scale_and_clamp_interact() {
let mut vt = VirtualTime::new(); vt.scale = 4.0;
let e = vt.effective_elapsed(2.0); assert!((e - 1.0).abs() < f64::EPSILON);
}
#[test]
fn scale_clamped_to_bounds() {
let mut vt = VirtualTime::new();
vt.scale = -1.0;
assert_eq!(vt.effective_elapsed(0.1), 0.0);
vt.scale = 100.0;
let e = vt.effective_elapsed(0.1);
assert!((e - 0.8).abs() < f64::EPSILON); }
#[test]
fn negative_raw_clamped_to_zero() {
let vt = VirtualTime::new();
assert_eq!(vt.effective_elapsed(-0.5), 0.0);
}
}