diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..5c98b42 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,2 @@ +# Default ignored files +/workspace.xml \ No newline at end of file diff --git a/.idea/futures-timer.iml b/.idea/futures-timer.iml new file mode 100644 index 0000000..b7b4242 --- /dev/null +++ b/.idea/futures-timer.iml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..28a804d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..38e13ee --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 676fe3f..f7fa63b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,15 @@ Timeouts for futures. """ [dependencies] +gloo-timers = { version = "0.2.0", features = ["futures"], optional = true } +send_wrapper = { version = "0.4.0", optional = true } [dev-dependencies] async-std = { version = "1.0.1", features = ["attributes"] } futures = "0.3.1" + +[features] +wasm-bindgen = [ + "gloo-timers", + "send_wrapper" +] diff --git a/src/delay.rs b/src/delay.rs index 328eb2f..a4ab758 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -25,7 +25,6 @@ use crate::{ScheduledTimer, TimerHandle}; /// at. pub struct Delay { state: Option>>, - when: Instant, } impl Delay { @@ -38,12 +37,6 @@ impl Delay { Delay::new_handle(Instant::now() + dur, Default::default()) } - /// Return the `Instant` when this delay will fire. - #[inline] - pub fn when(&self) -> Instant { - self.when - } - /// Creates a new future which will fire at the time specified by `at`. /// /// The returned instance of `Delay` will be bound to the timer specified by @@ -51,12 +44,7 @@ impl Delay { pub(crate) fn new_handle(at: Instant, handle: TimerHandle) -> Delay { let inner = match handle.inner.upgrade() { Some(i) => i, - None => { - return Delay { - state: None, - when: at, - } - } + None => return Delay { state: None }, }; let state = Arc::new(Node::new(ScheduledTimer { at: Mutex::new(Some(at)), @@ -70,30 +58,23 @@ impl Delay { // timer, meaning that we'll want to immediately return an error from // `poll`. if inner.list.push(&state).is_err() { - return Delay { - state: None, - when: at, - }; + return Delay { state: None }; } inner.waker.wake(); - Delay { - state: Some(state), - when: at, - } + Delay { state: Some(state) } } /// Resets this timeout to an new timeout which will fire at the time /// specified by `at`. #[inline] - pub fn reset(&mut self, at: Instant) { - self.when = at; - if self._reset(self.when).is_err() { + pub fn reset(&mut self, dur: Duration) { + if self._reset(dur).is_err() { self.state = None } } - fn _reset(&mut self, at: Instant) -> Result<(), ()> { + fn _reset(&mut self, dur: Duration) -> Result<(), ()> { let state = match self.state { Some(ref state) => state, None => return Err(()), @@ -111,7 +92,7 @@ impl Delay { Err(s) => bits = s, } } - *state.at.lock().unwrap() = Some(at); + *state.at.lock().unwrap() = Some(Instant::now() + dur); // If we fail to push our node then we've become an inert timer, so // we'll want to clear our `state` field accordingly timeouts.list.push(state)?; @@ -165,6 +146,6 @@ impl Drop for Delay { impl fmt::Debug for Delay { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - f.debug_struct("Delay").field("when", &self.when).finish() + f.debug_struct("Delay").finish() } } diff --git a/src/delay_wasm.rs b/src/delay_wasm.rs new file mode 100644 index 0000000..2ec56ac --- /dev/null +++ b/src/delay_wasm.rs @@ -0,0 +1,36 @@ +//! A version of `Delay` that works on wasm. + +use gloo_timers::future::TimeoutFuture; +use send_wrapper::SendWrapper; +use std::{ + future::Future, + pin::Pin, + task::{Context, Poll}, + time::Duration, +}; + +/// A version of `Delay` that works on wasm. +#[derive(Debug)] +pub struct Delay(SendWrapper); + +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))) + } + + /// Resets the timeout. + #[inline] + pub fn reset(&mut self, dur: Duration) { + *self = Delay::new(at); + } +} + +impl Future for Delay { + type Output = (); + + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { + Pin::new(&mut *Pin::into_inner(self).0).poll(cx) + } +} diff --git a/src/lib.rs b/src/lib.rs index 005c75f..f9173f4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,15 +2,13 @@ //! //! # Examples //! -//! ```no_run -//! # #[async_std::main] -//! # async fn main() { +//! ``` //! use std::time::Duration; //! use futures_timer::Delay; +//! use futures::executor::block_on; //! -//! let now = Delay::new(Duration::from_secs(3)).await; +//! let now = block_on(Delay::new(Duration::from_secs(3))); //! println!("waited for 3 secs"); -//! # } //! ``` #![deny(missing_docs)] @@ -18,7 +16,10 @@ mod arc_list; mod atomic_waker; +#[cfg(not(all(target_arch = "wasm32", feature = "wasm-bindgen")))] mod delay; +#[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))] +mod delay_wasm; mod global; mod heap; mod heap_timer; @@ -30,4 +31,7 @@ use heap::{Heap, Slot}; use heap_timer::HeapTimer; use timer::{ScheduledTimer, Timer, TimerHandle}; +#[cfg(not(all(target_arch = "wasm32", feature = "wasm-bindgen")))] pub use self::delay::Delay; +#[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))] +pub use self::delay_wasm::Delay; diff --git a/tests/smoke.rs b/tests/smoke.rs index a8da290..b2f172e 100644 --- a/tests/smoke.rs +++ b/tests/smoke.rs @@ -24,7 +24,7 @@ async fn reset() -> Result<(), Box> { assert!(i.elapsed() > dur); let i = Instant::now(); - d.reset(Instant::now() + dur); + d.reset(dur); d.await; assert!(i.elapsed() > dur); Ok(())