cancellable_timer/lib.rs
1#![deny(missing_docs)]
2
3//! Crate that implements a timer with a `sleep` method that can be cancelled.
4//!
5//! # Example
6//!
7//! ```
8//! use std::time::Duration;
9//! use cancellable_timer::*;
10//!
11//! fn main() {
12//! let (mut timer, canceller) = Timer::new2().unwrap();
13//!
14//! // Spawn a thread that will cancel the timer after 2s.
15//! std::thread::spawn(move || {
16//! std::thread::sleep(Duration::from_secs(2));
17//! println!("Stop the timer.");
18//! canceller.cancel();
19//! });
20//!
21//! println!("Wait 10s");
22//! let r = timer.sleep(Duration::from_secs(10));
23//! println!("Done: {:?}", r);
24//! }
25//! ```
26
27extern crate mio;
28
29use std::io;
30use std::time::Duration;
31
32use mio::*;
33
34/// A timer object that can be used to put the current thread to sleep
35/// or to start a callback after a given amount of time.
36pub struct Timer {
37 poll: Poll,
38 token: Token,
39 _registration: Registration,
40 events: Events,
41}
42
43/// An object that allows cancelling the associated [Timer](struct.Timer.html).
44#[derive(Clone)]
45pub struct Canceller {
46 set_readiness: SetReadiness,
47}
48
49impl Timer {
50 /// Create a [Timer](struct.Timer.html) and its associated [Canceller](struct.Canceller.html).
51 pub fn new2() -> io::Result<(Self, Canceller)> {
52 let poll = Poll::new()?;
53
54 let token = Token(0);
55 let (registration, set_readiness) = Registration::new2();
56 poll.register(®istration, token, Ready::readable(), PollOpt::edge())?;
57
58 Ok((
59 Timer {
60 poll,
61 token,
62 _registration: registration,
63 events: Events::with_capacity(4),
64 },
65 Canceller { set_readiness },
66 ))
67 }
68
69 /// Put the current thread to sleep until the given time has
70 /// elapsed or the timer is cancelled.
71 ///
72 /// Returns:
73 /// * Ok(()) if the given time has elapsed.
74 /// * An [Error](https://docs.rust-lang.org/std/io/struct.Error.html)
75 /// of kind [ErrorKind::Interrupted](https://docs.rust-lang.org/std/io/enum.ErrorKind.html)
76 /// if the timer has been cancelled.
77 /// * Some other [Error](https://docs.rust-lang.org/std/io/struct.Error.html)
78 /// if something goes wrong.
79 pub fn sleep(&mut self, duration: Duration) -> io::Result<()> {
80 self.poll.poll(&mut self.events, Some(duration))?;
81 for event in self.events.iter() {
82 if event.token() == self.token {
83 return Err(io::Error::new(
84 io::ErrorKind::Interrupted,
85 "timer cancelled",
86 ));
87 }
88 }
89 Ok(())
90 }
91
92 /// Run a callback on a new thread after a specified amount of time.
93 /// The callback is not run if `after` returns an error.
94 ///
95 /// Otherwise, the callback is given:
96 /// * Ok(()) if the amount of time has elapsed.
97 /// * An [Error](https://docs.rust-lang.org/std/io/struct.Error.html)
98 /// of kind [ErrorKind::Interrupted](https://docs.rust-lang.org/std/io/enum.ErrorKind.html)
99 /// if the timer has been cancelled.
100 /// * Some other [Error](https://docs.rust-lang.org/std/io/struct.Error.html)
101 /// if something goes wrong.
102 pub fn after<F>(wait: Duration, callback: F) -> io::Result<Canceller>
103 where
104 F: FnOnce(io::Result<()>),
105 F: Send + 'static,
106 {
107 let (mut timer, canceller) = Timer::new2()?;
108 std::thread::Builder::new().spawn(move || {
109 callback(timer.sleep(wait));
110 })?;
111 Ok(canceller)
112 }
113}
114
115impl Canceller {
116 /// Cancel the associated [Timer](struct.Timer.html).
117 pub fn cancel(&self) -> io::Result<()> {
118 self.set_readiness.set_readiness(Ready::readable())
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125 use std::thread;
126
127 #[test]
128 fn uninterrupted_sleep() {
129 let (mut timer, _) = Timer::new2().unwrap();
130 let r = timer.sleep(Duration::from_secs(1));
131 assert!(r.is_ok());
132 }
133
134 #[test]
135 fn cancel_before_sleep() {
136 let (mut timer, canceller) = Timer::new2().unwrap();
137 canceller.cancel().unwrap();
138 let r = timer.sleep(Duration::from_secs(1));
139 assert_eq!(r.unwrap_err().kind(), io::ErrorKind::Interrupted);
140 }
141
142 #[test]
143 fn cancel_during_sleep() {
144 let (mut timer, canceller) = Timer::new2().unwrap();
145 thread::spawn(move || {
146 thread::sleep(Duration::from_secs(2));
147 canceller.cancel().unwrap();
148 });
149 let r = timer.sleep(Duration::from_secs(10));
150 assert_eq!(r.unwrap_err().kind(), io::ErrorKind::Interrupted);
151 }
152}