use std::time::{Duration, Instant};
use super::sleep::sleep_until;
#[derive(Debug)]
pub struct Interval {
first_ticked: bool,
start: Instant,
period: Duration,
}
impl Interval {
pub(crate) fn new(start: Instant, period: Duration) -> Self {
Self {
first_ticked: false,
start,
period,
}
}
pub fn reset(&mut self, start: Option<Instant>) {
self.start = start.unwrap_or_else(Instant::now);
self.first_ticked = false;
}
pub async fn tick(&mut self) -> Instant {
if !self.first_ticked {
sleep_until(self.start).await;
self.first_ticked = true;
self.start
} else {
let now = Instant::now();
let elapsed_ns = (now - self.start).as_nanos();
let period_ns = self.period.as_nanos();
let drift_ns = (elapsed_ns % period_ns) as u64;
let next = now + self.period - Duration::from_nanos(drift_ns);
sleep_until(next).await;
next
}
}
}
pub fn interval(period: Duration) -> Interval {
interval_at(Instant::now(), period)
}
pub fn interval_at(start: Instant, period: Duration) -> Interval {
assert!(period > Duration::ZERO, "`period` must be non-zero.");
Interval::new(start, period)
}