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 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 #[inline]
144 pub fn saturating_add(self, rhs: Duration) -> Instant {
145 Instant(self.0.saturating_add(rhs.as_u64()))
146 }
147
148 #[inline]
150 pub fn checked_add(self, rhs: Duration) -> Option<Instant> {
151 self.0.checked_add(rhs.as_u64()).map(Instant)
152 }
153
154 #[inline]
156 pub fn saturating_sub(self, rhs: Duration) -> Instant {
157 Instant(self.0.saturating_sub(rhs.as_u64()))
158 }
159
160 #[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}