Skip to content

Commit b3316ef

Browse files
authored
Merge pull request #55 from fitzgen/timers-fixups
Little timers fixups
2 parents 533e673 + 43cb377 commit b3316ef

File tree

6 files changed

+445
-442
lines changed

6 files changed

+445
-442
lines changed

crates/console-timer/Cargo.toml

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ authors = ["Rust and WebAssembly Working Group"]
55
edition = "2018"
66

77
[dependencies.web-sys]
8-
version = "0.3.14"
8+
version = "0.3.17"
99
features = [
1010
"console",
1111
]
1212

1313
[dev-dependencies]
14-
wasm-bindgen-test = "0.2.37"
15-
gloo-timers = { version = "0.1.0", path = "../timers" }
14+
wasm-bindgen-test = "0.2.40"
15+
gloo-timers = { version = "0.1.0", path = "../timers" }

crates/timers/Cargo.toml

+5-5
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,20 @@ authors = ["Rust and WebAssembly Working Group"]
55
edition = "2018"
66

77
[dependencies]
8-
wasm-bindgen = "0.2.37"
9-
js-sys = "0.3.14"
8+
wasm-bindgen = "0.2.40"
9+
js-sys = "0.3.17"
1010

1111
[dependencies.futures_rs]
1212
package = "futures"
1313
version = "0.1.25"
1414
optional = true
1515

1616
[dependencies.wasm-bindgen-futures]
17-
version = "0.3.14"
17+
version = "0.3.17"
1818
optional = true
1919

2020
[dependencies.web-sys]
21-
version = "0.3.14"
21+
version = "0.3.17"
2222
features = [
2323
"Window",
2424
]
@@ -29,4 +29,4 @@ futures = ["futures_rs", "wasm-bindgen-futures"]
2929

3030

3131
[dev-dependencies]
32-
wasm-bindgen-test = "0.2.37"
32+
wasm-bindgen-test = "0.2.40"

crates/timers/src/callback.rs

