xmtp_common/
time.rs

1//! Time primitives for native and WebAssembly
2
3use 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}