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
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.
12 use core::time::Duration;
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.
19 /// Returns the amount of time elapsed since `self` was created.
20 fn elapsed(&self) -> Duration;
22 /// Returns the amount of time passed between `earlier` and `self`.
23 fn duration_since(&self, earlier: Self) -> Duration;
25 /// Returns the amount of time passed since the beginning of [`Time`].
27 /// Used during (de-)serialization.
28 fn duration_since_epoch() -> Duration;
31 /// A state in which time has no meaning.
32 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
35 impl Time for Eternity {
40 fn duration_since(&self, _earlier: Self) -> Duration {
41 Duration::from_secs(0)
44 fn duration_since_epoch() -> Duration {
45 Duration::from_secs(0)
48 fn elapsed(&self) -> Duration {
49 Duration::from_secs(0)
53 impl Sub<Duration> for Eternity {
56 fn sub(self, _other: Duration) -> Self {
61 #[cfg(not(feature = "no-std"))]
62 impl Time for std::time::Instant {
64 std::time::Instant::now()
67 fn duration_since(&self, earlier: Self) -> Duration {
68 // On rust prior to 1.60 `Instant::duration_since` will panic if time goes backwards.
69 // However, we support rust versions prior to 1.60 and some users appear to have "monotonic
70 // clocks" that go backwards in practice (likely relatively ancient kernels/etc). Thus, we
71 // manually check for time going backwards here and return a duration of zero in that case.
72 let now = Self::now();
73 if now > earlier { now - earlier } else { Duration::from_secs(0) }
76 fn duration_since_epoch() -> Duration {
77 use std::time::SystemTime;
78 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap()
80 fn elapsed(&self) -> Duration {
81 std::time::Instant::elapsed(self)
87 use super::{Time, Eternity};
89 use core::time::Duration;
93 /// Time that can be advanced manually in tests.
94 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
95 pub struct SinceEpoch(Duration);
99 static ELAPSED: Cell<Duration> = core::cell::Cell::new(Duration::from_secs(0));
102 pub fn advance(duration: Duration) {
103 Self::ELAPSED.with(|elapsed| elapsed.set(elapsed.get() + duration))
107 impl Time for SinceEpoch {
109 Self(Self::duration_since_epoch())
112 fn duration_since(&self, earlier: Self) -> Duration {
116 fn duration_since_epoch() -> Duration {
117 Self::ELAPSED.with(|elapsed| elapsed.get())
120 fn elapsed(&self) -> Duration {
121 Self::duration_since_epoch() - self.0
125 impl Sub<Duration> for SinceEpoch {
128 fn sub(self, other: Duration) -> Self {
134 fn time_passes_when_advanced() {
135 let now = SinceEpoch::now();
136 assert_eq!(now.elapsed(), Duration::from_secs(0));
138 SinceEpoch::advance(Duration::from_secs(1));
139 SinceEpoch::advance(Duration::from_secs(1));
141 let elapsed = now.elapsed();
142 let later = SinceEpoch::now();
144 assert_eq!(elapsed, Duration::from_secs(2));
145 assert_eq!(later - elapsed, now);
149 fn time_never_passes_in_an_eternity() {
150 let now = Eternity::now();
151 let elapsed = now.elapsed();
152 let later = Eternity::now();
154 assert_eq!(now.elapsed(), Duration::from_secs(0));
155 assert_eq!(later - elapsed, now);