Skip to main content

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