use std::time::Duration;
use tokio::time::{Instant, interval_at};
pub struct Pacer {
inner: tokio::time::Interval,
}
impl Pacer {
#[must_use]
pub fn new(msgs_per_sec: u64) -> Self {
let rate = msgs_per_sec.max(1);
let period = Duration::from_nanos(1_000_000_000u64 / rate);
let mut inner = interval_at(Instant::now() + period, period);
inner.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
Self { inner }
}
pub async fn await_token(&mut self) {
self.inner.tick().await;
}
}
#[cfg(test)]
mod tests {
use super::*;
use assert2::assert;
#[tokio::test(start_paused = true)]
async fn pacer_spaces_ticks() {
let mut p = Pacer::new(1000); let start = Instant::now();
for _ in 0..5 {
p.await_token().await;
}
let elapsed = start.elapsed();
assert!(elapsed >= Duration::from_millis(5));
}
#[tokio::test]
async fn zero_rate_clamped_does_not_panic() {
let _ = Pacer::new(0);
}
}