summaryrefslogtreecommitdiffhomepage
path: root/talpid-time/src/unix.rs
blob: 02b51b06fade63938eaa40b6f6c1d0c621aa01f2 (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
use nix::{
    sys::time::TimeSpec,
    time::{ClockId, clock_gettime},
};
use std::{ffi::c_long, time::Duration};

const NSEC_PER_SEC: c_long = 1_000_000_000;

#[cfg(any(target_os = "macos", target_os = "ios"))]
const CLOCK_ID: ClockId = ClockId::CLOCK_MONOTONIC;

#[cfg(any(target_os = "linux", target_os = "android"))]
const CLOCK_ID: ClockId = ClockId::CLOCK_BOOTTIME;

#[derive(Clone, Copy)]
pub struct Instant {
    t: TimeSpec,
}

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

    fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
        // Assumptions:
        // * `tv_sec >= 0`
        // * `tv_nsec < NSEC_PER_SEC`

        let (tv_sec, tv_nsec) = if self.t.tv_nsec() < earlier.t.tv_nsec() {
            (
                self.t.tv_sec() - earlier.t.tv_sec() - 1,
                NSEC_PER_SEC - earlier.t.tv_nsec() + self.t.tv_nsec(),
            )
        } else {
            (
                self.t.tv_sec() - earlier.t.tv_sec(),
                self.t.tv_nsec() - earlier.t.tv_nsec(),
            )
        };

        if tv_sec < 0 {
            return None;
        }

        Some(Duration::new(tv_sec as _, tv_nsec as _))
    }

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

fn now() -> TimeSpec {
    clock_gettime(CLOCK_ID).expect("Clock ID is valid")
}