use std::cmp;
use std::thread;
use std::time::{Duration, Instant};
use ::shared::config::Config;
#[derive(Debug)]
pub struct Ticker {
tick_start: Instant,
tick_overflow: u64,
tick_overflow_recovery: bool,
tick_overflow_recovery_rate: f32,
tick_delay: u64
}
impl Ticker {
pub fn new(config: Config) -> Ticker {
Ticker {
tick_start: Instant::now(),
tick_overflow: 0,
tick_overflow_recovery: config.tick_overflow_recovery,
tick_overflow_recovery_rate: config.tick_overflow_recovery_rate,
tick_delay: 1000000000 / config.send_rate
}
}
pub fn set_config(&mut self, config: Config) {
self.tick_overflow_recovery = config.tick_overflow_recovery;
self.tick_overflow_recovery_rate = config.tick_overflow_recovery_rate;
self.tick_delay = 1000000000 / config.send_rate
}
pub fn begin_tick(&mut self) {
self.tick_start = Instant::now();
}
pub fn reset(&mut self) {
self.tick_start = Instant::now();
self.tick_overflow = 0;
}
pub fn end_tick(&mut self) {
let time_taken = nanos_from_duration(self.tick_start.elapsed());
let mut reduction = cmp::min(time_taken, self.tick_delay);
if self.tick_overflow_recovery {
self.tick_overflow += time_taken - reduction;
let max_correction = (self.tick_delay - reduction) as i64;
let correction = cmp::min(
(max_correction as f32 * self.tick_overflow_recovery_rate) as i64,
max_correction
);
let reduced_overflow = cmp::max(0, self.tick_overflow as i64 - correction) as u64;
reduction += self.tick_overflow - reduced_overflow;
self.tick_overflow = reduced_overflow;
}
thread::sleep(Duration::new(0, (self.tick_delay - reduction) as u32));
}
}
fn nanos_from_duration(d: Duration) -> u64 {
d.as_secs() * 1000 * 1000000 + d.subsec_nanos() as u64
}