#[derive(Debug, Clone)]
pub struct StableDetector {
stable_count: usize,
threshold: usize,
}
impl StableDetector {
pub fn new() -> Self {
Self {
stable_count: 0,
threshold: 1,
}
}
pub fn with_threshold(threshold: usize) -> Self {
Self {
stable_count: 0,
threshold: threshold.max(1),
}
}
pub fn is_stable(queue_len: usize, pending_io_count: usize) -> bool {
queue_len == 0 && pending_io_count == 0
}
pub fn observe(&mut self, queue_len: usize, pending_io_count: usize) -> bool {
if Self::is_stable(queue_len, pending_io_count) {
self.stable_count = self.stable_count.saturating_add(1);
} else {
self.stable_count = 0;
}
self.stable_count >= self.threshold
}
pub fn reset(&mut self) {
self.stable_count = 0;
}
pub fn stable_count(&self) -> usize {
self.stable_count
}
}
impl Default for StableDetector {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use super::*;
#[test]
fn test_is_stable_static() {
assert!(StableDetector::is_stable(0, 0));
assert!(!StableDetector::is_stable(1, 0));
assert!(!StableDetector::is_stable(0, 1));
assert!(!StableDetector::is_stable(2, 3));
}
#[test]
fn test_observe_threshold_1() {
let mut det = StableDetector::new();
assert!(det.observe(0, 0));
assert_eq!(det.stable_count(), 1);
assert!(det.observe(0, 0));
assert_eq!(det.stable_count(), 2);
assert!(!det.observe(1, 0));
assert_eq!(det.stable_count(), 0);
assert!(det.observe(0, 0));
assert_eq!(det.stable_count(), 1);
}
#[test]
fn test_observe_threshold_3() {
let mut det = StableDetector::with_threshold(3);
assert!(!det.observe(0, 0));
assert_eq!(det.stable_count(), 1);
assert!(!det.observe(0, 0));
assert_eq!(det.stable_count(), 2);
assert!(det.observe(0, 0));
assert_eq!(det.stable_count(), 3);
assert!(!det.observe(0, 1));
assert_eq!(det.stable_count(), 0);
assert!(!det.observe(0, 0));
assert_eq!(det.stable_count(), 1);
}
#[test]
fn test_reset() {
let mut det = StableDetector::with_threshold(2);
det.observe(0, 0);
det.observe(0, 0);
assert_eq!(det.stable_count(), 2);
det.reset();
assert_eq!(det.stable_count(), 0);
}
#[test]
fn test_threshold_minimum_1() {
let det = StableDetector::with_threshold(0);
assert_eq!(det.threshold, 1);
}
}