use std::time::{Duration, Instant};
#[derive(Debug, Clone)]
pub struct RefreshPolicy {
pub min_interval: Duration,
pub max_interval: Duration,
pub step_interval: usize,
last_refresh: Instant,
last_step: usize,
}
impl Default for RefreshPolicy {
fn default() -> Self {
Self {
min_interval: Duration::from_millis(50),
max_interval: Duration::from_millis(1000),
step_interval: 10,
last_refresh: Instant::now(),
last_step: 0,
}
}
}
impl RefreshPolicy {
pub fn new(min_ms: u64, max_ms: u64, step_interval: usize) -> Self {
Self {
min_interval: Duration::from_millis(min_ms),
max_interval: Duration::from_millis(max_ms),
step_interval,
last_refresh: Instant::now(),
last_step: 0,
}
}
pub fn should_refresh(&mut self, global_step: usize) -> bool {
let elapsed = self.last_refresh.elapsed();
if elapsed >= self.max_interval {
self.last_refresh = Instant::now();
self.last_step = global_step;
return true;
}
if elapsed < self.min_interval {
return false;
}
if global_step.saturating_sub(self.last_step) >= self.step_interval {
self.last_refresh = Instant::now();
self.last_step = global_step;
return true;
}
false
}
pub fn force_refresh(&mut self, global_step: usize) {
self.last_refresh = Instant::now();
self.last_step = global_step;
}
#[cfg(test)]
fn advance_time(&mut self, duration: Duration) {
self.last_refresh -= duration;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_refresh_policy_default() {
let policy = RefreshPolicy::default();
assert_eq!(policy.min_interval, Duration::from_millis(50));
assert_eq!(policy.max_interval, Duration::from_millis(1000));
assert_eq!(policy.step_interval, 10);
}
#[test]
fn test_refresh_policy_new() {
let policy = RefreshPolicy::new(100, 500, 5);
assert_eq!(policy.min_interval, Duration::from_millis(100));
assert_eq!(policy.max_interval, Duration::from_millis(500));
assert_eq!(policy.step_interval, 5);
}
#[test]
fn test_refresh_policy_rate_limiting() {
let mut policy = RefreshPolicy::new(10_000, 60_000, 1);
policy.force_refresh(0);
let blocked = !policy.should_refresh(1);
assert!(blocked, "Immediate refresh should be blocked");
policy.advance_time(Duration::from_millis(15_000));
let allowed = policy.should_refresh(2);
assert!(allowed, "Refresh should be allowed after min_interval");
}
#[test]
fn test_refresh_policy_step_interval() {
let mut policy = RefreshPolicy::new(0, 10000, 10);
policy.force_refresh(0);
policy.advance_time(Duration::from_millis(20));
assert!(!policy.should_refresh(5));
assert!(policy.should_refresh(10));
}
#[test]
fn test_refresh_policy_force_refresh() {
let mut policy = RefreshPolicy::default();
policy.force_refresh(100);
assert_eq!(policy.last_step, 100);
}
#[test]
fn test_refresh_policy_max_interval_triggers() {
let mut policy = RefreshPolicy::new(10, 50, 1000);
policy.force_refresh(0);
policy.advance_time(Duration::from_millis(500));
assert!(policy.should_refresh(1));
}
#[test]
fn test_refresh_policy_clone() {
let policy = RefreshPolicy::new(100, 500, 5);
let cloned = policy.clone();
assert_eq!(policy.min_interval, cloned.min_interval);
assert_eq!(policy.max_interval, cloned.max_interval);
assert_eq!(policy.step_interval, cloned.step_interval);
}
#[test]
fn test_refresh_policy_debug() {
let policy = RefreshPolicy::default();
let debug_str = format!("{policy:?}");
assert!(debug_str.contains("RefreshPolicy"));
}
#[test]
fn test_refresh_policy_no_refresh_below_step_interval() {
let mut policy = RefreshPolicy::new(0, 10000, 100);
policy.force_refresh(0);
policy.advance_time(Duration::from_millis(20));
assert!(!policy.should_refresh(50));
assert!(!policy.should_refresh(99));
assert!(policy.should_refresh(100));
}
}