use std::time::{Duration, Instant};
pub(super) const HOLD: Duration = Duration::from_millis(250);
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(super) enum Settled {
Open,
Waiting,
Changed,
}
pub(super) struct Settle<T> {
opened: T,
pending: Option<(T, Instant)>,
}
impl<T: Clone + PartialEq> Settle<T> {
pub fn new(opened: T) -> Self {
Self { opened, pending: None }
}
pub fn observe(&mut self, current: &T, now: Instant) -> Settled {
if *current == self.opened {
self.pending = None;
return Settled::Open;
}
match &self.pending {
Some((pending, since)) if pending == current => {
if now.saturating_duration_since(*since) >= HOLD {
Settled::Changed
} else {
Settled::Waiting
}
}
_ => {
self.pending = Some((current.clone(), now));
Settled::Waiting
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_open_geometry_captures() {
let start = Instant::now();
let mut settle = Settle::new((1920u32, 1080u32));
assert_eq!(settle.observe(&(1920, 1080), start), Settled::Open);
assert_eq!(settle.observe(&(1920, 1080), start + HOLD * 4), Settled::Open);
}
#[test]
fn a_change_ends_the_stream_once_it_holds() {
let start = Instant::now();
let mut settle = Settle::new((1920u32, 1080u32));
assert_eq!(settle.observe(&(1280, 720), start), Settled::Waiting);
assert_eq!(settle.observe(&(1280, 720), start + HOLD / 2), Settled::Waiting);
assert_eq!(settle.observe(&(1280, 720), start + HOLD), Settled::Changed);
}
#[test]
fn a_drag_restarts_the_wait_on_every_new_size() {
let start = Instant::now();
let mut settle = Settle::new((1920u32, 1080u32));
let mut now = start;
for step in 1..=(2 * HOLD.as_millis() / 10) as u32 {
now = start + Duration::from_millis(u64::from(step) * 10);
assert_eq!(settle.observe(&(1920 - step * 2, 1080), now), Settled::Waiting);
}
let last = (1920 - (2 * HOLD.as_millis() / 10) as u32 * 2, 1080);
assert_eq!(settle.observe(&last, now + HOLD / 2), Settled::Waiting);
assert_eq!(settle.observe(&last, now + HOLD), Settled::Changed);
}
#[test]
fn a_drag_back_to_the_open_geometry_cancels() {
let start = Instant::now();
let mut settle = Settle::new((1920u32, 1080u32));
assert_eq!(settle.observe(&(1280, 720), start), Settled::Waiting);
assert_eq!(settle.observe(&(1920, 1080), start + HOLD / 2), Settled::Open);
assert_eq!(settle.observe(&(1280, 720), start + HOLD), Settled::Waiting);
assert_eq!(settle.observe(&(1280, 720), start + HOLD * 2), Settled::Changed);
}
}