use std::time::{Duration, Instant};
#[derive(Debug, Default, Clone, Copy)]
pub struct RequestGapTracker {
last_request_at: Option<Instant>,
}
impl RequestGapTracker {
pub fn note_request_sent(&mut self) {
self.last_request_at = Some(Instant::now());
}
pub fn cache_gap_exceeds(&self, threshold: Duration) -> Option<Duration> {
let last_request_at = self.last_request_at?;
let elapsed = last_request_at.elapsed();
(elapsed > threshold).then_some(elapsed)
}
pub fn has_sent_request(&self) -> bool {
self.last_request_at.is_some()
}
}
pub fn format_gap(elapsed: Duration) -> String {
let secs = elapsed.as_secs();
if secs < 60 {
format!("{secs}s")
} else {
format!("{} min", secs / 60)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cache_gap_exceeds_is_none_without_a_prior_request() {
let tracker = RequestGapTracker::default();
assert_eq!(tracker.cache_gap_exceeds(Duration::from_millis(1)), None);
}
#[test]
fn cache_gap_exceeds_is_none_below_threshold() {
let mut tracker = RequestGapTracker::default();
tracker.note_request_sent();
assert_eq!(tracker.cache_gap_exceeds(Duration::from_secs(60)), None);
}
#[test]
fn cache_gap_exceeds_is_some_above_threshold() {
let mut tracker = RequestGapTracker::default();
tracker.note_request_sent();
std::thread::sleep(Duration::from_millis(10));
let gap = tracker.cache_gap_exceeds(Duration::from_millis(5));
assert!(gap.is_some());
}
#[test]
fn has_sent_request_is_false_until_note_request_sent() {
let mut tracker = RequestGapTracker::default();
assert!(!tracker.has_sent_request());
tracker.note_request_sent();
assert!(tracker.has_sent_request());
}
}