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#[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 pub fn now() -> Instant {
65 let now = Self::_now();
66 Self::_update(now);
67 Instant(now)
68 }
69
70 pub fn now_without_cache_update() -> Instant {
75 let now = Self::_now();
76 Instant(now)
77 }
78
79 pub fn recent() -> Instant {
81 match Self::_recent() {
82 0 => Instant::now(),
83 recent => Instant(recent),
84 }
85 }
86
87 pub fn update() {
92 let now = Self::_now();
93 Self::_update(now);
94 }
95
96 #[inline]
98 pub fn duration_since(&self, earlier: Instant) -> Duration {
99 *self - earlier
100 }
101
102 #[inline]
105 pub fn elapsed_since_recent(&self) -> Duration {
106 Self::recent() - *self
107 }
108
109 #[inline]
113 pub fn elapsed(&self) -> Duration {
114 Self::now() - *self
115 }
116
117 #[inline]
132 pub const fn as_ticks(&self) -> u64 {
133 self.as_u64()
134 }
135
136 #[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 #[inline]
165 pub const fn saturating_add(self, rhs: Duration) -> Instant {
166 Instant(self.0.saturating_add(rhs.as_u64()))
167 }
168
169 #[inline]
171 pub fn checked_add(self, rhs: Duration) -> Option<Instant> {
172 self.0.checked_add(rhs.as_u64()).map(Instant)
173 }
174
175 #[inline]
177 pub const fn saturating_sub(self, rhs: Duration) -> Instant {
178 Instant(self.0.saturating_sub(rhs.as_u64()))
179 }
180
181 #[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}