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