use std::io;
use std::thread;
use std::marker::PhantomData;
use std::time::Duration;
use error::{READY, ECANCELED, stopped};
use io_service::{IoObject, IoService, Handler, AsyncResult, TimerActor};
use clock::{Clock, SteadyClock, SystemClock, Expiry};
pub struct WaitableTimer<C: Clock> {
act: TimerActor,
_marker: PhantomData<C>,
}
impl<C: Clock> WaitableTimer<C> {
pub fn new(io: &IoService) -> WaitableTimer<C> {
WaitableTimer {
act: TimerActor::new(io),
_marker: PhantomData,
}
}
pub fn async_wait_at<F>(&self, endpoint: C::TimePoint, handler: F) -> F::Output
where F: Handler<()>
{
async_wait(&self.act, C::expires_at(endpoint), handler)
}
pub fn async_wait_for<F>(&self, duration: C::Duration, handler: F) -> F::Output
where F: Handler<()>
{
async_wait(&self.act, C::expires_from(duration), handler)
}
pub fn cancel(&self) {
if let Some(callback) = self.act.unset_wait() {
self.io_service().dispatch(move |io| callback(io, ECANCELED));
}
}
pub fn wait_at(&self, endpoint: C::TimePoint) -> io::Result<()> {
sleep_for(self.io_service(), C::elapsed_at(endpoint))
}
pub fn wait_for(&self, duration: C::Duration) -> io::Result<()> {
sleep_for(self.io_service(), C::elapsed_from(duration))
}
}
unsafe impl<C: Clock> IoObject for WaitableTimer<C> {
fn io_service(&self) -> &IoService {
self.act.io_service()
}
}
fn async_wait<F>(act: &TimerActor, expiry: Expiry, handler: F) -> F::Output
where F: Handler<()>
{
let out = handler.async_result();
act.set_wait(expiry, Box::new(move |io: *const IoService, ec| {
let io = unsafe { &*io };
match ec {
READY => handler.callback(io, Ok(())),
ec => handler.callback(io, Err(ec.into())),
}
}));
out.get(act.io_service())
}
fn sleep_for(io: &IoService, duration: Duration) -> io::Result<()> {
if !io.stopped() {
thread::sleep(duration);
Ok(())
} else {
Err(stopped())
}
}
pub type SteadyTimer = WaitableTimer<SteadyClock>;
pub type SystemTimer = WaitableTimer<SystemClock>;