New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement sleep and interval for Yew Platform #2784
Conversation
Visit the preview URL for this PR (updated for commit 4f1973c): https://yew-rs-api--pr2784-sleep-interval-bsns9r0r.web.app (expires Thu, 28 Jul 2022 13:33:40 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 |
Size Comparison
✅ None of the examples has changed their size significantly. |
# Conflicts: # packages/yew/Cargo.toml # packages/yew/tests/use_reducer.rs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, it took so long to get to this. Looks good!
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(), | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why implement it here? What's wrong with the gloo
implementation? If there's a bug or improvement to be made, I think we should fix it there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See: rustwasm/gloo#121
The difficulty of patching it with gloo is due to its callback-first API.
Patching gloo_timers
requires recursively calling setTimeout
, which is difficult to implement due to ownership rules.
It gets worse with Interval
, as we have to implement it with a series of patched Timeout
than using setInterval
.
At that time, it's simply easier to implement Interval with Stream
and make the API future-first.
However, this is a bigger change than it is needed to patch around this behaviour.
I patched it here because we have a future-first API and this have very little impact on code size.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense. I'm not sure who actually is using a timer that's over 24 days long but I'm fine with merging this change.
Patching it in Gloo would be needless (and not small) breaking change
Description
This pull request implements
yew::platform::time
which providessleep()
andinterval()
support.Checklist