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)]
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 pub fn now() -> Instant {
64 let now = Self::_now();
65 Self::_update(now);
66 Instant(now)
67 }
68
69 pub fn now_without_cache_update() -> Instant {
74 let now = Self::_now();
75 Instant(now)
76 }
77
78 pub fn recent() -> Instant {
80 match Self::_recent() {
81 0 => Instant::now(),
82 recent => Instant(recent),
83 }
84 }
85
86 pub fn update() {
91 let now = Self::_now();
92 Self::_update(now);
93 }
94
95 #[inline]
97 pub fn duration_since(&self, earlier: Instant) -> Duration {
98 *self - earlier
99 }
100
101 #[inline]
104 pub fn elapsed_since_recent(&self) -> Duration {
105 Self::recent() - *self
106 }
107
108 #[inline]
112 pub fn elapsed(&self) -> Duration {
113 Self::now() - *self
114 }
115
116 #[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}