1#![warn(missing_docs)]
5
6#[derive(Copy, Clone)]
10pub struct Instant {
11 #[cfg(target_arch = "wasm32")]
12 value: f64,
13 #[cfg(not(target_arch = "wasm32"))]
14 inner: std::time::Instant,
15}
16
17impl Instant {
18 pub fn now() -> Self {
20 Self {
21 #[cfg(target_arch = "wasm32")]
22 value: {
23 thread_local! {
24 static PERFORMANCE: web_sys::Performance = web_sys::window()
25 .expect("no window")
26 .performance()
27 .expect("no performance");
28 }
29 PERFORMANCE.with(|performance| performance.now() / 1000.0)
30 },
31 #[cfg(not(target_arch = "wasm32"))]
32 inner: std::time::Instant::now(),
33 }
34 }
35
36 pub fn duration_since(&self, earlier: Self) -> Duration {
38 #[cfg(target_arch = "wasm32")]
39 return Duration::from_secs_f64(self.value - earlier.value);
40 #[cfg(not(target_arch = "wasm32"))]
41 return Duration::from_secs_f64(self.inner.duration_since(earlier.inner).as_secs_f64());
42 }
43
44 pub fn elapsed(&self) -> Duration {
46 Self::now().duration_since(*self)
47 }
48}
49
50#[derive(Copy, Clone)]
54pub struct Duration {
55 secs: f64,
56}
57
58impl std::ops::Add for Duration {
59 type Output = Self;
60 fn add(self, rhs: Self) -> Self {
61 Self {
62 secs: self.secs + rhs.secs,
63 }
64 }
65}
66
67impl std::fmt::Debug for Duration {
68 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
69 std::time::Duration::from(*self).fmt(f)
70 }
71}
72
73impl Duration {
74 pub fn from_secs_f64(secs: f64) -> Self {
76 Self { secs }
77 }
78
79 pub fn as_secs_f64(&self) -> f64 {
81 self.secs
82 }
83}
84
85impl From<Duration> for std::time::Duration {
86 fn from(value: Duration) -> Self {
87 std::time::Duration::from_secs_f64(value.as_secs_f64())
88 }
89}
90
91impl From<std::time::Duration> for Duration {
92 fn from(value: std::time::Duration) -> Self {
93 Duration::from_secs_f64(value.as_secs_f64())
94 }
95}
96
97pub struct Timer {
99 start: Instant,
100}
101
102impl Timer {
103 #[allow(clippy::new_without_default)]
104 pub fn new() -> Self {
106 Self {
107 start: Instant::now(),
108 }
109 }
110
111 pub fn reset(&mut self) {
113 self.start = Instant::now();
114 }
115
116 pub fn elapsed(&self) -> Duration {
118 self.start.elapsed()
119 }
120
121 pub fn tick(&mut self) -> Duration {
123 let now = Instant::now();
124 let duration = now.duration_since(self.start);
125 self.start = now;
126 duration
127 }
128}
129
130pub async fn sleep(duration: Duration) {
132 #[cfg(target_arch = "wasm32")]
133 {
134 let promise = js_sys::Promise::new(&mut |resolve, _reject| {
135 web_sys::window()
136 .unwrap()
137 .set_timeout_with_callback_and_timeout_and_arguments_0(
138 &resolve,
139 (duration.as_secs_f64() * 1000.0).round() as _,
140 )
141 .unwrap();
142 });
143 let future = wasm_bindgen_futures::JsFuture::from(promise);
144 future.await.unwrap();
145 }
146 #[cfg(not(target_arch = "wasm32"))]
147 {
148 async_std::task::sleep(duration.into()).await;
149 }
150}
151
152#[test]
153fn test() {
154 let mut timer = Timer::new();
155 timer.elapsed();
156 for _ in 0..100 {
157 timer.tick();
158 }
159}