-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
time.rs
75 lines (63 loc) · 2.22 KB
/
time.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
use std::cell::Cell;
use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
use std::task::{Context, Poll};
use std::time::Duration;
use futures::stream;
use futures::stream::Stream;
use gloo::timers::callback::Timeout;
#[inline(always)]
pub(crate) fn sleep(dur: Duration) -> impl Future<Output = ()> {
pub struct Sleep {
inner: Option<Timeout>,
dur_left: Option<u128>,
timeout_registered: Rc<Cell<bool>>,
}
impl Future for Sleep {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
static I32_MAX_U128: u128 = 2_147_483_647;
static I32_MAX_U32: u32 = 2_147_483_647;
// If polling before the registered timeout is reached, return Pending.
if self.timeout_registered.get() {
return Poll::Pending;
}
// set_timeout can only accept maximum of i32, so we wrap around if it gets longer.
let next_timeout = match self.dur_left.map(|m| (m, u32::try_from(m))) {
Some((m_u128, Err(_))) => {
self.dur_left = Some(m_u128 - I32_MAX_U128);
I32_MAX_U32
}
Some((m_u128, _)) if m_u128 > I32_MAX_U128 => {
self.dur_left = Some(m_u128 - I32_MAX_U128);
I32_MAX_U32
}
Some((_, Ok(m_u32))) => {
self.dur_left = None;
m_u32
}
None => return Poll::Ready(()),
};
let waker = cx.waker().clone();
self.timeout_registered.set(true);
let timeout_registered = self.timeout_registered.clone();
self.inner = Some(Timeout::new(next_timeout, move || {
timeout_registered.set(false);
waker.wake();
}));
Poll::Pending
}
}
Sleep {
inner: None,
dur_left: Some(dur.as_millis()),
timeout_registered: Cell::new(false).into(),
}
}
pub(crate) fn interval(dur: Duration) -> impl Stream<Item = ()> {
stream::unfold((), move |_: ()| async move {
sleep(dur).await;
Some(((), ()))
})
}