use crate::all::{Duration, Instant};
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Rate {
duration: Duration,
last_tick: Instant,
first_tick: Instant,
ticks: u64,
delta_rem: i32,
}
impl Default for Rate {
fn default() -> Self {
Self {
duration: Duration::ZERO,
first_tick: Instant::now(),
last_tick: Instant::now(),
ticks: 0,
delta_rem: 0,
}
}
}
impl Rate {
pub fn new(duration_per_tick: Duration) -> Self {
Self {
duration: duration_per_tick,
first_tick: Instant::now(),
last_tick: Instant::now(),
ticks: 0,
delta_rem: 0,
}
}
pub fn with_seconds(seconds_per_tick: f64) -> Self {
Self::new(Duration::seconds_f64(seconds_per_tick))
}
pub fn with_tps(ticks_per_second: f64) -> Self {
Self::new(Duration::seconds_f64(1.0 / ticks_per_second))
}
#[inline(always)]
pub fn reset(&mut self) {
self.ticks = 0;
self.first_tick = Instant::now();
self.last_tick = Instant::now();
self.delta_rem = 0;
}
#[inline(always)]
pub const fn ticks(&self) -> u64 {
self.ticks
}
#[inline(always)]
pub fn increment_ticks(&mut self) {
self.ticks += 1;
}
#[inline(always)]
pub const fn first_tick(&self) -> Instant {
self.first_tick
}
#[inline(always)]
pub fn set_first_tick(&mut self, instant: Instant) {
self.first_tick = instant;
}
#[inline(always)]
pub const fn last_tick(&self) -> Instant {
self.last_tick
}
#[inline(always)]
pub fn set_last_tick(&mut self, instant: Instant) {
self.last_tick = instant;
}
#[inline(always)]
pub const fn duration(&self) -> Duration {
self.duration
}
#[inline(always)]
pub fn tps(&self) -> f64 {
1. / self.duration.as_seconds_f64()
}
#[inline(always)]
pub fn set_duration(&mut self, duration_per_tick: Duration) {
self.duration = duration_per_tick;
}
#[inline(always)]
pub fn set_seconds(&mut self, seconds_per_tick: f64) {
self.duration = Duration::seconds_f64(seconds_per_tick);
}
#[inline(always)]
pub fn set_tps(&mut self, ticks_per_second: f64) {
self.duration = Duration::seconds_f64(1. / ticks_per_second);
}
#[inline]
pub fn do_tick(&mut self, instant: Instant) -> Option<Duration> {
let delta = self.last_elapsed(instant);
if (delta + Duration::new(0, self.delta_rem)) >= self.duration {
let lag: i128 = (delta - self.duration).whole_nanoseconds();
let lag_clamped = lag.clamp(i32::MIN as i128, i32::MAX as i128);
self.delta_rem = self.delta_rem.saturating_add(lag_clamped as i32);
self.increment_ticks();
self.set_last_tick(instant);
Some(delta)
} else {
None
}
}
#[inline(always)]
pub fn do_tick_now(&mut self) -> Option<Duration> {
self.do_tick(Instant::now())
}
#[inline]
pub fn do_tick_fast(&mut self, instant: Instant) -> Option<Duration> {
let delta = self.last_elapsed(instant);
if delta >= self.duration {
self.increment_ticks();
self.set_last_tick(instant);
Some(delta)
} else {
None
}
}
#[inline(always)]
pub fn do_tick_fast_now(&mut self) -> Option<Duration> {
self.do_tick_fast(Instant::now())
}
#[inline(always)]
pub fn first_elapsed(&self, instant: Instant) -> Duration {
instant - self.first_tick
}
#[inline(always)]
pub fn last_elapsed(&self, instant: Instant) -> Duration {
instant - self.last_tick
}
#[inline(always)]
pub fn tick_elapsed(&self, tick: u64, instant: Instant) -> Duration {
instant - self.instant_tick(tick)
}
#[inline(always)]
pub fn duration_ticks(&self, ticks: u64) -> Duration {
Duration::seconds_f64(self.duration.as_seconds_f64() * ticks as f64)
}
#[inline(always)]
pub fn instant_tick(&self, tick: u64) -> Instant {
self.first_tick + self.duration_ticks(tick)
}
#[inline(always)]
pub fn instant_tick_checked(&self, tick: u64) -> Option<Instant> {
self.first_tick.checked_add(self.duration_ticks(tick))
}
}
mod core_impl {
use super::Rate;
use core::fmt;
impl fmt::Display for Rate {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"#{:05}, tps:{}, Δdiff:{}",
self.ticks, self.duration, self.delta_rem,
)
}
}
}