use serde::{Deserialize, Serialize};
use std::fmt;
use std::ops::{Add, Sub};
use vek::num_traits::SaturatingSub;
pub type SnapTick = i32;
#[derive(
Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
)]
pub struct Instant(i64);
impl Add<Duration> for Instant {
type Output = Instant;
fn add(self, rhs: Duration) -> Self::Output {
Instant(self.0 + rhs.0 as i64)
}
}
impl Sub<Duration> for Instant {
type Output = Instant;
fn sub(self, rhs: Duration) -> Self::Output {
Instant(self.0 - rhs.0 as i64)
}
}
impl Instant {
pub fn duration_passed_since(self, past_time: Instant, duration: Duration) -> bool {
past_time.0 + duration.0 as i64 <= self.0
}
pub fn duration_since(self, past_time: Instant) -> Option<Duration> {
Some(Duration(self.0.checked_sub(past_time.0)? as u32))
}
pub fn advance(&self) -> Self {
Self(self.0 + 1)
}
pub const fn zero() -> Instant {
Instant(0)
}
pub fn seconds(&self) -> f32 {
self.0 as f32 / 50.0
}
pub fn snap_tick(self) -> SnapTick {
self.0.try_into().unwrap()
}
pub fn from_snap_tick(t: SnapTick) -> Self {
Self(t.into())
}
}
impl fmt::Display for Duration {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let days = self.0 / 50 / 60 / 60 / 24;
let hours = self.0 / 50 / 60 / 60 % 24;
let minutes = self.0 / 50 / 60 % 60;
let seconds = self.0 / 50 % 60;
let sub_seconds = (self.0 % 50) * 2;
let ticks = self.0;
if days > 0 {
write!(
f,
"{days}d {hours:02}:{minutes:02}:{seconds:02}.{sub_seconds:02} ({ticks})"
)
} else if hours > 0 {
write!(
f,
"{hours:02}:{minutes:02}:{seconds:02}.{sub_seconds:02} ({ticks})"
)
} else {
write!(f, "{minutes:02}:{seconds:02}.{sub_seconds:02} ({ticks})",)
}
}
}
impl fmt::Display for Instant {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let days = self.0 / 50 / 60 / 60 / 24;
let hours = self.0 / 50 / 60 / 60 % 24;
let minutes = self.0 / 50 / 60 % 60;
let seconds = self.0 / 50 % 60;
let ticks = self.0;
if days > 0 {
write!(f, "{days}d {hours:02}:{minutes:02}:{seconds:02} ({ticks})")
} else if hours > 0 {
write!(f, "{hours:02}:{minutes:02}:{seconds:02} ({ticks})")
} else {
write!(f, "{minutes:02}:{seconds:02} ({ticks})",)
}
}
}
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Duration(u32);
impl Add<Duration> for Duration {
type Output = Duration;
fn add(self, rhs: Duration) -> Self::Output {
Duration(self.0 + rhs.0)
}
}
impl Sub<Self> for Duration {
type Output = Duration;
fn sub(self, rhs: Self) -> Self::Output {
Duration(self.0.sub(rhs.0))
}
}
impl SaturatingSub for Duration {
fn saturating_sub(&self, rhs: &Self) -> Self {
Duration(self.0.saturating_sub(rhs.0))
}
}
impl Duration {
pub fn decrement(self) -> Option<Duration> {
self.0.checked_sub(1).map(Duration)
}
pub fn seconds(self) -> f32 {
self.0 as f32 / 50.0
}
pub fn ticks(self) -> SnapTick {
self.0.try_into().unwrap()
}
pub fn from_ticks(n: SnapTick) -> Duration {
Duration(if n.is_negative() { 0 } else { n as u32 })
}
pub const fn from_min(n: u32) -> Duration {
Duration(n * 50 * 60)
}
pub const fn from_secs(n: u32) -> Duration {
Duration(n * 50)
}
pub fn from_secs_f32(s: f32) -> Duration {
Duration((s * 50.0) as u32)
}
pub fn from_ms_f32(ms: f32) -> Duration {
Duration(ms as u32 / 20)
}
pub const T0MS: Duration = Duration(0);
pub const T20MS: Duration = Duration(1);
pub const T40MS: Duration = Duration(2);
pub const T60MS: Duration = Duration(3);
pub const T80MS: Duration = Duration(4);
pub const T100MS: Duration = Duration(5);
pub const T120MS: Duration = Duration(6);
pub const T140MS: Duration = Duration(7);
pub const T160MS: Duration = Duration(8);
pub const T180MS: Duration = Duration(9);
pub const T200MS: Duration = Duration(10);
pub const T220MS: Duration = Duration(11);
pub const T240MS: Duration = Duration(12);
pub const T260MS: Duration = Duration(13);
pub const T280MS: Duration = Duration(14);
pub const T300MS: Duration = Duration(15);
pub const T320MS: Duration = Duration(16);
pub const T340MS: Duration = Duration(17);
pub const T360MS: Duration = Duration(18);
pub const T380MS: Duration = Duration(19);
pub const T400MS: Duration = Duration(20);
pub const T420MS: Duration = Duration(21);
pub const T440MS: Duration = Duration(22);
pub const T460MS: Duration = Duration(23);
pub const T480MS: Duration = Duration(24);
pub const T500MS: Duration = Duration(25);
pub const T520MS: Duration = Duration(26);
pub const T540MS: Duration = Duration(27);
pub const T560MS: Duration = Duration(28);
pub const T580MS: Duration = Duration(29);
pub const T600MS: Duration = Duration(30);
pub const T620MS: Duration = Duration(31);
pub const T640MS: Duration = Duration(32);
pub const T660MS: Duration = Duration(33);
pub const T680MS: Duration = Duration(34);
pub const T700MS: Duration = Duration(35);
pub const T720MS: Duration = Duration(36);
pub const T740MS: Duration = Duration(37);
pub const T760MS: Duration = Duration(38);
pub const T780MS: Duration = Duration(39);
pub const T800MS: Duration = Duration(40);
pub const T820MS: Duration = Duration(41);
pub const T840MS: Duration = Duration(42);
pub const T860MS: Duration = Duration(43);
pub const T880MS: Duration = Duration(44);
pub const T900MS: Duration = Duration(45);
pub const T920MS: Duration = Duration(46);
pub const T940MS: Duration = Duration(47);
pub const T960MS: Duration = Duration(48);
pub const T980MS: Duration = Duration(49);
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn simple() {
let a = Instant(150);
let b = Instant(50);
assert!(a.duration_passed_since(b, Duration::from_secs(1)));
assert!(a.duration_passed_since(b, Duration::from_secs(2)));
assert!(!a.duration_passed_since(b, Duration::from_secs(3)));
assert!(!a.duration_passed_since(b, Duration::from_secs(5)));
}
}