Drop now-unused methods on `Time`
[rust-lightning] / lightning / src / util / time.rs
1 // This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
2 // or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
4 // You may not use this file except in accordance with one or both of these
5 // licenses.
6
7 //! [`Time`] trait and different implementations. Currently, it's mainly used in tests so we can
8 //! manually advance time.
9 //! Other crates may symlink this file to use it while [`Time`] trait is sealed here.
10
11 use core::ops::Sub;
12 use core::time::Duration;
13
14 /// A measurement of time.
15 pub trait Time: Copy + Sub<Duration, Output = Self> where Self: Sized {
16         /// Returns an instance corresponding to the current moment.
17         fn now() -> Self;
18
19         /// Returns the amount of time passed between `earlier` and `self`.
20         fn duration_since(&self, earlier: Self) -> Duration;
21 }
22
23 /// A state in which time has no meaning.
24 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
25 pub struct Eternity;
26
27 impl Time for Eternity {
28         fn now() -> Self {
29                 Self
30         }
31
32         fn duration_since(&self, _earlier: Self) -> Duration {
33                 Duration::from_secs(0)
34         }
35 }
36
37 impl Sub<Duration> for Eternity {
38         type Output = Self;
39
40         fn sub(self, _other: Duration) -> Self {
41                 self
42         }
43 }
44
45 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
46 #[cfg(feature = "std")]
47 pub struct MonotonicTime(std::time::Instant);
48
49 /// The amount of time to shift `Instant` forward to prevent overflow when subtracting a `Duration`
50 /// from `Instant::now` on some operating systems (e.g., iOS representing `Instance` as `u64`).
51 #[cfg(feature = "std")]
52 const SHIFT: Duration = Duration::from_secs(10 * 365 * 24 * 60 * 60); // 10 years.
53
54 #[cfg(feature = "std")]
55 impl Time for MonotonicTime {
56         fn now() -> Self {
57                 let instant = std::time::Instant::now().checked_add(SHIFT).expect("Overflow on MonotonicTime instantiation");
58                 Self(instant)
59         }
60
61         fn duration_since(&self, earlier: Self) -> Duration {
62                 // On rust prior to 1.60 `Instant::duration_since` will panic if time goes backwards.
63                 // However, we support rust versions prior to 1.60 and some users appear to have "monotonic
64                 // clocks" that go backwards in practice (likely relatively ancient kernels/etc). Thus, we
65                 // manually check for time going backwards here and return a duration of zero in that case.
66                 let now = Self::now();
67                 if now.0 > earlier.0 { now.0 - earlier.0 } else { Duration::from_secs(0) }
68         }
69 }
70
71 #[cfg(feature = "std")]
72 impl Sub<Duration> for MonotonicTime {
73         type Output = Self;
74
75         fn sub(self, other: Duration) -> Self {
76                 let instant = self.0.checked_sub(other).expect("MonotonicTime is not supposed to go backward futher than 10 years");
77                 Self(instant)
78         }
79 }
80
81 #[cfg(test)]
82 pub mod tests {
83         use super::{Time, Eternity};
84
85         use core::time::Duration;
86         use core::ops::Sub;
87         use core::cell::Cell;
88
89         /// Time that can be advanced manually in tests.
90         #[derive(Clone, Copy, Debug, PartialEq, Eq)]
91         pub struct SinceEpoch(Duration);
92
93         impl SinceEpoch {
94                 thread_local! {
95                         static ELAPSED: Cell<Duration> = core::cell::Cell::new(Duration::from_secs(0));
96                 }
97
98                 pub fn advance(duration: Duration) {
99                         Self::ELAPSED.with(|elapsed| elapsed.set(elapsed.get() + duration))
100                 }
101         }
102
103         impl Time for SinceEpoch {
104                 fn now() -> Self {
105                         Self(Self::ELAPSED.with(|elapsed| elapsed.get()))
106                 }
107
108                 fn duration_since(&self, earlier: Self) -> Duration {
109                         self.0 - earlier.0
110                 }
111         }
112
113         impl Sub<Duration> for SinceEpoch {
114                 type Output = Self;
115
116                 fn sub(self, other: Duration) -> Self {
117                         Self(self.0 - other)
118                 }
119         }
120
121         #[test]
122         fn time_passes_when_advanced() {
123                 let now = SinceEpoch::now();
124
125                 SinceEpoch::advance(Duration::from_secs(1));
126                 SinceEpoch::advance(Duration::from_secs(1));
127
128                 let later = SinceEpoch::now();
129
130                 assert_eq!(now.0 + Duration::from_secs(2), later.0);
131         }
132
133         #[test]
134         fn time_never_passes_in_an_eternity() {
135                 let now = Eternity::now();
136                 let later = Eternity::now();
137
138                 assert_eq!(later, now);
139         }
140 }