coarsetime/
instant.rs

1#[allow(unused_imports)]
2use std::mem::MaybeUninit;
3use std::ops::*;
4#[allow(unused_imports)]
5use std::ptr::*;
6use std::sync::atomic::{AtomicU64, Ordering};
7
8use super::duration::*;
9#[allow(unused_imports)]
10use super::helpers::*;
11
12/// A measurement of a *monotonically* increasing clock. Opaque and useful only
13/// with `Duration`.
14/// Resulting durations are actual durations; they do not get affected by
15/// clock adjustments, leap seconds, or similar.
16/// In order to get a measurement of the *wall clock*, use `Date` instead.
17#[derive(Copy, Clone, Debug, Hash, Ord, Eq, PartialOrd, PartialEq)]
18pub struct Instant(u64);
19
20static RECENT: AtomicU64 = AtomicU64::new(0);
21
22#[cfg(windows)]
23extern "system" {
24    pub fn GetTickCount64() -> libc::c_ulonglong;
25}
26
27#[cfg(any(target_os = "macos", target_os = "freebsd"))]
28#[allow(non_camel_case_types)]
29type clockid_t = libc::c_int;
30
31#[cfg(target_os = "macos")]
32const CLOCK_MONOTONIC_RAW_APPROX: clockid_t = 5;
33
34#[cfg(target_os = "macos")]
35extern "system" {
36    fn clock_gettime_nsec_np(clk_id: clockid_t) -> u64;
37}
38
39#[cfg(target_os = "freebsd")]
40const CLOCK_MONOTONIC_FAST: clockid_t = 12;
41
42#[cfg(all(
43    any(target_arch = "wasm32", target_arch = "wasm64"),
44    target_os = "unknown"
45))]
46mod js_imports {
47    use wasm_bindgen::prelude::*;
48
49    #[wasm_bindgen]
50    extern "C" {
51        #[allow(non_camel_case_types)]
52        pub type performance;
53
54        #[wasm_bindgen(static_method_of = performance)]
55        pub fn now() -> f64;
56    }
57}
58
59impl Instant {
60    /// Returns an instant corresponding to "now"
61    ///
62    /// This function also updates the stored instant.
63    pub fn now() -> Instant {
64        let now = Self::_now();
65        Self::_update(now);
66        Instant(now)
67    }
68
69    /// Returns an instant corresponding to "now" without updating the cached value.
70    /// After this, `recent()` will still return the old instant.
71    ///
72    /// `now()` is generally preferred over this function.
73    pub fn now_without_cache_update() -> Instant {
74        let now = Self::_now();
75        Instant(now)
76    }
77
78    /// Returns an instant corresponding to the latest update
79    pub fn recent() -> Instant {
80        match Self::_recent() {
81            0 => Instant::now(),
82            recent => Instant(recent),
83        }
84    }
85
86    /// Update the stored instant
87    ///
88    /// This function should be called frequently, for example in an event loop
89    /// or using an `Updater` task.
90    pub fn update() {
91        let now = Self::_now();
92        Self::_update(now);
93    }
94
95    /// Returns the amount of time elapsed from another instant to this one
96    #[inline]
97    pub fn duration_since(&self, earlier: Instant) -> Duration {
98        *self - earlier
99    }
100
101    /// Returns the amount of time elapsed between the this instant was created
102    /// and the latest update
103    #[inline]
104    pub fn elapsed_since_recent(&self) -> Duration {
105        Self::recent() - *self
106    }
107
108    /// Returns the amount of time elapsed since this instant was created
109    ///
110    /// This function also updates the stored instant.
111    #[inline]
112    pub fn elapsed(&self) -> Duration {
113        Self::now() - *self
114    }
115
116    /// Return a representation of this instant as a number of "ticks".
117    ///
118    /// Note that length of a 'tick' is not guaranteed to represent
119    /// the same amount of time across different platforms, or from
120    /// one version of `coarsetime` to another.
121    ///
122    /// Note also that the instant represented by "0" ticks is
123    /// unspecified.  It is not guaranteed to be the same time across
124    /// different platforms, or from one version of `coarsetime` to
125    /// another.
126    ///
127    /// This API is mainly intended for applications that need to
128    /// store the value of an `Instant` in an
129    /// [`AtomicU64`](std::sync::atomic::AtomicU64).
130    #[inline]
131    pub fn as_ticks(&self) -> u64 {
132        self.as_u64()
133    }
134
135    #[doc(hidden)]
136    #[inline]
137    pub fn as_u64(&self) -> u64 {
138        self.0
139    }
140
141    #[cfg(any(target_os = "linux", target_os = "android"))]
142    fn _now() -> u64 {
143        let mut tp = MaybeUninit::<libc::timespec>::uninit();
144        let tp = unsafe {
145            libc::clock_gettime(libc::CLOCK_MONOTONIC_COARSE, tp.as_mut_ptr());
146            tp.assume_init()
147        };
148        _timespec_to_u64(tp.tv_sec as u64, tp.tv_nsec as u32)
149    }
150
151    #[cfg(target_os = "macos")]
152    fn _now() -> u64 {
153        let nsec = unsafe { clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW_APPROX) };
154        _nsecs_to_u64(nsec)
155    }
156
157    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
158    fn _now() -> u64 {
159        let mut tp = MaybeUninit::<libc::timespec>::uninit();
160        let tp = unsafe {
161            libc::clock_gettime(libc::CLOCK_MONOTONIC_FAST, tp.as_mut_ptr());
162            tp.assume_init()
163        };
164        _timespec_to_u64(tp.tv_sec as u64, tp.tv_nsec as u32)
165    }
166
167    #[cfg(all(
168        unix,
169        not(any(
170            target_os = "macos",
171            target_os = "linux",
172            target_os = "android",
173            target_os = "freebsd",
174            target_os = "dragonfly"
175        ))
176    ))]
177    fn _now() -> u64 {
178        let mut tv = MaybeUninit::<libc::timeval>::uninit();
179        let tv = unsafe {
180            libc::gettimeofday(tv.as_mut_ptr(), null_mut());
181            tv.assume_init()
182        };
183        _timeval_to_u64(tv.tv_sec as u64, tv.tv_usec as u32)
184    }
185
186    #[cfg(windows)]
187    fn _now() -> u64 {
188        let tc = unsafe { GetTickCount64() } as u64;
189        _millis_to_u64(tc)
190    }
191
192    #[cfg(any(
193        target_os = "wasix",
194        all(target_os = "wasi", not(feature = "wasi-abi2"))
195    ))]
196    fn _now() -> u64 {
197        use wasix::{clock_time_get, CLOCKID_MONOTONIC, CLOCKID_REALTIME};
198        let nsec = unsafe { clock_time_get(CLOCKID_MONOTONIC, 1_000_000) }
199            .or_else(|_| unsafe { clock_time_get(CLOCKID_REALTIME, 1_000_000) })
200            .expect("Clock not available");
201        _nsecs_to_u64(nsec)
202    }
203
204    #[cfg(all(target_os = "wasi", feature = "wasi-abi2"))]
205    fn _now() -> u64 {
206        let nsec = wasi_abi2::clocks::monotonic_clock::now();
207        _nsecs_to_u64(nsec)
208    }
209
210    #[cfg(all(
211        any(target_arch = "wasm32", target_arch = "wasm64"),
212        target_os = "unknown"
213    ))]
214    fn _now() -> u64 {
215        _millis_to_u64(js_imports::performance::now() as u64)
216    }
217
218    #[cfg(all(target_arch = "x86_64", target_env = "sgx", target_vendor = "fortanix"))]
219    fn _now() -> u64 {
220        let timestamp = std::time::SystemTime::now()
221            .duration_since(std::time::UNIX_EPOCH)
222            .unwrap();
223        timestamp.as_secs() * 1_000_000_000 + (timestamp.subsec_nanos() as u64)
224    }
225
226    #[inline]
227    fn _update(now: u64) {
228        RECENT.store(now, Ordering::Relaxed)
229    }
230
231    #[inline]
232    fn _recent() -> u64 {
233        let recent = RECENT.load(Ordering::Relaxed);
234        if recent != 0 {
235            recent
236        } else {
237            let now = Self::_now();
238            Self::_update(now);
239            Self::_recent()
240        }
241    }
242}
243
244impl Default for Instant {
245    fn default() -> Instant {
246        Self::now()
247    }
248}
249
250impl Sub<Instant> for Instant {
251    type Output = Duration;
252
253    #[inline]
254    fn sub(self, other: Instant) -> Duration {
255        Duration::from_u64(self.0.saturating_sub(other.0))
256    }
257}
258
259impl Sub<Duration> for Instant {
260    type Output = Instant;
261
262    #[inline]
263    fn sub(self, rhs: Duration) -> Instant {
264        Instant(self.0 - rhs.as_u64())
265    }
266}
267
268impl SubAssign<Duration> for Instant {
269    #[inline]
270    fn sub_assign(&mut self, rhs: Duration) {
271        *self = *self - rhs;
272    }
273}
274
275impl Add<Duration> for Instant {
276    type Output = Instant;
277
278    #[inline]
279    fn add(self, rhs: Duration) -> Instant {
280        Instant(self.0 + rhs.as_u64())
281    }
282}
283
284impl AddAssign<Duration> for Instant {
285    #[inline]
286    fn add_assign(&mut self, rhs: Duration) {
287        *self = *self + rhs;
288    }
289}