1#![deny(missing_docs)]
30
31pub mod clocks;
32pub mod prelude;
33
34use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
35
36pub use crate::clocks::{Clock, DefaultClock};
37
38#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
49pub struct Instant(i64);
50impl Instant {
52 pub const EPOCH: Self = Self(0);
54
55 pub const FOREVER_AGO: Self = Self(i64::min_value());
57
58 pub const SOMEDAY: Self = Self(i64::max_value());
60}
61
62#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
68pub struct Duration(i64);
69impl Duration {
71 pub const NANOSECOND: Self = Self(1);
73
74 pub const MICROSECOND: Self = Self(1000 * Self::NANOSECOND.0);
76
77 pub const MILLISECOND: Self = Self(1000 * Self::MICROSECOND.0);
79
80 pub const SECOND: Self = Self(1000 * Self::MILLISECOND.0);
82
83 pub const MINUTE: Self = Self(60 * Self::SECOND.0);
85
86 pub const HOUR: Self = Self(60 * Self::MINUTE.0);
88
89 pub const FOREVER: Self = Self(i64::max_value());
96
97 pub const fn from_nanos(nanos: i64) -> Self {
99 Self(nanos)
100 }
101
102 pub const fn as_nanos(self) -> i64 {
104 self.0
105 }
106}
107
108impl Add<Duration> for Instant {
110 type Output = Instant;
111
112 fn add(self, rhs: Duration) -> Instant {
113 Instant(self.0 + rhs.0)
114 }
115}
116impl Add<Duration> for Duration {
118 type Output = Duration;
119
120 fn add(self, rhs: Duration) -> Duration {
121 Duration(self.0 + rhs.0)
122 }
123}
124impl Div<i64> for Duration {
126 type Output = Duration;
127
128 fn div(self, rhs: i64) -> Duration {
129 Duration(self.0 / rhs)
130 }
131}
132impl Mul<Duration> for i64 {
134 type Output = Duration;
135
136 fn mul(self, rhs: Duration) -> Duration {
137 Duration(self * rhs.0)
138 }
139}
140impl Mul<i64> for Duration {
142 type Output = Duration;
143
144 fn mul(self, rhs: i64) -> Duration {
145 Duration(self.0 * rhs)
146 }
147}
148impl Neg for Duration {
150 type Output = Duration;
151
152 fn neg(self) -> Duration {
153 Duration(-self.0)
154 }
155}
156impl Sub<Duration> for Instant {
158 type Output = Instant;
159
160 fn sub(self, rhs: Duration) -> Instant {
161 Instant(self.0 - rhs.0)
162 }
163}
164impl Sub<Duration> for Duration {
166 type Output = Duration;
167
168 fn sub(self, rhs: Duration) -> Duration {
169 Duration(self.0 - rhs.0)
170 }
171}
172impl Sub<Instant> for Instant {
174 type Output = Duration;
175
176 fn sub(self, rhs: Instant) -> Duration {
177 Duration(self.0 - rhs.0)
178 }
179}
180
181impl AddAssign<Duration> for Instant {
183 fn add_assign(&mut self, other: Duration) {
184 self.0 += other.0;
185 }
186}
187impl AddAssign<Duration> for Duration {
189 fn add_assign(&mut self, other: Duration) {
190 self.0 += other.0;
191 }
192}
193impl DivAssign<i64> for Duration {
195 fn div_assign(&mut self, other: i64) {
196 self.0 /= other
197 }
198}
199impl MulAssign<i64> for Duration {
201 fn mul_assign(&mut self, other: i64) {
202 self.0 *= other;
203 }
204}
205impl SubAssign<Duration> for Duration {
207 fn sub_assign(&mut self, other: Duration) {
208 self.0 -= other.0;
209 }
210}
211impl SubAssign<Duration> for Instant {
213 fn sub_assign(&mut self, other: Duration) {
214 self.0 -= other.0;
215 }
216}
217
218#[cfg(test)]
219mod tests {
220 use super::*;
221 use quickcheck::{Arbitrary, Gen};
222 use quickcheck_macros::quickcheck;
223 use std::convert::TryInto;
224
225 const MINUS_FOREVER: Duration = Duration(i64::min_value());
227
228 #[test]
231 fn special_instants() {
233 assert!(Instant::FOREVER_AGO < Instant::EPOCH);
235 assert!(Instant::FOREVER_AGO < Instant::SOMEDAY);
236 assert!(Instant::EPOCH < Instant::SOMEDAY);
237
238 assert_eq!(Instant::SOMEDAY - Instant::EPOCH, Duration::FOREVER);
240 assert_eq!(Instant::FOREVER_AGO - Instant::EPOCH, MINUS_FOREVER);
241 }
242
243 #[test]
244 fn special_durations() {
246 assert_eq!(Duration::default(), Duration(0));
248 assert_eq!(Duration::NANOSECOND, Duration(1));
249
250 assert!(Duration::NANOSECOND > Duration(0));
252 assert_eq!(Duration::NANOSECOND, Duration::from_nanos(1));
253 assert_eq!(Duration::NANOSECOND.as_nanos(), 1);
254
255 assert_eq!(Duration::MICROSECOND, 1000 * Duration::NANOSECOND);
257 assert_eq!(Duration::MILLISECOND, 1000 * Duration::MICROSECOND);
258 assert_eq!(Duration::SECOND, 1000 * Duration::MILLISECOND);
259 assert_eq!(Duration::MINUTE, 60 * Duration::SECOND);
260 assert_eq!(Duration::HOUR, 60 * Duration::MINUTE);
261
262 assert!(Duration::HOUR < Duration::FOREVER);
264 }
265
266 impl Arbitrary for Duration {
269 fn arbitrary<G: Gen>(g: &mut G) -> Self {
270 Duration(<i64 as Arbitrary>::arbitrary::<G>(g))
271 }
272 }
273
274 impl Arbitrary for Instant {
275 fn arbitrary<G: Gen>(g: &mut G) -> Self {
276 Instant(<i64 as Arbitrary>::arbitrary::<G>(g))
277 }
278 }
279
280 #[quickcheck]
281 fn duration_properties(d: Duration) -> bool {
283 let mut dt0 = d;
285 dt0 *= 0;
286 let mut dt1 = d;
287 dt1 *= 1;
288 let mut dd1 = d;
289 dd1 /= 1;
290 let always_check = d >= MINUS_FOREVER
291 && d <= Duration::FOREVER
292 && 0 * d == Duration::default()
293 && d * 0 == 0 * d
294 && dt0 == 0 * d
295 && 1 * d == d
296 && d * 1 == 1 * d
297 && dt1 == 1 * d
298 && d / 1 == d
299 && dd1 == d / 1
300 && Duration::from_nanos(d.as_nanos()) == d;
301
302 if d == MINUS_FOREVER {
305 return always_check;
306 }
307 let mut dtm1 = d;
308 dtm1 *= -1;
309 let mut ddm1 = d;
310 ddm1 /= -1;
311 (-d != d || d.as_nanos() == 0)
312 && (-1) * d == -d
313 && d * (-1) == -d
314 && d / (-1) == -d
315 && dtm1 == -d
316 && ddm1 == -d
317 && -(-d) == d
318 }
319
320 #[quickcheck]
321 fn duration_duration_properties(d1: Duration, d2: Duration) -> bool {
323 let sum = (i128::from(d1.as_nanos()) + i128::from(d2.as_nanos()))
324 .try_into()
325 .map(Duration::from_nanos);
326 let sum_test = if let Ok(sum) = sum {
327 let mut d1p2 = d1;
328 d1p2 += d2;
329 d1 + d2 == sum && d1p2 == d1 + d2
330 } else {
331 true
332 };
333
334 let diff = (i128::from(d1.as_nanos()) - i128::from(d2.as_nanos()))
335 .try_into()
336 .map(Duration::from_nanos);
337 let diff_test = if let Ok(diff) = diff {
338 let mut d1m2 = d1;
339 d1m2 -= d2;
340 d1 - d2 == diff && d1m2 == d1 - d2
341 } else {
342 true
343 };
344
345 sum_test && diff_test
346 }
347
348 #[quickcheck]
349 fn duration_i64_properties(d: Duration, i: i64) -> bool {
351 let mul = (i128::from(d.as_nanos()) * i128::from(i))
352 .try_into()
353 .map(Duration::from_nanos);
354 let mul_test = if let Ok(mul) = mul {
355 let mut dti = d;
356 dti *= i;
357 d * i == mul && i * d == d * i && dti == d * i
358 } else {
359 true
360 };
361
362 if i == 0 {
363 return mul_test;
364 }
365 let div = (i128::from(d.as_nanos()) / i128::from(i))
366 .try_into()
367 .map(Duration::from_nanos);
368 let div_test = if let Ok(div) = div {
369 let mut doi = d;
370 doi /= i;
371 d / i == div && doi == d / i
372 } else {
373 true
374 };
375
376 mul_test && div_test
377 }
378
379 #[quickcheck]
380 fn instant_properties(i: Instant) -> bool {
382 i >= Instant::FOREVER_AGO && i <= Instant::SOMEDAY
383 }
384
385 #[quickcheck]
386 fn instant_duration_properties(i: Instant, d: Duration) -> bool {
388 let sum = (i128::from(i.0) + i128::from(d.as_nanos()))
389 .try_into()
390 .map(Instant);
391 let sum_test = if let Ok(sum) = sum {
392 let mut ipd = i;
393 ipd += d;
394 i + d == sum && ipd == i + d
395 } else {
396 true
397 };
398
399 let diff = (i128::from(i.0) - i128::from(d.as_nanos()))
400 .try_into()
401 .map(Instant);
402 let diff_test = if let Ok(diff) = diff {
403 let mut imd = i;
404 imd -= d;
405 i - d == diff && imd == i - d
406 } else {
407 true
408 };
409
410 sum_test && diff_test
411 }
412
413 #[quickcheck]
414 fn instant_instant_properties(i1: Instant, i2: Instant) -> bool {
416 let diff = (i128::from(i1.0) - i128::from(i2.0))
417 .try_into()
418 .map(Duration::from_nanos);
419 if let Ok(diff) = diff {
420 i1 - i2 == diff
421 } else {
422 true
423 }
424 }
425}