use crate::tmux::detector::Status;
pub const STREAK: u8 = 2;
#[derive(Debug, Default, Clone)]
pub struct Smoother {
current: Status,
candidate: Status,
streak: u8,
}
impl Smoother {
pub fn new() -> Self {
Self::default()
}
pub fn observe(&mut self, raw: Status) -> Status {
if self.current == Status::Unknown {
self.current = raw;
self.candidate = raw;
self.streak = STREAK;
return self.current;
}
if raw == Status::Unknown {
return self.current;
}
if raw == self.current {
self.candidate = self.current;
self.streak = STREAK;
return self.current;
}
if raw == Status::Running || raw == Status::Waiting {
self.current = raw;
self.candidate = raw;
self.streak = STREAK;
return self.current;
}
if raw != self.candidate {
self.candidate = raw;
self.streak = 1;
} else {
self.streak = self.streak.saturating_add(1);
}
if self.streak >= STREAK {
self.current = self.candidate;
}
self.current
}
pub fn current(&self) -> Status {
self.current
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn first_observation_sticks() {
let mut s = Smoother::new();
assert_eq!(s.observe(Status::Idle), Status::Idle);
}
#[test]
fn running_to_waiting_is_instant() {
let mut s = Smoother::new();
s.observe(Status::Running);
assert_eq!(s.observe(Status::Waiting), Status::Waiting);
}
#[test]
fn idle_to_running_is_instant() {
let mut s = Smoother::new();
s.observe(Status::Idle);
assert_eq!(s.observe(Status::Running), Status::Running);
}
#[test]
fn idle_to_waiting_is_instant() {
let mut s = Smoother::new();
s.observe(Status::Idle);
assert_eq!(s.observe(Status::Waiting), Status::Waiting);
}
#[test]
fn waiting_to_running_is_instant() {
let mut s = Smoother::new();
s.observe(Status::Waiting);
assert_eq!(s.observe(Status::Running), Status::Running);
}
#[test]
fn running_to_idle_needs_streak() {
let mut s = Smoother::new();
s.observe(Status::Running);
assert_eq!(s.observe(Status::Idle), Status::Running); assert_eq!(s.observe(Status::Idle), Status::Idle); }
#[test]
fn idle_flipflop_during_demotion_resets_streak() {
let mut s = Smoother::new();
s.observe(Status::Running);
assert_eq!(s.observe(Status::Idle), Status::Running); assert_eq!(s.observe(Status::Running), Status::Running);
assert_eq!(s.observe(Status::Idle), Status::Running); assert_eq!(s.observe(Status::Idle), Status::Idle); }
#[test]
fn unknown_does_not_disturb_state() {
let mut s = Smoother::new();
s.observe(Status::Running);
assert_eq!(s.observe(Status::Unknown), Status::Running);
assert_eq!(s.observe(Status::Unknown), Status::Running);
}
}