use std::time::{Duration, Instant};
#[derive(Clone, Copy, Debug)]
pub struct CloseBudget {
limit: Duration,
started: Instant,
}
impl CloseBudget {
pub fn start(limit: Duration) -> CloseBudget {
CloseBudget {
limit,
started: Instant::now(),
}
}
pub const fn limit(&self) -> Duration {
self.limit
}
pub fn remaining(&self) -> Duration {
self.limit.saturating_sub(self.started.elapsed())
}
pub fn is_spent(&self) -> bool {
self.remaining().is_zero()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_budget_is_spent_by_the_phases_that_share_it() {
let budget = CloseBudget::start(Duration::from_millis(50));
assert_eq!(budget.limit(), Duration::from_millis(50));
let before = budget.remaining();
assert!(before <= Duration::from_millis(50));
std::thread::sleep(Duration::from_millis(10));
let after = budget.remaining();
assert!(after < before, "{after:?} must be less than {before:?}");
assert!(!budget.is_spent());
}
#[test]
fn an_overrun_budget_is_zero_and_not_negative() {
let budget = CloseBudget::start(Duration::from_millis(1));
std::thread::sleep(Duration::from_millis(5));
assert_eq!(budget.remaining(), Duration::ZERO);
assert!(budget.is_spent());
}
}