use std::cell::RefCell;
use std::io;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use std::time::Duration;
use mio::{Evented, Poll, PollOpt, Ready, Token};
use mio_extras::timer as mio_timer;
pub use self::mio_timer::Timeout;
use {EventDispatcher, EventSource};
pub struct Timer<T> {
inner: Arc<Mutex<mio_timer::Timer<T>>>,
}
impl<T> Timer<T> {
pub fn new() -> Timer<T> {
Timer {
inner: Arc::new(Mutex::new(mio_timer::Builder::default().build())),
}
}
pub fn with_resolution(resolution: Duration) -> Timer<T> {
Timer {
inner: Arc::new(Mutex::new(
mio_timer::Builder::default()
.tick_duration(resolution)
.build(),
)),
}
}
pub fn handle(&self) -> TimerHandle<T> {
TimerHandle {
inner: self.inner.clone(),
}
}
}
pub struct TimerHandle<T> {
inner: Arc<Mutex<mio_timer::Timer<T>>>,
}
impl<T> Clone for TimerHandle<T> {
fn clone(&self) -> TimerHandle<T> {
TimerHandle {
inner: self.inner.clone(),
}
}
}
impl<T> TimerHandle<T> {
pub fn add_timeout(&self, delay_from_now: Duration, data: T) -> Timeout {
self.inner.lock().unwrap().set_timeout(delay_from_now, data)
}
pub fn cancel_timeout(&self, timeout: &Timeout) -> Option<T> {
self.inner.lock().unwrap().cancel_timeout(timeout)
}
}
impl<T> Evented for Timer<T> {
fn register(
&self,
poll: &Poll,
token: Token,
interest: Ready,
opts: PollOpt,
) -> io::Result<()> {
self.inner
.lock()
.unwrap()
.register(poll, token, interest, opts)
}
fn reregister(
&self,
poll: &Poll,
token: Token,
interest: Ready,
opts: PollOpt,
) -> io::Result<()> {
self.inner
.lock()
.unwrap()
.reregister(poll, token, interest, opts)
}
fn deregister(&self, poll: &Poll) -> io::Result<()> {
self.inner.lock().unwrap().deregister(poll)
}
}
impl<T: 'static> EventSource for Timer<T> {
type Event = (T, TimerHandle<T>);
fn interest(&self) -> Ready {
Ready::readable()
}
fn pollopts(&self) -> PollOpt {
PollOpt::edge()
}
fn make_dispatcher<Data: 'static, F: FnMut((T, TimerHandle<T>), &mut Data) + 'static>(
&self,
callback: F,
) -> Rc<RefCell<EventDispatcher<Data>>> {
Rc::new(RefCell::new(Dispatcher {
_data: ::std::marker::PhantomData,
timer: self.inner.clone(),
callback,
}))
}
}
struct Dispatcher<Data, T, F: FnMut((T, TimerHandle<T>), &mut Data)> {
_data: ::std::marker::PhantomData<fn(&mut Data)>,
timer: Arc<Mutex<mio_timer::Timer<T>>>,
callback: F,
}
impl<Data, T, F: FnMut((T, TimerHandle<T>), &mut Data)> EventDispatcher<Data>
for Dispatcher<Data, T, F>
{
fn ready(&mut self, _: Ready, data: &mut Data) {
let handle = TimerHandle {
inner: self.timer.clone(),
};
loop {
let opt_evt = self.timer.lock().unwrap().poll();
match opt_evt {
Some(val) => (self.callback)((val, handle.clone()), data),
None => break,
}
}
}
}
#[cfg(test)]
mod tests {
use std::io;
use std::time::Duration;
use super::*;
#[test]
fn single_timer() {
let mut event_loop = ::EventLoop::new().unwrap();
let evl_handle = event_loop.handle();
let mut fired = false;
let timer = evl_handle
.insert_source(Timer::<()>::new(), move |((), _), f| {
*f = true;
})
.map_err(Into::<io::Error>::into)
.unwrap();
timer.handle().add_timeout(Duration::from_millis(300), ());
event_loop
.dispatch(Some(::std::time::Duration::from_millis(100)), &mut fired)
.unwrap();
assert!(!fired);
event_loop
.dispatch(Some(::std::time::Duration::from_millis(300)), &mut fired)
.unwrap();
assert!(fired);
}
#[test]
fn multi_timout_order() {
let mut event_loop = ::EventLoop::new().unwrap();
let evl_handle = event_loop.handle();
let mut fired = Vec::new();
let timer = evl_handle
.insert_source(Timer::new(), |(val, _), fired: &mut Vec<u32>| {
fired.push(val);
})
.map_err(Into::<io::Error>::into)
.unwrap();
timer.handle().add_timeout(Duration::from_millis(300), 1);
timer.handle().add_timeout(Duration::from_millis(100), 2);
timer.handle().add_timeout(Duration::from_millis(600), 3);
event_loop
.dispatch(Some(::std::time::Duration::from_millis(200)), &mut fired)
.unwrap();
assert_eq!(&fired, &[2]);
event_loop
.dispatch(Some(::std::time::Duration::from_millis(300)), &mut fired)
.unwrap();
assert_eq!(&fired, &[2, 1]);
event_loop
.dispatch(Some(::std::time::Duration::from_millis(400)), &mut fired)
.unwrap();
assert_eq!(&fired, &[2, 1, 3]);
}
#[test]
fn timer_cancel() {
let mut event_loop = ::EventLoop::new().unwrap();
let evl_handle = event_loop.handle();
let mut fired = Vec::new();
let timer = evl_handle
.insert_source(Timer::new(), |(val, _), fired: &mut Vec<u32>| {
fired.push(val)
})
.map_err(Into::<io::Error>::into)
.unwrap();
let timeout1 = timer.handle().add_timeout(Duration::from_millis(300), 1);
let timeout2 = timer.handle().add_timeout(Duration::from_millis(100), 2);
let timeout3 = timer.handle().add_timeout(Duration::from_millis(600), 3);
event_loop
.dispatch(Some(::std::time::Duration::from_millis(200)), &mut fired)
.unwrap();
assert_eq!(&fired, &[2]);
assert_eq!(timer.handle().cancel_timeout(&timeout2), None);
assert_eq!(timer.handle().cancel_timeout(&timeout1), Some(1));
event_loop
.dispatch(Some(::std::time::Duration::from_millis(300)), &mut fired)
.unwrap();
assert_eq!(&fired, &[2]);
assert_eq!(timer.handle().cancel_timeout(&timeout3), Some(3));
event_loop
.dispatch(Some(::std::time::Duration::from_millis(600)), &mut fired)
.unwrap();
assert_eq!(&fired, &[2]);
}
}