From 6df4afb6710c86888dfbccfcd4c3f1b1af7db036 Mon Sep 17 00:00:00 2001 From: Alex Hamilton Date: Thu, 21 Mar 2019 22:54:40 -0500 Subject: [PATCH 1/5] Split up callback and future/stream APIs. The future/stream versions are behind the "futures" feature gate. This gate is propagated through the workspace using appropriate feature names. Closes #36. --- Cargo.toml | 4 + crates/timers/Cargo.toml | 15 +- crates/timers/src/lib.rs | 738 ++++++++++++++++++++------------------- 3 files changed, 393 insertions(+), 364 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 94da6375..424c6a56 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,4 +10,8 @@ version = "0.1.0" [dependencies] gloo-timers = { version = "0.1.0", path = "crates/timers" } +[features] +default = [] +futures = ["gloo-timers/use_futures"] + [workspace] diff --git a/crates/timers/Cargo.toml b/crates/timers/Cargo.toml index 3916173c..a2f345ed 100644 --- a/crates/timers/Cargo.toml +++ b/crates/timers/Cargo.toml @@ -5,10 +5,16 @@ authors = ["Rust and WebAssembly Working Group"] edition = "2018" [dependencies] -wasm-bindgen-futures = "0.3.14" wasm-bindgen = "0.2.37" js-sys = "0.3.14" -futures = "0.1.25" + +[dependencies.futures] +version = "0.1.25" +optional = true + +[dependencies.wasm-bindgen-futures] +version = "0.3.14" +optional = true [dependencies.web-sys] version = "0.3.14" @@ -16,5 +22,10 @@ features = [ "Window", ] +[features] +default = [] +use_futures = ["futures", "wasm-bindgen-futures"] + + [dev-dependencies] wasm-bindgen-test = "0.2.37" diff --git a/crates/timers/src/lib.rs b/crates/timers/src/lib.rs index 6bc093a3..bd749b3c 100644 --- a/crates/timers/src/lib.rs +++ b/crates/timers/src/lib.rs @@ -57,187 +57,257 @@ TODO #![deny(missing_docs, missing_debug_implementations)] -use futures::prelude::*; -use futures::sync::mpsc; -use std::fmt; use wasm_bindgen::prelude::*; -use wasm_bindgen::JsCast; -use wasm_bindgen_futures::JsFuture; fn window() -> web_sys::Window { web_sys::window().unwrap_throw() } -/// A scheduled timeout. -/// -/// See `Timeout::new` for scheduling new timeouts. -/// -/// Once scheduled, you can either `cancel` so that it doesn't run or `forget` -/// it so that it is un-cancel-able. -#[must_use = "timeouts cancel on drop; either call `forget` or `drop` explicitly"] -pub struct Timeout { - id: Option, - closure: Option>, -} +/// Callback-style APIs. +pub mod callback { + use super::window; + use std::fmt; + use wasm_bindgen::prelude::*; + use wasm_bindgen::JsCast; + /// A scheduled timeout. + /// + /// See `Timeout::new` for scheduling new timeouts. + /// + /// Once scheduled, you can either `cancel` so that it doesn't run or `forget` + /// it so that it is un-cancel-able. + #[must_use = "timeouts cancel on drop; either call `forget` or `drop` explicitly"] + pub struct Timeout { + id: Option, + closure: Option>, + } -impl Drop for Timeout { - fn drop(&mut self) { - if let Some(id) = self.id { - window().clear_timeout_with_handle(id); + impl Drop for Timeout { + fn drop(&mut self) { + if let Some(id) = self.id { + window().clear_timeout_with_handle(id); + } } } -} -impl fmt::Debug for Timeout { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Timeout").field("id", &self.id).finish() + impl fmt::Debug for Timeout { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Timeout").field("id", &self.id).finish() + } } -} -impl Timeout { - /// Schedule a timeout to invoke `callback` in `millis` milliseconds from - /// now. - /// - /// # Example - /// - /// ```no_run - /// use gloo_timers::Timeout; - /// - /// let timeout = Timeout::new(1_000, move || { - /// // Do something... - /// }); - /// ``` - pub fn new(millis: u32, callback: F) -> Timeout - where - F: 'static + FnOnce(), - { - // TODO: Use `FnOnce` here after this merges: - // https://github.com/rustwasm/wasm-bindgen/pull/1281 - let mut callback = Some(callback); - let closure = Closure::wrap(Box::new(move || { - let callback = callback.take().unwrap_throw(); - callback(); - }) as Box); - - let id = window() - .set_timeout_with_callback_and_timeout_and_arguments_0( - closure.as_ref().unchecked_ref::(), - millis as i32, - ) - .unwrap_throw(); - - Timeout { - id: Some(id), - closure: Some(closure), + impl Timeout { + /// Schedule a timeout to invoke `callback` in `millis` milliseconds from + /// now. + /// + /// # Example + /// + /// ```no_run + /// use gloo_timers::Timeout; + /// + /// let timeout = Timeout::new(1_000, move || { + /// // Do something... + /// }); + /// ``` + pub fn new(millis: u32, callback: F) -> Timeout + where + F: 'static + FnOnce(), + { + // TODO: Use `FnOnce` here after this merges: + // https://github.com/rustwasm/wasm-bindgen/pull/1281 + let mut callback = Some(callback); + let closure = Closure::wrap(Box::new(move || { + let callback = callback.take().unwrap_throw(); + callback(); + }) as Box); + + let id = window() + .set_timeout_with_callback_and_timeout_and_arguments_0( + closure.as_ref().unchecked_ref::(), + millis as i32, + ) + .unwrap_throw(); + + Timeout { + id: Some(id), + closure: Some(closure), + } } - } - /// Make this timeout uncancel-able. - /// - /// Returns the identifier returned by the original `setTimeout` call, and - /// therefore you can still cancel the timeout by calling `clearTimeout` - /// directly (perhaps via `web_sys::clear_timeout_with_handle`). - /// - /// # Example + /// Make this timeout uncancel-able. + /// + /// Returns the identifier returned by the original `setTimeout` call, and + /// therefore you can still cancel the timeout by calling `clearTimeout` + /// directly (perhaps via `web_sys::clear_timeout_with_handle`). + /// + /// # Example + /// + /// ```no_run + /// use gloo_timers::Timeout; + /// + /// // We definitely want to do stuff, and aren't going to ever cancel this + /// // timeout. + /// Timeout::new(1_000, || { + /// // Do stuff... + /// }).forget(); + /// ``` + pub fn forget(mut self) -> i32 { + let id = self.id.take().unwrap_throw(); + self.closure.take().unwrap_throw().forget(); + id + } + + /// Cancel this timeout so that the callback is not invoked after the time + /// is up. + /// + /// The scheduled callback is returned. + /// + /// # Example + /// + /// ```no_run + /// use gloo_timers::Timeout; + /// + /// let timeout = Timeout::new(1_000, || { + /// // Do stuff... + /// }); + /// + /// // If actually we didn't want to set a timer, then cancel it. + /// if nevermind() { + /// timeout.cancel(); + /// } + /// # fn nevermind() -> bool { true } + /// ``` + pub fn cancel(mut self) -> Closure { + self.closure.take().unwrap_throw() + } + } + /// A scheduled interval. /// - /// ```no_run - /// use gloo_timers::Timeout; + /// See `Interval::new` for scheduling new intervals. /// - /// // We definitely want to do stuff, and aren't going to ever cancel this - /// // timeout. - /// Timeout::new(1_000, || { - /// // Do stuff... - /// }).forget(); - /// ``` - pub fn forget(mut self) -> i32 { - let id = self.id.take().unwrap_throw(); - self.closure.take().unwrap_throw().forget(); - id + /// Once scheduled, you can either `cancel` so that it ceases to fire or `forget` + /// it so that it is un-cancel-able. + #[must_use = "intervals cancel on drop; either call `forget` or `drop` explicitly"] + pub struct Interval { + id: Option, + closure: Option>, } - /// Cancel this timeout so that the callback is not invoked after the time - /// is up. - /// - /// The scheduled callback is returned. - /// - /// # Example - /// - /// ```no_run - /// use gloo_timers::Timeout; - /// - /// let timeout = Timeout::new(1_000, || { - /// // Do stuff... - /// }); - /// - /// // If actually we didn't want to set a timer, then cancel it. - /// if nevermind() { - /// timeout.cancel(); - /// } - /// # fn nevermind() -> bool { true } - /// ``` - pub fn cancel(mut self) -> Closure { - self.closure.take().unwrap_throw() + impl Drop for Interval { + fn drop(&mut self) { + if let Some(id) = self.id { + window().clear_interval_with_handle(id); + } + } } -} -/// A scheduled timeout as a `Future`. -/// -/// See `TimeoutFuture::new` for scheduling new timeouts. -/// -/// Once scheduled, if you change your mind and don't want the timeout to fire, -/// you can `drop` the future. -/// -/// A timeout future will never resolve to `Err`. Its only failure mode is when -/// the timeout is so long that it is effectively infinite and never fires. -/// -/// # Example -/// -/// ```no_run -/// use futures::prelude::*; -/// use gloo_timers::TimeoutFuture; -/// -/// let timeout_a = TimeoutFuture::new(1_000).map(|_| "a"); -/// let timeout_b = TimeoutFuture::new(2_000).map(|_| "b"); -/// -/// wasm_bindgen_futures::spawn_local( -/// timeout_a -/// .select(timeout_b) -/// .and_then(|(who, other)| { -/// // `timeout_a` should have won this race. -/// assert_eq!(who, "a"); -/// -/// // Drop `timeout_b` to cancel its timeout. -/// drop(other); -/// -/// Ok(()) -/// }) -/// .map_err(|_| { -/// wasm_bindgen::throw_str( -/// "unreachable -- timeouts never fail, only potentially hang" -/// ); -/// }) -/// ); -/// ``` -#[must_use = "futures do nothing unless polled or spawned"] -pub struct TimeoutFuture { - id: Option, - inner: JsFuture, -} + impl fmt::Debug for Interval { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Interval").field("id", &self.id).finish() + } + } -impl Drop for TimeoutFuture { - fn drop(&mut self) { - if let Some(id) = self.id { - window().clear_timeout_with_handle(id); + impl Interval { + /// Schedule an interval to invoke `callback` every `millis` milliseconds. + /// + /// # Example + /// + /// ```no_run + /// use gloo_timers::Interval; + /// + /// let interval = Interval::new(1_000, move || { + /// // Do something... + /// }); + /// ``` + pub fn new(millis: u32, callback: F) -> Interval + where + F: 'static + FnMut(), + { + let mut callback = Some(callback); + let closure = Closure::wrap(Box::new(move || { + let mut callback = callback.take().unwrap_throw(); + callback(); + }) as Box); + + let id = window() + .set_interval_with_callback_and_timeout_and_arguments_0( + closure.as_ref().unchecked_ref::(), + millis as i32, + ) + .unwrap_throw(); + + Interval { + id: Some(id), + closure: Some(closure), + } + } + + /// Make this interval uncancel-able. + /// + /// Returns the identifier returned by the original `setInterval` call, and + /// therefore you can still cancel the interval by calling `clearInterval` + /// directly (perhaps via `web_sys::clear_interval_with_handle`). + /// + /// # Example + /// + /// ```no_run + /// use gloo_timers::Interval; + /// + /// // We want to do stuff every second, indefinitely. + /// Interval::new(1_000, || { + /// // Do stuff... + /// }).forget(); + /// ``` + pub fn forget(mut self) -> i32 { + let id = self.id.take().unwrap_throw(); + self.closure.take().unwrap_throw().forget(); + id + } + + /// Cancel this interval so that the callback is no longer periodically + /// invoked. + /// + /// The scheduled callback is returned. + /// + /// # Example + /// + /// ```no_run + /// use gloo_timers::Interval; + /// + /// let interval = Interval::new(1_000, || { + /// // Do stuff... + /// }); + /// + /// // If we don't want this interval to run anymore, then cancel it. + /// if nevermind() { + /// interval.cancel(); + /// } + /// # fn nevermind() -> bool { true } + /// ``` + pub fn cancel(mut self) -> Closure { + self.closure.take().unwrap_throw() } } } -impl TimeoutFuture { - /// Create a new timeout future. +/// Future/stream-backed APIs. +#[cfg(feature = "use_futures")] +pub mod future { + use super::window; + use futures::prelude::*; + use futures::sync::mpsc; + use std::fmt; + use wasm_bindgen::prelude::*; + use wasm_bindgen::JsCast; + use wasm_bindgen_futures::JsFuture; + /// A scheduled timeout as a `Future`. + /// + /// See `TimeoutFuture::new` for scheduling new timeouts. + /// + /// Once scheduled, if you change your mind and don't want the timeout to fire, + /// you can `drop` the future. /// - /// Remember that futures do nothing unless polled or spawned, so either - /// pass this future to `wasm_bindgen_futures::spawn_local` or use it inside - /// another future. + /// A timeout future will never resolve to `Err`. Its only failure mode is when + /// the timeout is so long that it is effectively infinite and never fires. /// /// # Example /// @@ -245,241 +315,185 @@ impl TimeoutFuture { /// use futures::prelude::*; /// use gloo_timers::TimeoutFuture; /// + /// let timeout_a = TimeoutFuture::new(1_000).map(|_| "a"); + /// let timeout_b = TimeoutFuture::new(2_000).map(|_| "b"); + /// /// wasm_bindgen_futures::spawn_local( - /// TimeoutFuture::new(1_000).map(|_| { - /// // Do stuff after one second... - /// }) + /// timeout_a + /// .select(timeout_b) + /// .and_then(|(who, other)| { + /// // `timeout_a` should have won this race. + /// assert_eq!(who, "a"); + /// + /// // Drop `timeout_b` to cancel its timeout. + /// drop(other); + /// + /// Ok(()) + /// }) + /// .map_err(|_| { + /// wasm_bindgen::throw_str( + /// "unreachable -- timeouts never fail, only potentially hang" + /// ); + /// }) /// ); /// ``` - pub fn new(millis: u32) -> TimeoutFuture { - let mut id = None; - let promise = js_sys::Promise::new(&mut |resolve, _reject| { - id = Some( - window() - .set_timeout_with_callback_and_timeout_and_arguments_0(&resolve, millis as i32) - .unwrap_throw(), - ); - }); - debug_assert!(id.is_some()); - let inner = JsFuture::from(promise); - TimeoutFuture { id, inner } + #[must_use = "futures do nothing unless polled or spawned"] + pub struct TimeoutFuture { + id: Option, + inner: JsFuture, } -} -impl fmt::Debug for TimeoutFuture { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("TimeoutFuture") - .field("id", &self.id) - .finish() - } -} - -impl Future for TimeoutFuture { - type Item = (); - type Error = (); - - fn poll(&mut self) -> Poll<(), ()> { - match self.inner.poll() { - Ok(Async::Ready(_)) => Ok(Async::Ready(())), - Ok(Async::NotReady) => Ok(Async::NotReady), - // We only ever `resolve` the promise, never reject it. - Err(_) => wasm_bindgen::throw_str("unreachable"), + impl Drop for TimeoutFuture { + fn drop(&mut self) { + if let Some(id) = self.id { + window().clear_timeout_with_handle(id); + } } } -} -/// A scheduled interval. -/// -/// See `Interval::new` for scheduling new intervals. -/// -/// Once scheduled, you can either `cancel` so that it ceases to fire or `forget` -/// it so that it is un-cancel-able. -#[must_use = "intervals cancel on drop; either call `forget` or `drop` explicitly"] -pub struct Interval { - id: Option, - closure: Option>, -} - -impl Drop for Interval { - fn drop(&mut self) { - if let Some(id) = self.id { - window().clear_interval_with_handle(id); + impl TimeoutFuture { + /// Create a new timeout future. + /// + /// Remember that futures do nothing unless polled or spawned, so either + /// pass this future to `wasm_bindgen_futures::spawn_local` or use it inside + /// another future. + /// + /// # Example + /// + /// ```no_run + /// use futures::prelude::*; + /// use gloo_timers::TimeoutFuture; + /// + /// wasm_bindgen_futures::spawn_local( + /// TimeoutFuture::new(1_000).map(|_| { + /// // Do stuff after one second... + /// }) + /// ); + /// ``` + pub fn new(millis: u32) -> TimeoutFuture { + let mut id = None; + let promise = js_sys::Promise::new(&mut |resolve, _reject| { + id = Some( + window() + .set_timeout_with_callback_and_timeout_and_arguments_0( + &resolve, + millis as i32, + ) + .unwrap_throw(), + ); + }); + debug_assert!(id.is_some()); + let inner = JsFuture::from(promise); + TimeoutFuture { id, inner } } } -} -impl fmt::Debug for Interval { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Interval").field("id", &self.id).finish() + impl fmt::Debug for TimeoutFuture { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("TimeoutFuture") + .field("id", &self.id) + .finish() + } } -} -impl Interval { - /// Schedule an interval to invoke `callback` every `millis` milliseconds. - /// - /// # Example - /// - /// ```no_run - /// use gloo_timers::Interval; - /// - /// let interval = Interval::new(1_000, move || { - /// // Do something... - /// }); - /// ``` - pub fn new(millis: u32, callback: F) -> Interval - where - F: 'static + FnMut(), - { - let mut callback = Some(callback); - let closure = Closure::wrap(Box::new(move || { - let mut callback = callback.take().unwrap_throw(); - callback(); - }) as Box); - - let id = window() - .set_interval_with_callback_and_timeout_and_arguments_0( - closure.as_ref().unchecked_ref::(), - millis as i32, - ) - .unwrap_throw(); - - Interval { - id: Some(id), - closure: Some(closure), + impl Future for TimeoutFuture { + type Item = (); + type Error = (); + + fn poll(&mut self) -> Poll<(), ()> { + match self.inner.poll() { + Ok(Async::Ready(_)) => Ok(Async::Ready(())), + Ok(Async::NotReady) => Ok(Async::NotReady), + // We only ever `resolve` the promise, never reject it. + Err(_) => wasm_bindgen::throw_str("unreachable"), + } } } - - /// Make this interval uncancel-able. - /// - /// Returns the identifier returned by the original `setInterval` call, and - /// therefore you can still cancel the interval by calling `clearInterval` - /// directly (perhaps via `web_sys::clear_interval_with_handle`). + /// A scheduled interval as a `Stream`. /// - /// # Example + /// See `IntervalStream::new` for scheduling new intervals. /// - /// ```no_run - /// use gloo_timers::Interval; + /// Once scheduled, if you want to stop the interval from continuing to fire, + /// you can `drop` the stream. /// - /// // We want to do stuff every second, indefinitely. - /// Interval::new(1_000, || { - /// // Do stuff... - /// }).forget(); - /// ``` - pub fn forget(mut self) -> i32 { - let id = self.id.take().unwrap_throw(); - self.closure.take().unwrap_throw().forget(); - id + /// An interval stream will never resolve to `Err`. + #[must_use = "streams do nothing unless polled or spawned"] + pub struct IntervalStream { + millis: u32, + id: Option, + closure: Closure, + inner: mpsc::UnboundedReceiver<()>, } - /// Cancel this interval so that the callback is no longer periodically - /// invoked. - /// - /// The scheduled callback is returned. - /// - /// # Example - /// - /// ```no_run - /// use gloo_timers::Interval; - /// - /// let interval = Interval::new(1_000, || { - /// // Do stuff... - /// }); - /// - /// // If we don't want this interval to run anymore, then cancel it. - /// if nevermind() { - /// interval.cancel(); - /// } - /// # fn nevermind() -> bool { true } - /// ``` - pub fn cancel(mut self) -> Closure { - self.closure.take().unwrap_throw() - } -} - -/// A scheduled interval as a `Stream`. -/// -/// See `IntervalStream::new` for scheduling new intervals. -/// -/// Once scheduled, if you want to stop the interval from continuing to fire, -/// you can `drop` the stream. -/// -/// An interval stream will never resolve to `Err`. -#[must_use = "streams do nothing unless polled or spawned"] -pub struct IntervalStream { - millis: u32, - id: Option, - closure: Closure, - inner: mpsc::UnboundedReceiver<()>, -} - -impl IntervalStream { - /// Create a new interval stream. - /// - /// Remember that streams do nothing unless polled or spawned, so either - /// spawn this stream via `wasm_bindgen_futures::spawn_local` or use it inside - /// another stream or future. - /// - /// # Example - /// - /// ```no_run - /// use futures::prelude::*; - /// use gloo_timers::IntervalStream; - /// - /// wasm_bindgen_futures::spawn_local( - /// IntervalStream::new(1_000) - /// .for_each(|_| { - /// // Do stuff every one second... - /// Ok(()) - /// }) - /// ); - /// ``` - pub fn new(millis: u32) -> IntervalStream { - let (sender, receiver) = mpsc::unbounded(); - let closure = Closure::wrap(Box::new(move || { - sender.unbounded_send(()).unwrap(); - }) as Box); - - IntervalStream { - millis, - id: None, - closure, - inner: receiver, + impl IntervalStream { + /// Create a new interval stream. + /// + /// Remember that streams do nothing unless polled or spawned, so either + /// spawn this stream via `wasm_bindgen_futures::spawn_local` or use it inside + /// another stream or future. + /// + /// # Example + /// + /// ```no_run + /// use futures::prelude::*; + /// use gloo_timers::IntervalStream; + /// + /// wasm_bindgen_futures::spawn_local( + /// IntervalStream::new(1_000) + /// .for_each(|_| { + /// // Do stuff every one second... + /// Ok(()) + /// }) + /// ); + /// ``` + pub fn new(millis: u32) -> IntervalStream { + let (sender, receiver) = mpsc::unbounded(); + let closure = Closure::wrap(Box::new(move || { + sender.unbounded_send(()).unwrap(); + }) as Box); + + IntervalStream { + millis, + id: None, + closure, + inner: receiver, + } } } -} -impl Drop for IntervalStream { - fn drop(&mut self) { - if let Some(id) = self.id { - window().clear_interval_with_handle(id); + impl Drop for IntervalStream { + fn drop(&mut self) { + if let Some(id) = self.id { + window().clear_interval_with_handle(id); + } } } -} -impl fmt::Debug for IntervalStream { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("IntervalStream") - .field("id", &self.id) - .finish() + impl fmt::Debug for IntervalStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("IntervalStream") + .field("id", &self.id) + .finish() + } } -} -impl Stream for IntervalStream { - type Item = (); - type Error = (); - - fn poll(&mut self) -> Poll, ()> { - if self.id.is_none() { - self.id = Some( - window() - .set_interval_with_callback_and_timeout_and_arguments_0( - self.closure.as_ref().unchecked_ref::(), - self.millis as i32, - ) - .unwrap_throw(), - ); + impl Stream for IntervalStream { + type Item = (); + type Error = (); + + fn poll(&mut self) -> Poll, ()> { + if self.id.is_none() { + self.id = Some( + window() + .set_interval_with_callback_and_timeout_and_arguments_0( + self.closure.as_ref().unchecked_ref::(), + self.millis as i32, + ) + .unwrap_throw(), + ); + } + + self.inner.poll() } - - self.inner.poll() } } From 70773b6c4bb8b521040a1e87fb1fb04a4146b4cd Mon Sep 17 00:00:00 2001 From: Alex Hamilton Date: Thu, 21 Mar 2019 23:22:11 -0500 Subject: [PATCH 2/5] Fix tests to accommodate new submodules. --- crates/timers/src/lib.rs | 28 +++++++++++++++------------- crates/timers/tests/web.rs | 8 +++++--- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/crates/timers/src/lib.rs b/crates/timers/src/lib.rs index bd749b3c..75503328 100644 --- a/crates/timers/src/lib.rs +++ b/crates/timers/src/lib.rs @@ -14,7 +14,7 @@ Timeouts fire once after a period of time (measured in milliseconds). ### Timeouts with a Callback Function ```no_run -use gloo_timers::Timeout; +use gloo_timers::callback::Timeout; let timeout = Timeout::new(1_000, move || { // Do something after the one second timeout is up! @@ -25,10 +25,12 @@ timeout.forget(); ``` ### Timeouts as `Future`s - -```no_run +*/ +#![cfg_attr(feature = "use_futures", doc = "```no_run")] +#![cfg_attr(not(feature = "use_futures"), doc = "```ignore")] +/*! use futures::prelude::*; -use gloo_timers::TimeoutFuture; +use gloo_timers::future::TimeoutFuture; use wasm_bindgen_futures::spawn_local; let timeout = TimeoutFuture::new(1_000).and_then(|_| { @@ -102,7 +104,7 @@ pub mod callback { /// # Example /// /// ```no_run - /// use gloo_timers::Timeout; + /// use gloo_timers::callback::Timeout; /// /// let timeout = Timeout::new(1_000, move || { /// // Do something... @@ -142,7 +144,7 @@ pub mod callback { /// # Example /// /// ```no_run - /// use gloo_timers::Timeout; + /// use gloo_timers::callback::Timeout; /// /// // We definitely want to do stuff, and aren't going to ever cancel this /// // timeout. @@ -164,7 +166,7 @@ pub mod callback { /// # Example /// /// ```no_run - /// use gloo_timers::Timeout; + /// use gloo_timers::callback::Timeout; /// /// let timeout = Timeout::new(1_000, || { /// // Do stuff... @@ -212,7 +214,7 @@ pub mod callback { /// # Example /// /// ```no_run - /// use gloo_timers::Interval; + /// use gloo_timers::callback::Interval; /// /// let interval = Interval::new(1_000, move || { /// // Do something... @@ -250,7 +252,7 @@ pub mod callback { /// # Example /// /// ```no_run - /// use gloo_timers::Interval; + /// use gloo_timers::callback::Interval; /// /// // We want to do stuff every second, indefinitely. /// Interval::new(1_000, || { @@ -271,7 +273,7 @@ pub mod callback { /// # Example /// /// ```no_run - /// use gloo_timers::Interval; + /// use gloo_timers::callback::Interval; /// /// let interval = Interval::new(1_000, || { /// // Do stuff... @@ -313,7 +315,7 @@ pub mod future { /// /// ```no_run /// use futures::prelude::*; - /// use gloo_timers::TimeoutFuture; + /// use gloo_timers::future::TimeoutFuture; /// /// let timeout_a = TimeoutFuture::new(1_000).map(|_| "a"); /// let timeout_b = TimeoutFuture::new(2_000).map(|_| "b"); @@ -362,7 +364,7 @@ pub mod future { /// /// ```no_run /// use futures::prelude::*; - /// use gloo_timers::TimeoutFuture; + /// use gloo_timers::future::TimeoutFuture; /// /// wasm_bindgen_futures::spawn_local( /// TimeoutFuture::new(1_000).map(|_| { @@ -436,7 +438,7 @@ pub mod future { /// /// ```no_run /// use futures::prelude::*; - /// use gloo_timers::IntervalStream; + /// use gloo_timers::future::IntervalStream; /// /// wasm_bindgen_futures::spawn_local( /// IntervalStream::new(1_000) diff --git a/crates/timers/tests/web.rs b/crates/timers/tests/web.rs index 3d3e434e..32aec61b 100644 --- a/crates/timers/tests/web.rs +++ b/crates/timers/tests/web.rs @@ -1,9 +1,11 @@ //! Test suite for the Web and headless browsers. -#![cfg(target_arch = "wasm32")] - +#![cfg(all(target_arch = "wasm32", feature = "use_futures"))] use futures::prelude::*; -use gloo_timers::{Interval, IntervalStream, Timeout, TimeoutFuture}; +use gloo_timers::{ + callback::{Interval, Timeout}, + future::{IntervalStream, TimeoutFuture}, +}; use std::cell::Cell; use std::rc::Rc; use wasm_bindgen_test::*; From fcb6891b6c4fc1ae624231a24d3bea9df777f5c5 Mon Sep 17 00:00:00 2001 From: Alex Hamilton Date: Sun, 24 Mar 2019 16:31:15 -0500 Subject: [PATCH 3/5] Change feature name to "futures". --- Cargo.toml | 2 +- crates/timers/Cargo.toml | 5 +++-- crates/timers/src/lib.rs | 13 ++++++++++--- crates/timers/tests/web.rs | 4 ++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 424c6a56..ee6a3489 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,6 @@ gloo-timers = { version = "0.1.0", path = "crates/timers" } [features] default = [] -futures = ["gloo-timers/use_futures"] +futures = ["gloo-timers/futures"] [workspace] diff --git a/crates/timers/Cargo.toml b/crates/timers/Cargo.toml index a2f345ed..7b21fc95 100644 --- a/crates/timers/Cargo.toml +++ b/crates/timers/Cargo.toml @@ -8,7 +8,8 @@ edition = "2018" wasm-bindgen = "0.2.37" js-sys = "0.3.14" -[dependencies.futures] +[dependencies.futures_rs] +package = "futures" version = "0.1.25" optional = true @@ -24,7 +25,7 @@ features = [ [features] default = [] -use_futures = ["futures", "wasm-bindgen-futures"] +futures = ["futures_rs", "wasm-bindgen-futures"] [dev-dependencies] diff --git a/crates/timers/src/lib.rs b/crates/timers/src/lib.rs index 75503328..93ae9c91 100644 --- a/crates/timers/src/lib.rs +++ b/crates/timers/src/lib.rs @@ -26,9 +26,10 @@ timeout.forget(); ### Timeouts as `Future`s */ -#![cfg_attr(feature = "use_futures", doc = "```no_run")] -#![cfg_attr(not(feature = "use_futures"), doc = "```ignore")] +#![cfg_attr(feature = "futures", doc = "```no_run")] +#![cfg_attr(not(feature = "futures"), doc = "```ignore")] /*! +# extern crate futures_rs as futures; use futures::prelude::*; use gloo_timers::future::TimeoutFuture; use wasm_bindgen_futures::spawn_local; @@ -59,6 +60,9 @@ TODO #![deny(missing_docs, missing_debug_implementations)] +#[cfg(feature = "futures")] +extern crate futures_rs as futures; + use wasm_bindgen::prelude::*; fn window() -> web_sys::Window { @@ -292,7 +296,7 @@ pub mod callback { } /// Future/stream-backed APIs. -#[cfg(feature = "use_futures")] +#[cfg(feature = "futures")] pub mod future { use super::window; use futures::prelude::*; @@ -314,6 +318,7 @@ pub mod future { /// # Example /// /// ```no_run + /// # extern crate futures_rs as futures; /// use futures::prelude::*; /// use gloo_timers::future::TimeoutFuture; /// @@ -363,6 +368,7 @@ pub mod future { /// # Example /// /// ```no_run + /// # extern crate futures_rs as futures; /// use futures::prelude::*; /// use gloo_timers::future::TimeoutFuture; /// @@ -437,6 +443,7 @@ pub mod future { /// # Example /// /// ```no_run + /// # extern crate futures_rs as futures; /// use futures::prelude::*; /// use gloo_timers::future::IntervalStream; /// diff --git a/crates/timers/tests/web.rs b/crates/timers/tests/web.rs index 32aec61b..642a948c 100644 --- a/crates/timers/tests/web.rs +++ b/crates/timers/tests/web.rs @@ -1,7 +1,7 @@ //! Test suite for the Web and headless browsers. -#![cfg(all(target_arch = "wasm32", feature = "use_futures"))] -use futures::prelude::*; +#![cfg(all(target_arch = "wasm32", feature = "futures"))] +use futures_rs::prelude::*; use gloo_timers::{ callback::{Interval, Timeout}, future::{IntervalStream, TimeoutFuture}, From 4664ccfc104c7d0abefd40661a6402d854201376 Mon Sep 17 00:00:00 2001 From: Alex Hamilton Date: Mon, 25 Mar 2019 14:03:00 -0500 Subject: [PATCH 4/5] Add note about feature requirement to docs. --- crates/timers/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/timers/src/lib.rs b/crates/timers/src/lib.rs index 93ae9c91..33ea9ab1 100644 --- a/crates/timers/src/lib.rs +++ b/crates/timers/src/lib.rs @@ -25,6 +25,10 @@ timeout.forget(); ``` ### Timeouts as `Future`s + +With the `futures` feature enabled, a `future` module containing futures-based +timers is exposed. + */ #![cfg_attr(feature = "futures", doc = "```no_run")] #![cfg_attr(not(feature = "futures"), doc = "```ignore")] From 105043fcf9ad1a75ef3b5f27337c2a64525ac57a Mon Sep 17 00:00:00 2001 From: Alex Hamilton Date: Mon, 25 Mar 2019 14:14:51 -0500 Subject: [PATCH 5/5] Fix console-timer import. --- crates/console-timer/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/console-timer/src/lib.rs b/crates/console-timer/src/lib.rs index 4ddeee23..904d965e 100644 --- a/crates/console-timer/src/lib.rs +++ b/crates/console-timer/src/lib.rs @@ -34,7 +34,7 @@ The measurement ends when the timer object goes out of scope / is dropped. ```no_run use gloo_console_timer::ConsoleTimer; -use gloo_timers::Timeout; +use gloo_timers::callback::Timeout; // Start timing a new operation. let timer = ConsoleTimer::new("foo");