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 fn as_ticks(&self) -> u64 {
133        self.as_u64()
134    }
135
136    #[doc(hidden)]
137    #[inline]
138    pub fn as_u64(&self) -> u64 {
139        self.0
140    }
141
142    /// Calculate an `Instant` that is a `Duration` later, saturating on overflow
143    #[inline]
144    pub fn saturating_add(self, rhs: Duration) -> Instant {
145        Instant(self.0.saturating_add(rhs.as_u64()))
146    }
147
148    /// Calculate an `Instant` that is a `Duration` later, returning `None` on overflow
149    #[inline]
150    pub fn checked_add(self, rhs: Duration) -> Option<Instant> {
151        self.0.checked_add(rhs.as_u64()).map(Instant)
152    }
153
154    /// Calculate an `Instant` that is a `Duration` earlier, saturating on underflow
155    #[inline]
156    pub fn saturating_sub(self, rhs: Duration) -> Instant {
157        Instant(self.0.saturating_sub(rhs.as_u64()))
158    }
159
160    /// Calculate an `Instant` that is a `Duration` earlier, returning `None` on underflow
161    #[inline]
162    pub fn checked_sub(self, rhs: Duration) -> Option<Instant> {
163        self.0.checked_sub(rhs.as_u64()).map(Instant)
164    }
165
166    #[cfg(any(target_os = "linux", target_os = "android"))]
167    fn _now() -> u64 {
168        let mut tp = MaybeUninit::<libc::timespec>::uninit();
169        let tp = unsafe {
170            libc::clock_gettime(libc::CLOCK_MONOTONIC_COARSE, tp.as_mut_ptr());
171            tp.assume_init()
172        };
173        _timespec_to_u64(tp.tv_sec as u64, tp.tv_nsec as u32)
174    }
175
176    #[cfg(target_os = "macos")]
177    fn _now() -> u64 {
178        let nsec = unsafe { clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW_APPROX) };
179        _nsecs_to_u64(nsec)
180    }
181
182    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
183    fn _now() -> u64 {
184        let mut tp = MaybeUninit::<libc::timespec>::uninit();
185        let tp = unsafe {
186            libc::clock_gettime(libc::CLOCK_MONOTONIC_FAST, tp.as_mut_ptr());
187            tp.assume_init()
188        };
189        _timespec_to_u64(tp.tv_sec as u64, tp.tv_nsec as u32)
190    }
191
192    #[cfg(all(
193        unix,
194        not(any(
195            target_os = "macos",
196            target_os = "linux",
197            target_os = "android",
198            target_os = "freebsd",
199            target_os = "dragonfly"
200        ))
201    ))]
202    fn _now() -> u64 {
203        let mut tv = MaybeUninit::<libc::timeval>::uninit();
204        let tv = unsafe {
205            libc::gettimeofday(tv.as_mut_ptr(), null_mut());
206            tv.assume_init()
207        };
208        _timeval_to_u64(tv.tv_sec as u64, tv.tv_usec as u32)
209    }
210
211    #[cfg(windows)]
212    fn _now() -> u64 {
213        let tc = unsafe { GetTickCount64() } as u64;
214        _millis_to_u64(tc)
215    }
216
217    #[cfg(all(target_os = "wasi", not(feature = "wasi-abi2")))]
218    fn _now() -> u64 {
219        use wasix::{clock_time_get, CLOCKID_MONOTONIC, CLOCKID_REALTIME};
220        let nsec = unsafe { clock_time_get(CLOCKID_MONOTONIC, 1_000_000) }
221            .or_else(|_| unsafe { clock_time_get(CLOCKID_REALTIME, 1_000_000) })
222            .expect("Clock not available");
223        _nsecs_to_u64(nsec)
224    }
225
226    #[cfg(all(target_os = "wasi", feature = "wasi-abi2"))]
227    fn _now() -> u64 {
228        let nsec = wasi_abi2::clocks::monotonic_clock::now();
229        _nsecs_to_u64(nsec)
230    }
231
232    #[cfg(all(
233        any(target_arch = "wasm32", target_arch = "wasm64"),
234        target_os = "unknown"
235    ))]
236    fn _now() -> u64 {
237        _millis_to_u64(js_imports::performance::now() as u64)
238    }
239
240    #[cfg(all(target_arch = "x86_64", target_env = "sgx", target_vendor = "fortanix"))]
241    fn _now() -> u64 {
242        let timestamp = std::time::SystemTime::now()
243            .duration_since(std::time::UNIX_EPOCH)
244            .unwrap();
245        timestamp.as_secs() * 1_000_000_000 + (timestamp.subsec_nanos() as u64)
246    }
247
248    #[inline]
249    fn _update(now: u64) {
250        RECENT.store(now, Ordering::Relaxed)
251    }
252
253    #[inline]
254    fn _recent() -> u64 {
255        let recent = RECENT.load(Ordering::Relaxed);
256        if recent != 0 {
257            recent
258        } else {
259            let now = Self::_now();
260            Self::_update(now);
261            Self::_recent()
262        }
263    }
264}
265
266impl Default for Instant {
267    fn default() -> Instant {
268        Self::now()
269    }
270}
271
272impl Sub<Instant> for Instant {
273    type Output = Duration;
274
275    #[inline]
276    fn sub(self, other: Instant) -> Duration {
277        Duration::from_u64(self.0.saturating_sub(other.0))
278    }
279}
280
281impl Sub<Duration> for Instant {
282    type Output = Instant;
283
284    #[inline]
285    fn sub(self, rhs: Duration) -> Instant {
286        Instant(self.0 - rhs.as_u64())
287    }
288}
289
290impl SubAssign<Duration> for Instant {
291    #[inline]
292    fn sub_assign(&mut self, rhs: Duration) {
293        *self = *self - rhs;
294    }
295}
296
297impl Add<Duration> for Instant {
298    type Output = Instant;
299
300    #[inline]
301    fn add(self, rhs: Duration) -> Instant {
302        Instant(self.0 + rhs.as_u64())
303    }
304}
305
306impl AddAssign<Duration> for Instant {
307    #[inline]
308    fn add_assign(&mut self, rhs: Duration) {
309        *self = *self + rhs;
310    }
311}