#![deny(missing_docs)]
extern crate mio;
use std::io;
use std::time::Duration;
use mio::*;
pub struct Timer {
poll: Poll,
token: Token,
_registration: Registration,
events: Events,
}
#[derive(Clone)]
pub struct Canceller {
set_readiness: SetReadiness,
}
impl Timer {
pub fn new2() -> io::Result<(Self, Canceller)> {
let poll = Poll::new()?;
let token = Token(0);
let (registration, set_readiness) = Registration::new2();
poll.register(®istration, token, Ready::readable(), PollOpt::edge())?;
Ok((
Timer {
poll,
token,
_registration: registration,
events: Events::with_capacity(4),
},
Canceller { set_readiness },
))
}
pub fn sleep(&mut self, duration: Duration) -> io::Result<()> {
self.poll.poll(&mut self.events, Some(duration))?;
for event in self.events.iter() {
if event.token() == self.token {
return Err(io::Error::new(
io::ErrorKind::Interrupted,
"timer cancelled",
));
}
}
Ok(())
}
pub fn after<F>(wait: Duration, callback: F) -> io::Result<Canceller>
where
F: FnOnce(io::Result<()>),
F: Send + 'static,
{
let (mut timer, canceller) = Timer::new2()?;
std::thread::Builder::new().spawn(move || {
callback(timer.sleep(wait));
})?;
Ok(canceller)
}
}
impl Canceller {
pub fn cancel(&self) -> io::Result<()> {
self.set_readiness.set_readiness(Ready::readable())
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::thread;
#[test]
fn uninterrupted_sleep() {
let (mut timer, _) = Timer::new2().unwrap();
let r = timer.sleep(Duration::from_secs(1));
assert!(r.is_ok());
}
#[test]
fn cancel_before_sleep() {
let (mut timer, canceller) = Timer::new2().unwrap();
canceller.cancel().unwrap();
let r = timer.sleep(Duration::from_secs(1));
assert_eq!(r.unwrap_err().kind(), io::ErrorKind::Interrupted);
}
#[test]
fn cancel_during_sleep() {
let (mut timer, canceller) = Timer::new2().unwrap();
thread::spawn(move || {
thread::sleep(Duration::from_secs(2));
canceller.cancel().unwrap();
});
let r = timer.sleep(Duration::from_secs(10));
assert_eq!(r.unwrap_err().kind(), io::ErrorKind::Interrupted);
}
}