summaryrefslogtreecommitdiffhomepage
path: root/talpid-time/src/lib.rs
blob: 4ca9c8bf5d8ba9636596cd661bda82d37ea1153a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
use std::time::Duration;

#[cfg(all(not(feature = "test"), target_os = "windows"))]
mod inner {
    pub use std::time::Instant;
}

#[cfg(all(not(feature = "test"), unix))]
#[path = "unix.rs"]
mod inner;

#[cfg(feature = "test")]
mod inner {
    /// Use mockable time for tests
    pub use tokio::time::Instant;
}

const MAX_SLEEP_INTERVAL: Duration = Duration::from_secs(60);

/// Represents a measurement of a monotonic clock.
/// Unlike [std::time::Instant], the difference between two
/// instances is guaranteed to include time spent in system
/// sleep.
#[derive(Clone, Copy)]
pub struct Instant {
    t: inner::Instant,
}

impl Instant {
    pub fn now() -> Self {
        Self {
            t: inner::Instant::now(),
        }
    }

    pub fn duration_since(&self, earlier: Instant) -> Duration {
        self.t.duration_since(earlier.t)
    }
}

/// Waits for the specified interval while taking into account system sleep or suspension.
/// The accuracy is to within about one minute.
pub async fn sleep(duration: Duration) {
    let started = Instant::now();

    loop {
        let elapsed = Instant::now().duration_since(started);

        if elapsed >= duration {
            return;
        }

        tokio::time::sleep(std::cmp::min(
            MAX_SLEEP_INTERVAL,
            duration.saturating_sub(elapsed),
        ))
        .await;
    }
}