use rand::distributions::{Distribution, Uniform, WeightedError, WeightedIndex};
use rand::Rng;
pub type LocalEventTime = u32;
pub trait Event: Clone {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ScheduleEventError {
CannotFireEvent,
WeightedError(WeightedError),
}
impl std::error::Error for ScheduleEventError {}
impl std::fmt::Display for ScheduleEventError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match *self {
ScheduleEventError::CannotFireEvent => write!(f, "Cannot fire the event"),
ScheduleEventError::WeightedError(we) => write!(f, "{}", we),
}
}
}
impl From<WeightedError> for ScheduleEventError {
fn from(we: WeightedError) -> Self {
ScheduleEventError::WeightedError(we)
}
}
#[derive(Debug, Clone)]
pub enum EventTimer {
Time(LocalEventTime),
Uniform(LocalEventTime, LocalEventTime, bool),
WeightedIndex(Vec<(LocalEventTime, u8)>),
}
impl EventTimer {
fn to_local_time<R: Rng + ?Sized>(
&self,
rng: &mut R,
) -> Result<LocalEventTime, ScheduleEventError> {
match &self {
EventTimer::Time(timeout) => Ok(*timeout),
EventTimer::Uniform(low, max, inclusive) => Ok(if *inclusive {
Uniform::from(*low..=*max).sample(rng)
} else {
Uniform::from(*low..*max).sample(rng)
}),
EventTimer::WeightedIndex(items) => {
let dist = WeightedIndex::new(items.iter().map(|item| item.1))?;
Ok(items
.get(dist.sample(rng))
.unwrap()
.0)
}
}
}
}
#[derive(Debug, Clone)]
pub enum Schedule {
Immediate,
Timeout(EventTimer),
Everytime,
EveryInterval(EventTimer),
Repeat(u8, EventTimer),
}
impl Schedule {
fn to_local_timer<R: Rng + ?Sized>(
&self,
rng: &mut R,
) -> Result<LocalEventTime, ScheduleEventError> {
match &self {
Schedule::Immediate => Ok(1),
Schedule::Timeout(timeout) => timeout.to_local_time(rng),
Schedule::Everytime => Ok(1),
Schedule::EveryInterval(interval) => interval.to_local_time(rng),
Schedule::Repeat(count, interval) => {
if *count == 0 {
return Err(ScheduleEventError::CannotFireEvent);
}
return interval.to_local_time(rng);
}
}
}
fn to_next(&self) -> Option<Schedule> {
match &self {
Schedule::Immediate
| Schedule::Timeout(_)
| Schedule::Repeat(0, _)
| Schedule::Repeat(1, _) => None,
Schedule::Everytime => Some(Schedule::Everytime),
Schedule::EveryInterval(interval) => Some(Schedule::EveryInterval(interval.clone())),
Schedule::Repeat(count, interval) => {
Some(Schedule::Repeat(count - 1, interval.clone()))
}
}
}
}
pub type Priority = u8;
#[derive(Debug, Clone)]
pub struct EventScheduler<E: Event> {
event_list: Vec<(LocalEventTime, Schedule, Priority, E)>,
}
impl<E: Event> EventScheduler<E> {
pub(crate) fn new() -> Self {
EventScheduler { event_list: vec![] }
}
pub(crate) fn next_time_and_fire<R: Rng + ?Sized>(
&mut self,
rng: &mut R,
) -> Vec<(Priority, E)> {
let mut removed: usize = 0;
for event in self.event_list.iter_mut() {
if event.0 > 0 {
event.0 -= 1;
}
if event.0 == 0 {
removed += 1;
}
}
let fired_events: Vec<(Schedule, Priority, E)> = self
.event_list
.drain(0..removed)
.map(|(_, s, pty, e)| (s, pty, e))
.collect();
for (schedule, pty, event) in fired_events.iter() {
if let Some(next_schedule) = schedule.to_next() {
self.schedule(rng, next_schedule, *pty, event.clone())
.unwrap();
}
}
return fired_events.into_iter().map(|(_, p, e)| (p, e)).collect();
}
pub fn have_event(&self) -> bool {
!self.event_list.is_empty()
}
pub fn count(&self) -> usize {
self.event_list.len()
}
pub fn clear(&mut self) {
self.event_list.clear();
}
pub fn remove_when<P>(&mut self, mut predicate: P)
where
P: FnMut(&(LocalEventTime, Schedule, Priority, E)) -> bool,
{
self.event_list.retain(|state| !predicate(state))
}
#[allow(unused_mut)]
pub fn retain<P>(&mut self, mut predicate: P)
where
P: FnMut(&(LocalEventTime, Schedule, Priority, E)) -> bool,
{
self.event_list.retain(predicate)
}
pub fn schedule<R: Rng + ?Sized>(
&mut self,
rng: &mut R,
schedule: Schedule,
priority: Priority,
event: E,
) -> Result<(), ScheduleEventError> {
let mut index: usize = 0;
let timer: LocalEventTime = schedule.to_local_timer(rng)?;
for (count, _, pty, _) in self.event_list.iter() {
if (&timer == count && &priority > pty) || &timer < count {
break;
}
index += 1;
}
self.event_list
.insert(index, (timer, schedule, priority, event));
Ok(())
}
pub fn schedule_when<R: Rng + ?Sized, P>(
&mut self,
rng: &mut R,
schedule: Schedule,
priority: Priority,
event: E,
predicate: P,
) -> Result<(), ScheduleEventError>
where
P: FnOnce(&Self) -> bool,
{
if !predicate(&self) {
return Ok(());
}
self.schedule(rng, schedule, priority, event)
}
pub fn immediate<R: Rng + ?Sized>(
&mut self,
rng: &mut R,
priority: Priority,
event: E,
) -> Result<(), ScheduleEventError> {
self.schedule(rng, Schedule::Immediate, priority, event)
}
pub fn timeout<R: Rng + ?Sized>(
&mut self,
rng: &mut R,
timeout: EventTimer,
priority: Priority,
event: E,
) -> Result<(), ScheduleEventError> {
self.schedule(rng, Schedule::Timeout(timeout), priority, event)
}
pub fn everytime<R: Rng + ?Sized>(
&mut self,
rng: &mut R,
priority: Priority,
event: E,
) -> Result<(), ScheduleEventError> {
self.schedule(rng, Schedule::Everytime, priority, event)
}
pub fn every_interval<R: Rng + ?Sized>(
&mut self,
rng: &mut R,
interval: EventTimer,
priority: Priority,
event: E,
) -> Result<(), ScheduleEventError> {
self.schedule(rng, Schedule::EveryInterval(interval), priority, event)
}
pub fn repeat<R: Rng + ?Sized>(
&mut self,
rng: &mut R,
count: u8,
interval: EventTimer,
priority: Priority,
event: E,
) -> Result<(), ScheduleEventError> {
self.schedule(rng, Schedule::Repeat(count, interval), priority, event)
}
}