use std::cmp::{self, Ord};
use std::collections::BinaryHeap;
use std::time::{Duration, Instant};
use script_traits::{TimerEvent, TimerEventRequest, TimerSchedulerMsg};
pub struct TimerScheduler(BinaryHeap<ScheduledEvent>);
struct ScheduledEvent {
request: TimerEventRequest,
for_time: Instant,
}
impl Ord for ScheduledEvent {
fn cmp(&self, other: &ScheduledEvent) -> cmp::Ordering {
self.for_time.cmp(&other.for_time).reverse()
}
}
impl PartialOrd for ScheduledEvent {
fn partial_cmp(&self, other: &ScheduledEvent) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Eq for ScheduledEvent {}
impl PartialEq for ScheduledEvent {
fn eq(&self, other: &ScheduledEvent) -> bool {
std::ptr::eq(self, other)
}
}
impl TimerScheduler {
pub fn new() -> Self {
TimerScheduler(BinaryHeap::<ScheduledEvent>::new())
}
pub fn check_timers(&mut self) -> Option<Duration> {
let now = Instant::now();
loop {
match self.0.peek() {
Some(event) if event.for_time <= now => {
let TimerEventRequest(ref sender, source, id, _) = event.request;
let _ = sender.send(TimerEvent(source, id));
},
None => return None,
Some(event) => return Some(event.for_time - now),
}
self.0.pop();
}
}
pub fn handle_timer_request(&mut self, request: TimerSchedulerMsg) {
let TimerEventRequest(_, _, _, delay) = request.0;
let event = ScheduledEvent {
request: request.0,
for_time: Instant::now() + delay,
};
self.0.push(event);
}
}