Skip to content

Commit

Permalink
fix(wasm): Fix panic when Delay is reused before resetting
Browse files Browse the repository at this point in the history
  • Loading branch information
oblique committed Jun 4, 2024
1 parent 07dbe53 commit e2163ce
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 21 deletions.
31 changes: 20 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,26 @@ jobs:
- name: cargo doc
run: cargo doc --no-deps

test_wasm:
name: Test (wasm)
runs-on: ubuntu-latest
strategy:
matrix:
rust:
- stable
steps:
- uses: actions/checkout@master
- name: Install Rust and add wasm target
run: rustup update ${{ matrix.rust }} && rustup default ${{ matrix.rust }} && rustup target add wasm32-unknown-unknown
- name: Install wasm-pack
uses: taiki-e/cache-cargo-install-action@v1
with:
tool: [email protected]
- name: cargo test
run: wasm-pack test --firefox --headless -- --features=wasm-bindgen
- name: cargo doc
run: cargo doc --no-deps --target=wasm32-unknown-unknown --features=wasm-bindgen

style:
name: Style
runs-on: ubuntu-latest
Expand Down Expand Up @@ -59,14 +79,3 @@ jobs:
git -c user.name='ci' -c user.email='ci' commit -m 'Deploy futures-timer API documentation'
git push -f -q https://git:${{ secrets.github_token }}@github.com/${{ github.repository }} HEAD:gh-pages
if: github.event_name == 'push' && github.event.ref == 'refs/heads/master' && github.repository == 'async-rs/futures-timer'

check_wasm:
name: Check Wasm
needs: [test]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Install Rust and add wasm target
run: rustup update stable && rustup target add wasm32-unknown-unknown
- name: cargo check
run: cargo check --target wasm32-unknown-unknown --features wasm-bindgen
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ send_wrapper = { version = "0.4.0", optional = true }

[dev-dependencies]
async-std = { version = "1.0.1", features = ["attributes"] }
cfg-if = "1.0.0"
futures = "0.3.1"
wasm-bindgen-test = "0.3.42"
web-time = "1.1.0"

[features]
wasm-bindgen = [
Expand Down
19 changes: 15 additions & 4 deletions src/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ use std::{

/// A version of `Delay` that works on wasm.
#[derive(Debug)]
pub struct Delay(SendWrapper<TimeoutFuture>);
pub struct Delay(Option<SendWrapper<TimeoutFuture>>);

impl Delay {
/// Creates a new future which will fire at `dur` time into the future.
#[inline]
pub fn new(dur: Duration) -> Delay {
Self(SendWrapper::new(TimeoutFuture::new(dur.as_millis() as u32)))
Self(Some(SendWrapper::new(TimeoutFuture::new(
dur.as_millis() as u32
))))
}

/// Resets the timeout.
Expand All @@ -30,7 +32,16 @@ impl Delay {
impl Future for Delay {
type Output = ();

fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
Pin::new(&mut *Pin::into_inner(self).0).poll(cx)
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
match self.0.as_mut() {
Some(delay) => match Pin::new(&mut **delay).poll(cx) {
Poll::Pending => Poll::Pending,
Poll::Ready(()) => {
self.0.take();
Poll::Ready(())
}
},
None => Poll::Ready(()),
}
}
}
21 changes: 18 additions & 3 deletions tests/smoke.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
use std::error::Error;
use std::pin::Pin;
use std::time::{Duration, Instant};
use std::time::Duration;

use futures::FutureExt;
use futures_timer::Delay;

#[async_std::test]
cfg_if::cfg_if! {
if #[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))] {
use wasm_bindgen_test::wasm_bindgen_test as async_test;
use web_time::Instant;
wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
} else {
use std::time::Instant;
use async_std::test as async_test;
}
}

#[async_test]
async fn works() {
let i = Instant::now();
let dur = Duration::from_millis(100);
let _d = Delay::new(dur).await;
assert!(i.elapsed() > dur);
}

#[async_std::test]
#[async_test]
async fn reset() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
let i = Instant::now();
let dur = Duration::from_millis(100);
Expand All @@ -21,6 +33,9 @@ async fn reset() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
// Allow us to re-use a future
Pin::new(&mut d).await;

// Reusing without resetting should return immediately
Pin::new(&mut d).now_or_never().unwrap();

assert!(i.elapsed() > dur);

let i = Instant::now();
Expand Down
17 changes: 14 additions & 3 deletions tests/timeout.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
use std::error::Error;
use std::time::{Duration, Instant};
use std::time::Duration;

use futures_timer::Delay;

#[async_std::test]
cfg_if::cfg_if! {
if #[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))] {
use wasm_bindgen_test::wasm_bindgen_test as async_test;
use web_time::Instant;
wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
} else {
use std::time::Instant;
use async_std::test as async_test;
}
}

#[async_test]
async fn smoke() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
let dur = Duration::from_millis(10);
let start = Instant::now();
Expand All @@ -12,7 +23,7 @@ async fn smoke() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
Ok(())
}

#[async_std::test]
#[async_test]
async fn two() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
let dur = Duration::from_millis(10);
Delay::new(dur).await;
Expand Down

0 comments on commit e2163ce

Please sign in to comment.