1use serde::{Deserialize, Serialize};
4use std::fmt;
5use std::ops::{Add, Sub};
6use vek::num_traits::SaturatingSub;
7
8pub type SnapTick = i32;
10
11#[derive(
12 Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
13)]
14pub struct Instant(i64);
16
17impl Add<Duration> for Instant {
18 type Output = Instant;
19 fn add(self, rhs: Duration) -> Self::Output {
20 Instant(self.0 + rhs.0 as i64)
21 }
22}
23
24impl Sub<Duration> for Instant {
25 type Output = Instant;
26 fn sub(self, rhs: Duration) -> Self::Output {
27 Instant(self.0 - rhs.0 as i64)
28 }
29}
30
31impl Instant {
32 pub fn duration_passed_since(self, past_time: Instant, duration: Duration) -> bool {
34 past_time.0 + duration.0 as i64 <= self.0
35 }
36
37 pub fn duration_since(self, past_time: Instant) -> Option<Duration> {
38 Some(Duration(self.0.checked_sub(past_time.0)? as u32))
39 }
40
41 pub fn advance(&self) -> Self {
42 Self(self.0 + 1)
43 }
44
45 pub const fn zero() -> Instant {
46 Instant(0)
47 }
48
49 pub fn seconds(&self) -> f32 {
50 self.0 as f32 / 50.0
51 }
52
53 pub fn snap_tick(self) -> SnapTick {
54 self.0.try_into().unwrap()
55 }
56
57 pub fn from_snap_tick(t: SnapTick) -> Self {
58 Self(t.into())
59 }
60}
61
62impl fmt::Display for Duration {
63 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
64 let days = self.0 / 50 / 60 / 60 / 24;
65 let hours = self.0 / 50 / 60 / 60 % 24;
66 let minutes = self.0 / 50 / 60 % 60;
67 let seconds = self.0 / 50 % 60;
68 let sub_seconds = (self.0 % 50) * 2;
69 let ticks = self.0;
70 if days > 0 {
71 write!(
72 f,
73 "{days}d {hours:02}:{minutes:02}:{seconds:02}.{sub_seconds:02} ({ticks})"
74 )
75 } else if hours > 0 {
76 write!(
77 f,
78 "{hours:02}:{minutes:02}:{seconds:02}.{sub_seconds:02} ({ticks})"
79 )
80 } else {
81 write!(f, "{minutes:02}:{seconds:02}.{sub_seconds:02} ({ticks})",)
82 }
83 }
84}
85
86impl fmt::Display for Instant {
87 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
89 let days = self.0 / 50 / 60 / 60 / 24;
90 let hours = self.0 / 50 / 60 / 60 % 24;
91 let minutes = self.0 / 50 / 60 % 60;
92 let seconds = self.0 / 50 % 60;
93 let ticks = self.0;
94 if days > 0 {
95 write!(f, "{days}d {hours:02}:{minutes:02}:{seconds:02} ({ticks})")
96 } else if hours > 0 {
97 write!(f, "{hours:02}:{minutes:02}:{seconds:02} ({ticks})")
98 } else {
99 write!(f, "{minutes:02}:{seconds:02} ({ticks})",)
100 }
101 }
102}
103
104#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
106pub struct Duration(u32);
107
108impl Add<Duration> for Duration {
109 type Output = Duration;
110 fn add(self, rhs: Duration) -> Self::Output {
111 Duration(self.0 + rhs.0)
112 }
113}
114
115impl Sub<Self> for Duration {
116 type Output = Duration;
117
118 fn sub(self, rhs: Self) -> Self::Output {
119 Duration(self.0.sub(rhs.0))
120 }
121}
122
123impl SaturatingSub for Duration {
124 fn saturating_sub(&self, rhs: &Self) -> Self {
125 Duration(self.0.saturating_sub(rhs.0))
126 }
127}
128
129impl Duration {
130 pub fn decrement(self) -> Option<Duration> {
131 self.0.checked_sub(1).map(Duration)
132 }
133
134 pub fn seconds(self) -> f32 {
135 self.0 as f32 / 50.0
136 }
137
138 pub fn ticks(self) -> SnapTick {
139 self.0.try_into().unwrap()
140 }
141
142 pub fn from_ticks(n: SnapTick) -> Duration {
144 Duration(if n.is_negative() { 0 } else { n as u32 })
145 }
146
147 pub const fn from_min(n: u32) -> Duration {
148 Duration(n * 50 * 60)
149 }
150
151 pub const fn from_secs(n: u32) -> Duration {
152 Duration(n * 50)
153 }
154
155 pub fn from_secs_f32(s: f32) -> Duration {
156 Duration((s * 50.0) as u32)
157 }
158
159 pub fn from_ms_f32(ms: f32) -> Duration {
160 Duration(ms as u32 / 20)
161 }
162
163 pub const T0MS: Duration = Duration(0);
164 pub const T20MS: Duration = Duration(1);
165 pub const T40MS: Duration = Duration(2);
166 pub const T60MS: Duration = Duration(3);
167 pub const T80MS: Duration = Duration(4);
168 pub const T100MS: Duration = Duration(5);
169 pub const T120MS: Duration = Duration(6);
170 pub const T140MS: Duration = Duration(7);
171 pub const T160MS: Duration = Duration(8);
172 pub const T180MS: Duration = Duration(9);
173 pub const T200MS: Duration = Duration(10);
174 pub const T220MS: Duration = Duration(11);
175 pub const T240MS: Duration = Duration(12);
176 pub const T260MS: Duration = Duration(13);
177 pub const T280MS: Duration = Duration(14);
178 pub const T300MS: Duration = Duration(15);
179 pub const T320MS: Duration = Duration(16);
180 pub const T340MS: Duration = Duration(17);
181 pub const T360MS: Duration = Duration(18);
182 pub const T380MS: Duration = Duration(19);
183 pub const T400MS: Duration = Duration(20);
184 pub const T420MS: Duration = Duration(21);
185 pub const T440MS: Duration = Duration(22);
186 pub const T460MS: Duration = Duration(23);
187 pub const T480MS: Duration = Duration(24);
188 pub const T500MS: Duration = Duration(25);
189 pub const T520MS: Duration = Duration(26);
190 pub const T540MS: Duration = Duration(27);
191 pub const T560MS: Duration = Duration(28);
192 pub const T580MS: Duration = Duration(29);
193 pub const T600MS: Duration = Duration(30);
194 pub const T620MS: Duration = Duration(31);
195 pub const T640MS: Duration = Duration(32);
196 pub const T660MS: Duration = Duration(33);
197 pub const T680MS: Duration = Duration(34);
198 pub const T700MS: Duration = Duration(35);
199 pub const T720MS: Duration = Duration(36);
200 pub const T740MS: Duration = Duration(37);
201 pub const T760MS: Duration = Duration(38);
202 pub const T780MS: Duration = Duration(39);
203 pub const T800MS: Duration = Duration(40);
204 pub const T820MS: Duration = Duration(41);
205 pub const T840MS: Duration = Duration(42);
206 pub const T860MS: Duration = Duration(43);
207 pub const T880MS: Duration = Duration(44);
208 pub const T900MS: Duration = Duration(45);
209 pub const T920MS: Duration = Duration(46);
210 pub const T940MS: Duration = Duration(47);
211 pub const T960MS: Duration = Duration(48);
212 pub const T980MS: Duration = Duration(49);
213}
214
215#[cfg(test)]
216mod test {
217 use super::*;
218
219 #[test]
220 fn simple() {
221 let a = Instant(150);
222 let b = Instant(50);
223 assert!(a.duration_passed_since(b, Duration::from_secs(1)));
224 assert!(a.duration_passed_since(b, Duration::from_secs(2)));
225 assert!(!a.duration_passed_since(b, Duration::from_secs(3)));
226 assert!(!a.duration_passed_since(b, Duration::from_secs(5)));
227 }
228}