diff options
Diffstat (limited to 'src/animation/clock.rs')
| -rw-r--r-- | src/animation/clock.rs | 191 |
1 files changed, 176 insertions, 15 deletions
diff --git a/src/animation/clock.rs b/src/animation/clock.rs index 3cfa727b..30f8bd45 100644 --- a/src/animation/clock.rs +++ b/src/animation/clock.rs @@ -1,41 +1,202 @@ -use std::cell::Cell; +use std::cell::RefCell; use std::rc::Rc; use std::time::Duration; use crate::utils::get_monotonic_time; -/// Clock that can have its time value overridden. +/// Shareable lazy clock that can change rate. /// -/// Can be cloned to share the same clock. +/// The clock will fetch the time once and then retain it until explicitly cleared with +/// [`Clock::clear`]. #[derive(Debug, Default, Clone)] pub struct Clock { - time_override: Rc<Cell<Option<Duration>>>, + inner: Rc<RefCell<AdjustableClock>>, +} + +#[derive(Debug, Default)] +struct LazyClock { + time: Option<Duration>, +} + +/// Clock that can adjust its rate. +#[derive(Debug)] +struct AdjustableClock { + inner: LazyClock, + current_time: Duration, + last_seen_time: Duration, + rate: f64, + complete_instantly: bool, } impl Clock { - /// Creates a new [`Clock`] with time override in place. - pub fn with_override(time: Duration) -> Self { + /// Creates a new clock with the given time. + pub fn with_time(time: Duration) -> Self { + let clock = AdjustableClock::new(LazyClock::with_time(time)); Self { - time_override: Rc::new(Cell::new(Some(time))), + inner: Rc::new(RefCell::new(clock)), } } - /// Sets the current time override. - pub fn set_time_override(&mut self, time: Option<Duration>) { - self.time_override.set(time); + /// Returns the current time. + pub fn now(&self) -> Duration { + self.inner.borrow_mut().now() } - /// Gets the current time. - #[inline] - pub fn now(&self) -> Duration { - self.time_override.get().unwrap_or_else(get_monotonic_time) + /// Returns the underlying time not adjusted for rate change. + pub fn now_unadjusted(&self) -> Duration { + self.inner.borrow_mut().inner.now() + } + + /// Sets the unadjusted clock time. + pub fn set_unadjusted(&mut self, time: Duration) { + self.inner.borrow_mut().inner.set(time); + } + + /// Clears the stored time so it's re-fetched again next. + pub fn clear(&mut self) { + self.inner.borrow_mut().inner.clear(); + } + + /// Gets the clock rate. + pub fn rate(&self) -> f64 { + self.inner.borrow().rate() + } + + /// Sets the clock rate. + pub fn set_rate(&mut self, rate: f64) { + self.inner.borrow_mut().set_rate(rate); + } + + /// Returns whether animations should complete instantly. + pub fn should_complete_instantly(&self) -> bool { + self.inner.borrow().should_complete_instantly() + } + + /// Sets whether animations should complete instantly. + pub fn set_complete_instantly(&mut self, value: bool) { + self.inner.borrow_mut().set_complete_instantly(value); } } impl PartialEq for Clock { fn eq(&self, other: &Self) -> bool { - Rc::ptr_eq(&self.time_override, &other.time_override) + Rc::ptr_eq(&self.inner, &other.inner) } } impl Eq for Clock {} + +impl LazyClock { + pub fn with_time(time: Duration) -> Self { + Self { time: Some(time) } + } + + pub fn clear(&mut self) { + self.time = None; + } + + pub fn set(&mut self, time: Duration) { + self.time = Some(time); + } + + pub fn now(&mut self) -> Duration { + *self.time.get_or_insert_with(get_monotonic_time) + } +} + +impl AdjustableClock { + pub fn new(mut inner: LazyClock) -> Self { + let time = inner.now(); + Self { + inner, + current_time: time, + last_seen_time: time, + rate: 1., + complete_instantly: false, + } + } + + pub fn rate(&self) -> f64 { + self.rate + } + + pub fn set_rate(&mut self, rate: f64) { + self.rate = rate.clamp(0., 1000.); + } + + pub fn should_complete_instantly(&self) -> bool { + self.complete_instantly + } + + pub fn set_complete_instantly(&mut self, value: bool) { + self.complete_instantly = value; + } + + pub fn now(&mut self) -> Duration { + let time = self.inner.now(); + + if self.last_seen_time == time { + return self.current_time; + } + + if self.last_seen_time < time { + let delta = time - self.last_seen_time; + let delta = delta.mul_f64(self.rate); + self.current_time = self.current_time.saturating_add(delta); + } else { + let delta = self.last_seen_time - time; + let delta = delta.mul_f64(self.rate); + self.current_time = self.current_time.saturating_sub(delta); + } + + self.last_seen_time = time; + self.current_time + } +} + +impl Default for AdjustableClock { + fn default() -> Self { + Self::new(LazyClock::default()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn frozen_clock() { + let mut clock = Clock::with_time(Duration::ZERO); + assert_eq!(clock.now(), Duration::ZERO); + + clock.set_unadjusted(Duration::from_millis(100)); + assert_eq!(clock.now(), Duration::from_millis(100)); + + clock.set_unadjusted(Duration::from_millis(200)); + assert_eq!(clock.now(), Duration::from_millis(200)); + } + + #[test] + fn rate_change() { + let mut clock = Clock::with_time(Duration::ZERO); + clock.set_rate(0.5); + + clock.set_unadjusted(Duration::from_millis(100)); + assert_eq!(clock.now_unadjusted(), Duration::from_millis(100)); + assert_eq!(clock.now(), Duration::from_millis(50)); + + clock.set_unadjusted(Duration::from_millis(200)); + assert_eq!(clock.now_unadjusted(), Duration::from_millis(200)); + assert_eq!(clock.now(), Duration::from_millis(100)); + + clock.set_unadjusted(Duration::from_millis(150)); + assert_eq!(clock.now_unadjusted(), Duration::from_millis(150)); + assert_eq!(clock.now(), Duration::from_millis(75)); + + clock.set_rate(2.0); + + clock.set_unadjusted(Duration::from_millis(250)); + assert_eq!(clock.now_unadjusted(), Duration::from_millis(250)); + assert_eq!(clock.now(), Duration::from_millis(275)); + } +} |
