libtw2_net/
time.rs

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        // Make the `None` value higher than any other.
73        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}