summaryrefslogtreecommitdiffhomepage
path: root/talpid-time/src/unix.rs
blob: 643a7049aa43f53670e4a1b95ff4e830e72dffdb (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
use libc::{c_long, clock_gettime, clockid_t, timespec};
use std::{mem::MaybeUninit, time::Duration};

const NSEC_PER_SEC: c_long = 1_000_000_000;

#[cfg(target_os = "macos")]
const CLOCK_ID: clockid_t = libc::CLOCK_MONOTONIC;

#[cfg(any(target_os = "linux", target_os = "android"))]
const CLOCK_ID: clockid_t = libc::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 {
    let mut t = MaybeUninit::zeroed();
    unsafe {
        clock_gettime(CLOCK_ID, t.as_mut_ptr());
        t.assume_init()
    }
}