use std::time::Duration;
use rotor::{Machine, Scope, Response, EventSet, GenericScope, Time};
use rotor::void::{Void, unreachable};
pub struct Ticker<M: Timer> {
deadline: Time,
machine: M,
}
pub struct Interval<M: SimpleTimer>(Duration, M);
pub type IntervalFunc<C> = Ticker<Interval<Box<FnMut(&mut Scope<C>) + Send>>>;
pub trait Timer {
type Context;
fn timeout(self, scope: &mut Scope<Self::Context>) -> Self;
fn next_wakeup_time(&self, scheduled: Time,
scope: &mut Scope<Self::Context>)
-> Time;
}
pub trait SimpleTimer {
type Context;
fn timeout(self, scope: &mut Scope<Self::Context>) -> Self;
}
impl<T: Timer> Ticker<T> {
pub fn new(scope: &mut Scope<T::Context>, machine: T)
-> Response<Ticker<T>, Void>
{
let next = machine.next_wakeup_time(scope.now(), scope);
Response::ok(Ticker {
deadline: next,
machine: machine,
}).deadline(next)
}
}
impl<M: Timer> Machine for Ticker<M> {
type Context = M::Context;
type Seed = Void;
fn create(seed: Self::Seed, _scope: &mut Scope<Self::Context>)
-> Response<Self, Void>
{
unreachable(seed);
}
fn ready(self, _events: EventSet, _scope: &mut Scope<Self::Context>)
-> Response<Self, Self::Seed>
{
let deadline = self.deadline;
Response::ok(self).deadline(deadline)
}
fn spawned(self, _scope: &mut Scope<Self::Context>)
-> Response<Self, Self::Seed>
{
unreachable!();
}
fn timeout(self, scope: &mut Scope<Self::Context>)
-> Response<Self, Self::Seed>
{
let now = scope.now();
if now >= self.deadline {
let newm = self.machine.timeout(scope);
let next = newm.next_wakeup_time(self.deadline, scope);
Response::ok(Ticker {
deadline: next,
machine: newm,
}).deadline(next)
} else {
let deadline = self.deadline;
Response::ok(self).deadline(deadline)
}
}
fn wakeup(self, _scope: &mut Scope<Self::Context>)
-> Response<Self, Self::Seed>
{
let deadline = self.deadline;
Response::ok(self).deadline(deadline)
}
}
impl<T: SimpleTimer> Timer for Interval<T> {
type Context = T::Context;
fn timeout(self, scope: &mut Scope<Self::Context>) -> Self {
Interval(self.0, self.1.timeout(scope))
}
fn next_wakeup_time(&self, scheduled: Time,
scope: &mut Scope<Self::Context>)
-> Time
{
let goal = scheduled + self.0;
if scope.now() > goal {
return scope.now() + self.0;
} else {
return goal;
}
}
}
impl<C> SimpleTimer for Box<FnMut(&mut Scope<C>) + Send> {
type Context = C;
fn timeout(mut self, scope: &mut Scope<Self::Context>) -> Self {
self(scope);
self
}
}
pub fn interval_func<C, F>(scope: &mut Scope<C>, interval: Duration, fun: F)
-> Response<IntervalFunc<C>, Void>
where F: FnMut(&mut Scope<C>) + 'static + Send
{
Ticker::new(scope, Interval(interval, Box::new(fun)))
}