1use crate::{if_native, if_wasm, wasm_or_native};
4use std::fmt;
5
6if_native! {
7 pub use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
8}
9if_wasm! {
10 pub use web_time::{Duration, Instant, SystemTime, UNIX_EPOCH};
11}
12
13#[derive(Debug)]
14pub struct Expired;
15
16impl std::error::Error for Expired {
17 fn description(&self) -> &str {
18 "Timer duration expired"
19 }
20}
21
22if_native! {
23 impl From<tokio::time::error::Elapsed> for Expired {
24 fn from(_: tokio::time::error::Elapsed) -> Expired {
25 Expired
26 }
27 }
28}
29
30impl fmt::Display for Expired {
31 fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
32 write!(f, "timer duration expired")
33 }
34}
35
36fn duration_since_epoch() -> Duration {
37 SystemTime::now()
38 .duration_since(UNIX_EPOCH)
39 .expect("Time went backwards")
40}
41
42pub fn now_ns() -> i64 {
43 duration_since_epoch().as_nanos() as i64
44}
45
46pub fn now_ms() -> u64 {
47 duration_since_epoch().as_millis() as u64
48}
49pub fn now_secs() -> i64 {
50 duration_since_epoch().as_secs() as i64
51}
52
53pub async fn timeout<F>(duration: Duration, future: F) -> Result<F::Output, Expired>
54where
55 F: std::future::IntoFuture,
56{
57 wasm_or_native! {
58 wasm => {
59 use futures::future::Either::*;
60 let millis = duration.as_millis().min(u32::MAX as u128) as u32;
61 let timeout = gloo_timers::future::TimeoutFuture::new(millis);
62 let future = future.into_future();
63 futures::pin_mut!(future);
64 match futures::future::select(timeout, future).await {
65 Left(_) => Err(Expired),
66 Right((value, _)) => Ok(value),
67 }
68 },
69 native => {
70 tokio::time::timeout(duration, future).await.map_err(Into::into)
71 }
72 }
73}
74
75#[doc(hidden)]
76pub async fn sleep(duration: Duration) {
77 wasm_or_native! {
78 native => {tokio::time::sleep(duration).await},
79 wasm => {gloo_timers::future::sleep(duration).await},
80 }
81}
82
83pub fn interval_stream(
84 period: crate::time::Duration,
85) -> impl futures::Stream<Item = crate::time::Instant> {
86 use futures::StreamExt;
87 wasm_or_native! {
88 wasm => {gloo_timers::future::IntervalStream::new(period.as_millis().min(u32::MAX as u128) as u32).map(|_| crate::time::Instant::now())},
89 native => {tokio_stream::wrappers::IntervalStream::new(tokio::time::interval(period)).map(|t| t.into_std())},
90 }
91}