1 use std::cmp::Ordering;
2 use std::ops::{Add, AddAssign, Sub, SubAssign};
3 use std::time::Duration;
4
5 #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Hash)]
6 pub struct Instant(Duration);
7
8 impl Ord for Instant {
cmp(&self, other: &Self) -> std::cmp::Ordering9 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
10 self.partial_cmp(other)
11 .expect("an instant should never be NaN or Inf.")
12 }
13 }
14 impl Eq for Instant {}
15
16 impl Instant {
17 #[inline]
now() -> Self18 pub fn now() -> Self {
19 Instant(duration_from_f64(now()))
20 }
21
22 #[inline]
duration_since(&self, earlier: Instant) -> Duration23 pub fn duration_since(&self, earlier: Instant) -> Duration {
24 assert!(
25 earlier.0 <= self.0,
26 "`earlier` cannot be later than `self`."
27 );
28 self.0 - earlier.0
29 }
30
31 #[inline]
elapsed(&self) -> Duration32 pub fn elapsed(&self) -> Duration {
33 Self::now().duration_since(*self)
34 }
35
36 /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as
37 /// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
38 /// otherwise.
39 #[inline]
checked_add(&self, duration: Duration) -> Option<Instant>40 pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
41 self.0.checked_add(duration).map(Instant)
42 }
43
44 /// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as
45 /// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
46 /// otherwise.
47 #[inline]
checked_sub(&self, duration: Duration) -> Option<Instant>48 pub fn checked_sub(&self, duration: Duration) -> Option<Instant> {
49 self.0.checked_sub(duration).map(Instant)
50 }
51
52 /// Returns the amount of time elapsed from another instant to this one, or None if that
53 /// instant is later than this one.
54 #[inline]
checked_duration_since(&self, earlier: Instant) -> Option<Duration>55 pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
56 if earlier.0 > self.0 {
57 None
58 } else {
59 Some(self.0 - earlier.0)
60 }
61 }
62
63 /// Returns the amount of time elapsed from another instant to this one, or zero duration if
64 /// that instant is later than this one.
65 #[inline]
saturating_duration_since(&self, earlier: Instant) -> Duration66 pub fn saturating_duration_since(&self, earlier: Instant) -> Duration {
67 self.checked_duration_since(earlier).unwrap_or_default()
68 }
69 }
70
71 impl Add<Duration> for Instant {
72 type Output = Self;
73
74 #[inline]
add(self, rhs: Duration) -> Self75 fn add(self, rhs: Duration) -> Self {
76 Instant(self.0 + rhs)
77 }
78 }
79
80 impl AddAssign<Duration> for Instant {
81 #[inline]
add_assign(&mut self, rhs: Duration)82 fn add_assign(&mut self, rhs: Duration) {
83 self.0 += rhs
84 }
85 }
86
87 impl Sub<Duration> for Instant {
88 type Output = Self;
89
90 #[inline]
sub(self, rhs: Duration) -> Self91 fn sub(self, rhs: Duration) -> Self {
92 Instant(self.0 - rhs)
93 }
94 }
95
96 impl Sub<Instant> for Instant {
97 type Output = Duration;
98
99 #[inline]
sub(self, rhs: Instant) -> Duration100 fn sub(self, rhs: Instant) -> Duration {
101 self.duration_since(rhs)
102 }
103 }
104
105 impl SubAssign<Duration> for Instant {
106 #[inline]
sub_assign(&mut self, rhs: Duration)107 fn sub_assign(&mut self, rhs: Duration) {
108 self.0 -= rhs
109 }
110 }
111
duration_from_f64(millis: f64) -> Duration112 fn duration_from_f64(millis: f64) -> Duration {
113 Duration::from_millis(millis.trunc() as u64)
114 + Duration::from_nanos((millis.fract() * 1.0e6) as u64)
115 }
116
117 #[cfg(all(feature = "stdweb", not(feature = "wasm-bindgen")))]
118 #[allow(unused_results)] // Needed because the js macro triggers it.
now() -> f64119 pub fn now() -> f64 {
120 use stdweb::unstable::TryInto;
121
122 // https://developer.mozilla.org/en-US/docs/Web/API/Performance/now
123 #[cfg(not(feature = "inaccurate"))]
124 let v = js! { return performance.now(); };
125 #[cfg(feature = "inaccurate")]
126 let v = js! { return Date.now(); };
127 v.try_into().unwrap()
128 }
129
130 #[cfg(feature = "wasm-bindgen")]
now() -> f64131 pub fn now() -> f64 {
132 #[cfg(not(feature = "inaccurate"))]
133 let now = {
134 use wasm_bindgen_rs::prelude::*;
135 use wasm_bindgen_rs::JsCast;
136 js_sys::Reflect::get(&js_sys::global(), &JsValue::from_str("performance"))
137 .expect("failed to get performance from global object")
138 .unchecked_into::<web_sys::Performance>()
139 .now()
140 };
141 #[cfg(feature = "inaccurate")]
142 let now = js_sys::Date::now();
143 now
144 }
145
146 // The JS now function is in a module so it won't have to be renamed
147 #[cfg(not(any(feature = "wasm-bindgen", feature = "stdweb")))]
148 mod js {
149 extern "C" {
150 #[cfg(not(target_os = "emscripten"))]
now() -> f64151 pub fn now() -> f64;
152 #[cfg(target_os = "emscripten")]
_emscripten_get_now() -> f64153 pub fn _emscripten_get_now() -> f64;
154 }
155 }
156 // Make the unsafe extern function "safe" so it can be called like the other 'now' functions
157 #[cfg(not(any(feature = "wasm-bindgen", feature = "stdweb")))]
now() -> f64158 pub fn now() -> f64 {
159 #[cfg(not(target_os = "emscripten"))]
160 return unsafe { js::now() };
161 #[cfg(target_os = "emscripten")]
162 return unsafe { js::_emscripten_get_now() };
163 }
164
165 /// Returns the number of millisecods elapsed since January 1, 1970 00:00:00 UTC.
166 #[cfg(any(feature = "wasm-bindgen", feature = "stdweb"))]
get_time() -> f64167 fn get_time() -> f64 {
168 #[cfg(feature = "wasm-bindgen")]
169 return js_sys::Date::now();
170 #[cfg(all(feature = "stdweb", not(feature = "wasm-bindgen")))]
171 {
172 let v = js! { return Date.now(); };
173 return v.try_into().unwrap();
174 }
175 }
176
177 #[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
178 pub struct SystemTime(f64);
179
180 impl SystemTime {
181 pub const UNIX_EPOCH: SystemTime = SystemTime(0.0);
182
now() -> SystemTime183 pub fn now() -> SystemTime {
184 cfg_if::cfg_if! {
185 if #[cfg(any(feature = "wasm-bindgen", feature = "stdweb"))] {
186 SystemTime(get_time())
187 } else {
188 SystemTime(now())
189 }
190 }
191 }
192
duration_since(&self, earlier: SystemTime) -> Result<Duration, ()>193 pub fn duration_since(&self, earlier: SystemTime) -> Result<Duration, ()> {
194 let dur_ms = self.0 - earlier.0;
195 if dur_ms < 0.0 {
196 return Err(());
197 }
198 Ok(Duration::from_millis(dur_ms as u64))
199 }
200
elapsed(&self) -> Result<Duration, ()>201 pub fn elapsed(&self) -> Result<Duration, ()> {
202 self.duration_since(SystemTime::now())
203 }
204
checked_add(&self, duration: Duration) -> Option<SystemTime>205 pub fn checked_add(&self, duration: Duration) -> Option<SystemTime> {
206 Some(*self + duration)
207 }
208
checked_sub(&self, duration: Duration) -> Option<SystemTime>209 pub fn checked_sub(&self, duration: Duration) -> Option<SystemTime> {
210 Some(*self - duration)
211 }
212 }
213
214 impl Add<Duration> for SystemTime {
215 type Output = SystemTime;
216
add(self, other: Duration) -> SystemTime217 fn add(self, other: Duration) -> SystemTime {
218 SystemTime(self.0 + other.as_millis() as f64)
219 }
220 }
221
222 impl Sub<Duration> for SystemTime {
223 type Output = SystemTime;
224
sub(self, other: Duration) -> SystemTime225 fn sub(self, other: Duration) -> SystemTime {
226 SystemTime(self.0 - other.as_millis() as f64)
227 }
228 }
229
230 impl AddAssign<Duration> for SystemTime {
add_assign(&mut self, rhs: Duration)231 fn add_assign(&mut self, rhs: Duration) {
232 *self = *self + rhs;
233 }
234 }
235
236 impl SubAssign<Duration> for SystemTime {
sub_assign(&mut self, rhs: Duration)237 fn sub_assign(&mut self, rhs: Duration) {
238 *self = *self - rhs;
239 }
240 }
241