pub const SECOND_PRESS_SECS: f32 = 4.0;
#[derive(Clone, Debug, PartialEq)]
pub struct SecondPress<T = ()> {
asked: Option<(f32, T)>,
}
impl<T> Default for SecondPress<T> {
fn default() -> Self {
Self { asked: None }
}
}
impl<T: PartialEq> SecondPress<T> {
pub fn asked(&self) -> bool {
self.asked.is_some()
}
pub fn lapse(&mut self, now: f32) -> bool {
let stale = self
.asked
.as_ref()
.is_some_and(|(at, _)| now - at > SECOND_PRESS_SECS);
if stale {
self.asked = None;
}
stale
}
pub fn press(&mut self, now: f32, about: T) -> bool {
match self.asked.take() {
Some((_, standing)) if standing == about => true,
_ => {
self.asked = Some((now, about));
false
}
}
}
pub fn take_back(&mut self) -> bool {
self.asked.take().is_some()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_second_press_soon_after_on_the_same_thing_says_yes() {
let mut q = SecondPress::default();
assert!(!q.press(0.0, 1), "the first press asks");
assert!(q.asked());
assert!(!q.lapse(SECOND_PRESS_SECS - 0.5));
assert!(q.press(SECOND_PRESS_SECS - 0.5, 1), "the second answers");
assert!(!q.asked(), "and settles it");
assert!(!q.press(0.0, 1));
assert!(!q.press(1.0, 2), "a different thing is a new question");
assert!(q.press(2.0, 2));
assert!(!q.press(0.0, 3));
assert!(q.lapse(SECOND_PRESS_SECS + 0.1));
assert!(!q.press(SECOND_PRESS_SECS + 0.2, 3));
assert!(q.take_back());
assert!(!q.take_back(), "nothing left to take back");
assert!(!q.press(10.0, 3));
}
}