Skip to content

Commit a4296c9

Browse files
authored
Improve timer functionality (#87)
1 parent e361484 commit a4296c9

File tree

1 file changed

+117
-44
lines changed

1 file changed

+117
-44
lines changed

src/lib.rs

Lines changed: 117 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,12 @@ fn duration_max() -> Duration {
9696
Duration::new(std::u64::MAX, 1_000_000_000 - 1)
9797
}
9898

99+
fn instant_max() -> Instant {
100+
// In order to ensure this point in time is never reached, it
101+
// is put 30 years into the future.
102+
Instant::now() + Duration::from_secs(86400 * 365 * 30)
103+
}
104+
99105
/// A future or stream that emits timed events.
100106
///
101107
/// Timers are futures that output a single [`Instant`] when they fire.
@@ -139,13 +145,57 @@ pub struct Timer {
139145
id_and_waker: Option<(usize, Waker)>,
140146

141147
/// The next instant at which this timer fires.
142-
when: Instant,
148+
///
149+
/// If this timer is a blank timer, this value is None. If the timer
150+
/// must be set, this value contains the next instant at which the
151+
/// timer must fire.
152+
when: Option<Instant>,
143153

144154
/// The period.
145155
period: Duration,
146156
}
147157

148158
impl Timer {
159+
/// Creates a timer that will never fire.
160+
///
161+
/// # Examples
162+
///
163+
/// This function may also be useful for creating a function with an optional timeout.
164+
///
165+
/// ```
166+
/// # futures_lite::future::block_on(async {
167+
/// use async_io::Timer;
168+
/// use futures_lite::prelude::*;
169+
/// use std::time::Duration;
170+
///
171+
/// async fn run_with_timeout(timeout: Option<Duration>) {
172+
/// let timer = timeout
173+
/// .map(|timeout| Timer::after(timeout))
174+
/// .unwrap_or_else(Timer::never);
175+
///
176+
/// run_lengthy_operation().or(timer).await;
177+
/// }
178+
/// # // Note that since a Timer as a Future returns an Instant,
179+
/// # // this function needs to return an Instant to be used
180+
/// # // in "or".
181+
/// # async fn run_lengthy_operation() -> std::time::Instant {
182+
/// # std::time::Instant::now()
183+
/// # }
184+
///
185+
/// // Times out after 5 seconds.
186+
/// run_with_timeout(Some(Duration::from_secs(5))).await;
187+
/// // Does not time out.
188+
/// run_with_timeout(None).await;
189+
/// # });
190+
/// ```
191+
pub fn never() -> Timer {
192+
Timer {
193+
id_and_waker: None,
194+
when: None,
195+
period: duration_max(),
196+
}
197+
}
198+
149199
/// Creates a timer that emits an event once after the given duration of time.
150200
///
151201
/// # Examples
@@ -159,7 +209,11 @@ impl Timer {
159209
/// # });
160210
/// ```
161211
pub fn after(duration: Duration) -> Timer {
162-
Timer::at(Instant::now() + duration)
212+
Timer::at(
213+
Instant::now()
214+
.checked_add(duration)
215+
.unwrap_or_else(instant_max),
216+
)
163217
}
164218

165219
/// Creates a timer that emits an event once at the given time instant.
@@ -196,7 +250,12 @@ impl Timer {
196250
/// # });
197251
/// ```
198252
pub fn interval(period: Duration) -> Timer {
199-
Timer::interval_at(Instant::now() + period, period)
253+
Timer::interval_at(
254+
Instant::now()
255+
.checked_add(period)
256+
.unwrap_or_else(instant_max),
257+
period,
258+
)
200259
}
201260

202261
/// Creates a timer that emits events periodically, starting at `start`.
@@ -217,7 +276,7 @@ impl Timer {
217276
pub fn interval_at(start: Instant, period: Duration) -> Timer {
218277
Timer {
219278
id_and_waker: None,
220-
when: start,
279+
when: Some(start),
221280
period,
222281
}
223282
}
@@ -240,7 +299,11 @@ impl Timer {
240299
/// # });
241300
/// ```
242301
pub fn set_after(&mut self, duration: Duration) {
243-
self.set_at(Instant::now() + duration);
302+
self.set_at(
303+
Instant::now()
304+
.checked_add(duration)
305+
.unwrap_or_else(instant_max),
306+
);
244307
}
245308

246309
/// Sets the timer to emit an event once at the given time instant.
@@ -264,17 +327,17 @@ impl Timer {
264327
/// # });
265328
/// ```
266329
pub fn set_at(&mut self, instant: Instant) {
267-
if let Some((id, _)) = self.id_and_waker.as_ref() {
330+
if let (Some(when), Some((id, _))) = (self.when, self.id_and_waker.as_ref()) {
268331
// Deregister the timer from the reactor.
269-
Reactor::get().remove_timer(self.when, *id);
332+
Reactor::get().remove_timer(when, *id);
270333
}
271334

272335
// Update the timeout.
273-
self.when = instant;
336+
self.when = Some(instant);
274337

275338
if let Some((id, waker)) = self.id_and_waker.as_mut() {
276339
// Re-register the timer with the new timeout.
277-
*id = Reactor::get().insert_timer(self.when, waker);
340+
*id = Reactor::get().insert_timer(instant, waker);
278341
}
279342
}
280343

@@ -299,7 +362,12 @@ impl Timer {
299362
/// # });
300363
/// ```
301364
pub fn set_interval(&mut self, period: Duration) {
302-
self.set_interval_at(Instant::now() + period, period);
365+
self.set_interval_at(
366+
Instant::now()
367+
.checked_add(period)
368+
.unwrap_or_else(instant_max),
369+
period,
370+
);
303371
}
304372

305373
/// Sets the timer to emit events periodically, starting at `start`.
@@ -324,26 +392,26 @@ impl Timer {
324392
/// # });
325393
/// ```
326394
pub fn set_interval_at(&mut self, start: Instant, period: Duration) {
327-
if let Some((id, _)) = self.id_and_waker.as_ref() {
395+
if let (Some(when), Some((id, _))) = (self.when, self.id_and_waker.as_ref()) {
328396
// Deregister the timer from the reactor.
329-
Reactor::get().remove_timer(self.when, *id);
397+
Reactor::get().remove_timer(when, *id);
330398
}
331399

332-
self.when = start;
400+
self.when = Some(start);
333401
self.period = period;
334402

335403
if let Some((id, waker)) = self.id_and_waker.as_mut() {
336404
// Re-register the timer with the new timeout.
337-
*id = Reactor::get().insert_timer(self.when, waker);
405+
*id = Reactor::get().insert_timer(start, waker);
338406
}
339407
}
340408
}
341409

342410
impl Drop for Timer {
343411
fn drop(&mut self) {
344-
if let Some((id, _)) = self.id_and_waker.take() {
412+
if let (Some(when), Some((id, _))) = (self.when, self.id_and_waker.take()) {
345413
// Deregister the timer from the reactor.
346-
Reactor::get().remove_timer(self.when, id);
414+
Reactor::get().remove_timer(when, id);
347415
}
348416
}
349417
}
@@ -363,39 +431,44 @@ impl Future for Timer {
363431
impl Stream for Timer {
364432
type Item = Instant;
365433

366-
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
367-
// Check if the timer has already fired.
368-
if Instant::now() >= self.when {
369-
if let Some((id, _)) = self.id_and_waker.take() {
370-
// Deregister the timer from the reactor.
371-
Reactor::get().remove_timer(self.when, id);
372-
}
373-
let when = self.when;
374-
if let Some(next) = when.checked_add(self.period) {
375-
self.when = next;
376-
// Register the timer in the reactor.
377-
let id = Reactor::get().insert_timer(self.when, cx.waker());
378-
self.id_and_waker = Some((id, cx.waker().clone()));
379-
}
380-
return Poll::Ready(Some(when));
381-
} else {
382-
match &self.id_and_waker {
383-
None => {
434+
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
435+
let this = self.get_mut();
436+
437+
if let Some(ref mut when) = this.when {
438+
// Check if the timer has already fired.
439+
if Instant::now() >= *when {
440+
if let Some((id, _)) = this.id_and_waker.take() {
441+
// Deregister the timer from the reactor.
442+
Reactor::get().remove_timer(*when, id);
443+
}
444+
let result_time = *when;
445+
if let Some(next) = (*when).checked_add(this.period) {
446+
*when = next;
384447
// Register the timer in the reactor.
385-
let id = Reactor::get().insert_timer(self.when, cx.waker());
386-
self.id_and_waker = Some((id, cx.waker().clone()));
448+
let id = Reactor::get().insert_timer(next, cx.waker());
449+
this.id_and_waker = Some((id, cx.waker().clone()));
387450
}
388-
Some((id, w)) if !w.will_wake(cx.waker()) => {
389-
// Deregister the timer from the reactor to remove the old waker.
390-
Reactor::get().remove_timer(self.when, *id);
391-
392-
// Register the timer in the reactor with the new waker.
393-
let id = Reactor::get().insert_timer(self.when, cx.waker());
394-
self.id_and_waker = Some((id, cx.waker().clone()));
451+
return Poll::Ready(Some(result_time));
452+
} else {
453+
match &this.id_and_waker {
454+
None => {
455+
// Register the timer in the reactor.
456+
let id = Reactor::get().insert_timer(*when, cx.waker());
457+
this.id_and_waker = Some((id, cx.waker().clone()));
458+
}
459+
Some((id, w)) if !w.will_wake(cx.waker()) => {
460+
// Deregister the timer from the reactor to remove the old waker.
461+
Reactor::get().remove_timer(*when, *id);
462+
463+
// Register the timer in the reactor with the new waker.
464+
let id = Reactor::get().insert_timer(*when, cx.waker());
465+
this.id_and_waker = Some((id, cx.waker().clone()));
466+
}
467+
Some(_) => {}
395468
}
396-
Some(_) => {}
397469
}
398470
}
471+
399472
Poll::Pending
400473
}
401474
}

0 commit comments

Comments
 (0)