+219
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
//! Callback-style timer APIs.
2+
3+
use super::window;
4+
use std::fmt;
5+
use wasm_bindgen::prelude::*;
6+
use wasm_bindgen::JsCast;
7+
8+
/// A scheduled timeout.
9+
///
10+
/// See `Timeout::new` for scheduling new timeouts.
11+
///
12+
/// Once scheduled, you can either `cancel` so that it doesn't run or `forget`
13+
/// it so that it is un-cancel-able.
14+
#[must_use = "timeouts cancel on drop; either call `forget` or `drop` explicitly"]
15+
pub struct Timeout {
16+
id: Option<i32>,
17+
closure: Option<Closure<FnMut()>>,
18+
}
19+
20+
impl Drop for Timeout {
21+
fn drop(&mut self) {
22+
if let Some(id) = self.id {
23+
window().clear_timeout_with_handle(id);
24+
}
25+
}
26+
}
27+
28+
impl fmt::Debug for Timeout {
29+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
30+
f.debug_struct("Timeout").field("id", &self.id).finish()
31+
}
32+
}
33+
34+
impl Timeout {
35+
/// Schedule a timeout to invoke `callback` in `millis` milliseconds from
36+
/// now.
37+
///
38+
/// # Example
39+
///
40+
/// ```no_run
41+
/// use gloo_timers::callback::Timeout;
42+
///
43+
/// let timeout = Timeout::new(1_000, move || {
44+
/// // Do something...
45+
/// });
46+
/// ```
47+
pub fn new<F>(millis: u32, callback: F) -> Timeout
48+
where
49+
F: 'static + FnOnce(),
50+
{
51+
let closure = Closure::once(callback);
52+
53+
let id = window()
54+
.set_timeout_with_callback_and_timeout_and_arguments_0(
55+
closure.as_ref().unchecked_ref::<js_sys::Function>(),
56+
millis as i32,
57+
)
58+
.unwrap_throw();
59+
60+
Timeout {
61+
id: Some(id),
62+
closure: Some(closure),
63+
}
64+
}
65+
66+
/// Make this timeout uncancel-able.
67+
///
68+
/// Returns the identifier returned by the original `setTimeout` call, and
69+
/// therefore you can still cancel the timeout by calling `clearTimeout`
70+
/// directly (perhaps via `web_sys::clear_timeout_with_handle`).
71+
///
72+
/// # Example
73+
///
74+
/// ```no_run
75+
/// use gloo_timers::callback::Timeout;
76+
///
77+
/// // We definitely want to do stuff, and aren't going to ever cancel this
78+
/// // timeout.
79+
/// Timeout::new(1_000, || {
80+
/// // Do stuff...
81+
/// }).forget();
82+
/// ```
83+
pub fn forget(mut self) -> i32 {
84+
let id = self.id.take().unwrap_throw();
85+
self.closure.take().unwrap_throw().forget();
86+
id
87+
}
88+
89+
/// Cancel this timeout so that the callback is not invoked after the time
90+
/// is up.
91+
///
92+
/// The scheduled callback is returned.
93+
///
94+
/// # Example
95+
///
96+
/// ```no_run
97+
/// use gloo_timers::callback::Timeout;
98+
///
99+
/// let timeout = Timeout::new(1_000, || {
100+
/// // Do stuff...
101+
/// });
102+
///
103+
/// // If actually we didn't want to set a timer, then cancel it.
104+
/// if nevermind() {
105+
/// timeout.cancel();
106+
/// }
107+
/// # fn nevermind() -> bool { true }
108+
/// ```
109+
pub fn cancel(mut self) -> Closure<FnMut()> {
110+
self.closure.take().unwrap_throw()
111+
}
112+
}
113+
/// A scheduled interval.
114+
///
115+
/// See `Interval::new` for scheduling new intervals.
116+
///
117+
/// Once scheduled, you can either `cancel` so that it ceases to fire or `forget`
118+
/// it so that it is un-cancel-able.
119+
#[must_use = "intervals cancel on drop; either call `forget` or `drop` explicitly"]
120+
pub struct Interval {
121+
id: Option<i32>,
122+
closure: Option<Closure<FnMut()>>,
123+
}
124+
125+
impl Drop for Interval {
126+
fn drop(&mut self) {
127+
if let Some(id) = self.id {
128+
window().clear_interval_with_handle(id);
129+
}
130+
}
131+
}
132+
133+
impl fmt::Debug for Interval {
134+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
135+
f.debug_struct("Interval").field("id", &self.id).finish()
136+
}
137+
}
138+
139+
impl Interval {
140+
/// Schedule an interval to invoke `callback` every `millis` milliseconds.
141+
///
142+
/// # Example
143+
///
144+
/// ```no_run
145+
/// use gloo_timers::callback::Interval;
146+
///
147+
/// let interval = Interval::new(1_000, move || {
148+
/// // Do something...
149+
/// });
150+
/// ```
151+
pub fn new<F>(millis: u32, callback: F) -> Interval
152+
where
153+
F: 'static + FnMut(),
154+
{
155+
let mut callback = Some(callback);
156+
let closure = Closure::wrap(Box::new(move || {
157+
let mut callback = callback.take().unwrap_throw();
158+
callback();
159+
}) as Box<FnMut()>);
160+
161+
let id = window()
162+
.set_interval_with_callback_and_timeout_and_arguments_0(
163+
closure.as_ref().unchecked_ref::<js_sys::Function>(),
164+
millis as i32,
165+
)
166+
.unwrap_throw();
167+
168+
Interval {
169+
id: Some(id),
170+
closure: Some(closure),
171+
}
172+
}
173+
174+
/// Make this interval uncancel-able.
175+
///
176+
/// Returns the identifier returned by the original `setInterval` call, and
177+
/// therefore you can still cancel the interval by calling `clearInterval`
178+
/// directly (perhaps via `web_sys::clear_interval_with_handle`).
179+
///
180+
/// # Example
181+
///
182+
/// ```no_run
183+
/// use gloo_timers::callback::Interval;
184+
///
185+
/// // We want to do stuff every second, indefinitely.
186+
/// Interval::new(1_000, || {
187+
/// // Do stuff...
188+
/// }).forget();
189+
/// ```
190+
pub fn forget(mut self) -> i32 {
191+
let id = self.id.take().unwrap_throw();
192+
self.closure.take().unwrap_throw().forget();
193+
id
194+
}
195+
196+
/// Cancel this interval so that the callback is no longer periodically
197+
/// invoked.
198+
///
199+
/// The scheduled callback is returned.
200+
///
201+
/// # Example
202+
///
203+
/// ```no_run
204+
/// use gloo_timers::callback::Interval;
205+
///
206+
/// let interval = Interval::new(1_000, || {
207+
/// // Do stuff...
208+
/// });
209+
///
210+
/// // If we don't want this interval to run anymore, then cancel it.
211+
/// if nevermind() {
212+
/// interval.cancel();
213+
/// }
214+
/// # fn nevermind() -> bool { true }
215+
/// ```
216+
pub fn cancel(mut self) -> Closure<FnMut()> {
217+
self.closure.take().unwrap_throw()
218+
}
219+
}

0 commit comments

Comments
 (0)