mod easing;
pub mod particles;
pub mod shaders;
mod timeline;
mod transition;
mod tween;
pub use easing::Easing;
pub use particles::{Burst, Particle, ParticleField};
pub use timeline::{LoopMode, Seek, Timeline};
pub use transition::Transition;
pub use tween::{Lerp, Tween};
pub use crate::base::FrameRequester;
use std::time::{Duration, Instant};
#[derive(Debug, Clone)]
pub struct Clock {
kind: ClockKind,
}
#[derive(Debug, Clone)]
enum ClockKind {
Real { start: Instant },
Virtual { now: Duration },
}
impl Clock {
pub fn real() -> Clock {
Clock {
kind: ClockKind::Real {
start: Instant::now(),
},
}
}
pub fn fixed() -> Clock {
Clock {
kind: ClockKind::Virtual {
now: Duration::ZERO,
},
}
}
pub fn now(&self) -> Duration {
match &self.kind {
ClockKind::Real { start } => start.elapsed(),
ClockKind::Virtual { now } => *now,
}
}
pub fn advance(&mut self, by: Duration) {
match &mut self.kind {
ClockKind::Virtual { now } => *now += by,
ClockKind::Real { .. } => {
panic!("Clock::advance on a real clock — use Clock::fixed() in tests")
}
}
}
pub fn is_virtual(&self) -> bool {
matches!(self.kind, ClockKind::Virtual { .. })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn virtual_clock_is_deterministic() {
let mut c = Clock::fixed();
assert_eq!(c.now(), Duration::ZERO);
c.advance(Duration::from_millis(16));
c.advance(Duration::from_millis(16));
assert_eq!(c.now(), Duration::from_millis(32));
}
#[test]
fn real_clock_moves_forward() {
let c = Clock::real();
let a = c.now();
let b = c.now();
assert!(b >= a);
}
#[test]
#[should_panic(expected = "real clock")]
fn advancing_a_real_clock_is_a_harness_bug() {
Clock::real().advance(Duration::from_millis(1));
}
}