Skip to content
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

Fix panic when Delay is used after Poll::Ready #74

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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(()),
}
}
}
30 changes: 27 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 @@ -29,3 +41,15 @@ async fn reset() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
assert!(i.elapsed() > dur);
Ok(())
}

#[async_test]
async fn use_after_ready() {
let dur = Duration::from_millis(100);
let mut d = Delay::new(dur);

Pin::new(&mut d).await;

// Use after ready should return immediately if `Delay::reset`
// was not called.
Pin::new(&mut d).now_or_never().unwrap();
}
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