batbox_time/
lib.rs

1//! Time related things
2//!
3//! [std::time] is not working on web so use this instead
4#![warn(missing_docs)]
5
6/// A measurement of a monotonically nondecreasing clock.
7///
8/// Alternative of [std::time::Instant]
9#[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    /// Returns an instant corresponding to "now".
19    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    /// Returns the amount of time elapsed from another instant to this one
37    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    /// Returns the amount of time elapsed since this instant
45    pub fn elapsed(&self) -> Duration {
46        Self::now().duration_since(*self)
47    }
48}
49
50/// Represents a span of time.
51///
52/// Alternative of [std::time::Duration]
53#[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    /// Creates a new Duration from the specified number of seconds represented as f64.
75    pub fn from_secs_f64(secs: f64) -> Self {
76        Self { secs }
77    }
78
79    /// Returns the number of seconds contained by this Duration as f64
80    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
97/// Timer can be used to track time since some instant
98pub struct Timer {
99    start: Instant,
100}
101
102impl Timer {
103    #[allow(clippy::new_without_default)]
104    /// Constructs a new timer.
105    pub fn new() -> Self {
106        Self {
107            start: Instant::now(),
108        }
109    }
110
111    /// Reset timer
112    pub fn reset(&mut self) {
113        self.start = Instant::now();
114    }
115
116    /// Get duration elapsed since last reset.
117    pub fn elapsed(&self) -> Duration {
118        self.start.elapsed()
119    }
120
121    /// Reset, and get time elapsed since last reset.
122    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
130/// Sleep for specified duration
131pub 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}