use std::cmp::Ordering;
use std::collections::BinaryHeap;
use std::rc::Weak;
use std::time::{Duration, Instant};
use timely::scheduling::Activator;
#[derive(Default)]
pub struct Scheduler {
activator_queue: BinaryHeap<TimedActivator>,
}
impl Scheduler {
pub fn new() -> Self {
Scheduler {
activator_queue: BinaryHeap::new(),
}
}
pub fn has_pending(&self) -> bool {
if let Some(ref timed_activator) = self.activator_queue.peek() {
timed_activator.is_ready()
} else {
false
}
}
pub fn until_next(&self) -> Option<Duration> {
if let Some(ref timed_activator) = self.activator_queue.peek() {
Some(timed_activator.until_ready())
} else {
None
}
}
pub fn schedule_at(&mut self, at: Instant, activator: Weak<Activator>) {
self.activator_queue.push(TimedActivator {
at,
activator,
event: None,
});
}
pub fn schedule_now(&mut self, activator: Weak<Activator>) {
self.schedule_at(Instant::now(), activator);
}
pub fn schedule_after(&mut self, after: Duration, activator: Weak<Activator>) {
self.schedule_at(Instant::now() + after, activator);
}
pub fn event_at(&mut self, at: Instant, event: Event) {
self.activator_queue.push(TimedActivator {
at,
activator: Weak::new(),
event: Some(event),
});
}
pub fn event_after(&mut self, after: Duration, event: Event) {
self.event_at(Instant::now() + after, event);
}
}
impl Iterator for Scheduler {
type Item = TimedActivator;
fn next(&mut self) -> Option<TimedActivator> {
if self.has_pending() {
Some(self.activator_queue.pop().unwrap())
} else {
None
}
}
}
#[derive(PartialEq, Eq, Debug)]
pub enum Event {
Tick,
}
pub struct TimedActivator {
at: Instant,
activator: Weak<Activator>,
event: Option<Event>,
}
impl TimedActivator {
fn is_ready(&self) -> bool {
Instant::now() >= self.at
}
fn until_ready(&self) -> Duration {
let now = Instant::now();
if self.at > now {
self.at.duration_since(now)
} else {
Duration::from_millis(0)
}
}
pub fn schedule(self) -> Option<Event> {
if let Some(activator) = self.activator.upgrade() {
activator.activate();
}
self.event
}
}
impl Ord for TimedActivator {
fn cmp(&self, other: &TimedActivator) -> Ordering {
other.at.cmp(&self.at)
}
}
impl PartialOrd for TimedActivator {
fn partial_cmp(&self, other: &TimedActivator) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for TimedActivator {
fn eq(&self, other: &TimedActivator) -> bool {
self.at.eq(&other.at)
}
}
impl Eq for TimedActivator {}