1use libtw2_common::num::Cast;
2use optional::Optioned;
3use std::cmp;
4use std::ops;
5use std::time::Duration;
6
7#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
8pub struct Timestamp {
9 usec: u64,
10}
11
12impl Default for Timestamp {
13 fn default() -> Timestamp {
14 Timestamp::sentinel()
15 }
16}
17
18impl Timestamp {
19 pub fn sentinel() -> Timestamp {
20 optional::Noned::get_none()
21 }
22 pub fn from_secs_since_epoch(secs: u64) -> Timestamp {
23 Timestamp {
24 usec: secs.checked_mul(1_000_000_000).unwrap(),
25 }
26 }
27 pub fn from_usecs_since_epoch(usecs: u64) -> Timestamp {
28 Timestamp { usec: usecs }
29 }
30 pub fn as_usecs_since_epoch(&self) -> u64 {
31 self.usec
32 }
33}
34
35impl ops::Add<Duration> for Timestamp {
36 type Output = Timestamp;
37 fn add(self, duration: Duration) -> Timestamp {
38 Timestamp::from_usecs_since_epoch(
39 self.usec
40 .checked_add(
41 duration
42 .as_secs()
43 .checked_mul(1_000_000_000)
44 .unwrap()
45 .checked_add(duration.subsec_nanos().u64())
46 .unwrap(),
47 )
48 .unwrap(),
49 )
50 }
51}
52
53impl optional::Noned for Timestamp {
54 fn is_none(&self) -> bool {
55 optional::Noned::is_none(&self.usec)
56 }
57 fn get_none() -> Timestamp {
58 Timestamp {
59 usec: optional::Noned::get_none(),
60 }
61 }
62}
63
64impl optional::OptEq for Timestamp {
65 fn opt_eq(&self, other: &Timestamp) -> bool {
66 *self == *other
67 }
68}
69
70impl optional::OptOrd for Timestamp {
71 fn opt_cmp(&self, other: &Timestamp) -> cmp::Ordering {
72 self.cmp(other)
74 }
75}
76
77#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
78pub struct Timeout {
79 timeout: Optioned<Timestamp>,
80}
81
82impl Timeout {
83 pub fn active(timestamp: Timestamp) -> Timeout {
84 Timeout {
85 timeout: Optioned::some(timestamp),
86 }
87 }
88 pub fn inactive() -> Timeout {
89 Timeout {
90 timeout: Optioned::none(),
91 }
92 }
93 pub fn is_active(&self) -> bool {
94 self.timeout.is_some()
95 }
96 pub fn to_opt(self) -> Option<Timestamp> {
97 self.timeout.into()
98 }
99 pub fn time_from(self, time: Timestamp) -> Option<Duration> {
100 self.to_opt().map(|t| {
101 if t > time {
102 let us = t.as_usecs_since_epoch() - time.as_usecs_since_epoch();
103 Duration::new(us / 1_000_000_000, (us % 1_000_000_000).assert_u32())
104 } else {
105 Duration::from_millis(0)
106 }
107 })
108 }
109}
110
111#[cfg(test)]
112mod test {
113 use super::Timeout;
114 use super::Timestamp;
115
116 #[test]
117 fn ord() {
118 let t = Timeout::inactive();
119 let t0 = Timeout::active(Timestamp::from_secs_since_epoch(0));
120 let t1 = Timeout::active(Timestamp::from_secs_since_epoch(1));
121 let t2 = Timeout::active(Timestamp::from_secs_since_epoch(2));
122 assert!(t0 < t);
123 assert!(t0 < t1);
124 assert!(t1 < t2);
125 assert!(t2 < t);
126 }
127}