use std::cell::RefCell;
use std::io;
use std::rc::Rc;
use std::time::Duration;
use mio::{Events, Poll};
use list::SourceList;
use sources::{EventSource, Idle, Source};
#[derive(Clone)]
pub struct LoopHandle {
poll: Rc<Poll>,
list: Rc<RefCell<SourceList>>,
idles: Rc<RefCell<Vec<Rc<RefCell<Option<Box<FnMut()>>>>>>>,
}
impl LoopHandle {
pub fn insert_source<E: EventSource, F: FnMut(E::Event) + 'static>(
&self,
source: E,
callback: F,
) -> io::Result<Source<E>> {
let dispatcher = source.make_dispatcher(callback);
let token = self.list.borrow_mut().add_source(dispatcher);
let interest = source.interest();
let opt = source.pollopts();
self.poll.register(&source, token, interest, opt)?;
Ok(Source {
source,
poll: self.poll.clone(),
list: self.list.clone(),
token,
})
}
pub fn insert_idle<F: FnMut() + 'static>(&self, callback: F) -> Idle {
let callback = Rc::new(RefCell::new(Some(Box::new(callback) as Box<FnMut()>)));
self.idles.borrow_mut().push(callback.clone());
Idle { callback }
}
}
pub struct EventLoop {
handle: LoopHandle,
events_buffer: Events,
}
impl EventLoop {
pub fn new() -> io::Result<EventLoop> {
Ok(EventLoop {
handle: LoopHandle {
poll: Rc::new(Poll::new()?),
list: Rc::new(RefCell::new(SourceList::new())),
idles: Rc::new(RefCell::new(Vec::new())),
},
events_buffer: Events::with_capacity(32),
})
}
pub fn handle(&self) -> LoopHandle {
self.handle.clone()
}
fn dispatch_events(&mut self, timeout: Option<Duration>) -> io::Result<()> {
self.events_buffer.clear();
self.handle.poll.poll(&mut self.events_buffer, timeout)?;
loop {
if self.events_buffer.is_empty() {
break;
}
for event in &self.events_buffer {
if let Some(dispatcher) = self.handle.list.borrow().get_dispatcher(event.token()) {
dispatcher.borrow_mut().ready(event.readiness());
}
}
self.events_buffer.clear();
self.handle
.poll
.poll(&mut self.events_buffer, Some(Duration::from_millis(0)))?;
}
Ok(())
}
fn dispatch_idles(&mut self) {
let idles = ::std::mem::replace(&mut *self.handle.idles.borrow_mut(), Vec::new());
for idle in idles {
if let Some(ref mut callback) = *idle.borrow_mut() {
callback();
}
}
}
pub fn dispatch(&mut self, timeout: Option<Duration>) -> io::Result<()> {
self.dispatch_events(timeout)?;
self.dispatch_idles();
Ok(())
}
}
#[cfg(test)]
mod tests {
use std::cell::Cell;
use std::rc::Rc;
use std::time::Duration;
use super::EventLoop;
#[test]
fn dispatch_idle() {
let mut event_loop = EventLoop::new().unwrap();
let dispatched = Rc::new(Cell::new(false));
let impl_dispatched = dispatched.clone();
event_loop
.handle()
.insert_idle(move || impl_dispatched.set(true));
event_loop.dispatch(Some(Duration::from_millis(0))).unwrap();
assert!(dispatched.get());
}
#[test]
fn cancel_idle() {
let mut event_loop = EventLoop::new().unwrap();
let dispatched = Rc::new(Cell::new(false));
let impl_dispatched = dispatched.clone();
let idle = event_loop
.handle()
.insert_idle(move || impl_dispatched.set(true));
idle.cancel();
event_loop.dispatch(Some(Duration::from_millis(0))).unwrap();
assert!(!dispatched.get());
}
}