use std::{
cmp::Ordering,
time::{Duration, Instant},
};
pub const INFINITE_DURATION: Duration = Duration::new(u64::MAX, 1_000_000_000 - 1);
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum TimerDuration {
Elapsed,
Real(Duration),
Infinite,
}
impl TimerDuration {
pub fn from_difference(a: TimerDuration, b: Duration) -> TimerDuration {
let a = a.to_real();
if a < b {
TimerDuration::Elapsed
} else {
TimerDuration::Real(a - b)
}
}
pub fn to_real(&self) -> Duration {
match *self {
Self::Real(d) if d > Duration::ZERO => d,
Self::Infinite => INFINITE_DURATION,
_ => Duration::new(0, 0),
}
}
}
impl From<Duration> for TimerDuration {
fn from(value: Duration) -> Self {
if value == Duration::ZERO {
return Self::Elapsed;
}
Self::Real(value)
}
}
impl PartialOrd for TimerDuration {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for TimerDuration {
fn cmp(&self, other: &Self) -> Ordering {
match (self, other) {
(TimerDuration::Elapsed, TimerDuration::Elapsed) => Ordering::Equal,
(TimerDuration::Elapsed, _) => Ordering::Less,
(TimerDuration::Real(_), TimerDuration::Elapsed) => Ordering::Greater,
(TimerDuration::Real(a), TimerDuration::Real(b)) => a.cmp(b),
(TimerDuration::Real(_), TimerDuration::Infinite) => Ordering::Less,
(TimerDuration::Infinite, TimerDuration::Infinite) => Ordering::Equal,
(TimerDuration::Infinite, _) => Ordering::Greater,
}
}
}
#[derive(Clone, Copy)]
pub struct Timer(Instant, TimerDuration);
impl Timer {
pub fn new(d: TimerDuration) -> Self {
Self(Instant::now(), d)
}
pub fn time_elapsed(&self) -> Duration {
self.0.elapsed()
}
}
pub trait Timed {
fn has_elapsed(&self) -> bool;
fn time_left(&self) -> TimerDuration;
}
impl Timed for Timer {
fn has_elapsed(&self) -> bool {
self.0.elapsed() >= self.1.to_real()
}
fn time_left(&self) -> TimerDuration {
TimerDuration::from_difference(self.1, self.0.elapsed())
}
}