use std::cmp::Ordering;
use std::collections::BinaryHeap;
use super::clock::SimTime;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct EventSeq(u64);
impl EventSeq {
#[must_use]
pub const fn new(seq: u64) -> Self {
Self(seq)
}
#[must_use]
pub const fn as_u64(&self) -> u64 {
self.0
}
}
impl PartialOrd for EventSeq {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for EventSeq {
fn cmp(&self, other: &Self) -> Ordering {
self.0.cmp(&other.0)
}
}
#[derive(Debug)]
struct QueuedEvent<E> {
time: SimTime,
seq: EventSeq,
event: E,
}
impl<E> PartialEq for QueuedEvent<E> {
fn eq(&self, other: &Self) -> bool {
self.time == other.time && self.seq == other.seq
}
}
impl<E> Eq for QueuedEvent<E> {}
impl<E> PartialOrd for QueuedEvent<E> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<E> Ord for QueuedEvent<E> {
fn cmp(&self, other: &Self) -> Ordering {
match other.time.cmp(&self.time) {
Ordering::Equal => other.seq.cmp(&self.seq),
ordering => ordering,
}
}
}
#[derive(Debug)]
pub struct EventQueue<E> {
heap: BinaryHeap<QueuedEvent<E>>,
next_seq: u64,
}
impl<E> EventQueue<E> {
#[must_use]
pub fn new() -> Self {
Self {
heap: BinaryHeap::new(),
next_seq: 0,
}
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.heap.is_empty()
}
#[must_use]
pub fn len(&self) -> usize {
self.heap.len()
}
pub fn schedule(&mut self, time: SimTime, event: E) -> EventSeq {
let seq = EventSeq::new(self.next_seq);
self.next_seq += 1;
self.heap.push(QueuedEvent { time, seq, event });
seq
}
#[must_use]
pub fn peek(&self) -> Option<(SimTime, &E)> {
self.heap.peek().map(|qe| (qe.time, &qe.event))
}
#[must_use]
pub fn peek_time(&self) -> Option<SimTime> {
self.heap.peek().map(|qe| qe.time)
}
pub fn pop(&mut self) -> Option<(SimTime, EventSeq, E)> {
self.heap.pop().map(|qe| (qe.time, qe.seq, qe.event))
}
pub fn pop_if_ready(&mut self, now: SimTime) -> Option<(SimTime, EventSeq, E)> {
if let Some(qe) = self.heap.peek() {
if qe.time <= now {
return self.pop();
}
}
None
}
pub fn pop_all_ready(&mut self, now: SimTime) -> Vec<(SimTime, EventSeq, E)> {
let mut events = Vec::new();
while let Some(result) = self.pop_if_ready(now) {
events.push(result);
}
events
}
pub fn cancel_where<F>(&mut self, predicate: F) -> usize
where
F: Fn(&E) -> bool,
{
let original_len = self.heap.len();
let events: Vec<_> = self.heap.drain().collect();
for qe in events {
if !predicate(&qe.event) {
self.heap.push(qe);
}
}
original_len - self.heap.len()
}
pub fn clear(&mut self) {
self.heap.clear();
}
pub fn count_where<F>(&self, predicate: F) -> usize
where
F: Fn(&E) -> bool,
{
self.heap.iter().filter(|qe| predicate(&qe.event)).count()
}
}
impl<E> Default for EventQueue<E> {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, Clone, PartialEq)]
enum TestEvent {
A(u32),
B(u32),
}
#[test]
fn test_queue_basic() {
let mut queue = EventQueue::new();
assert!(queue.is_empty());
assert_eq!(queue.len(), 0);
queue.schedule(SimTime::from_millis(100), TestEvent::A(1));
queue.schedule(SimTime::from_millis(50), TestEvent::A(2));
queue.schedule(SimTime::from_millis(150), TestEvent::A(3));
assert!(!queue.is_empty());
assert_eq!(queue.len(), 3);
}
#[test]
fn test_queue_ordering_by_time() {
let mut queue = EventQueue::new();
queue.schedule(SimTime::from_millis(100), TestEvent::A(1));
queue.schedule(SimTime::from_millis(50), TestEvent::A(2));
queue.schedule(SimTime::from_millis(150), TestEvent::A(3));
let (t1, _, e1) = queue.pop().unwrap();
let (t2, _, e2) = queue.pop().unwrap();
let (t3, _, e3) = queue.pop().unwrap();
assert_eq!(t1, SimTime::from_millis(50));
assert_eq!(t2, SimTime::from_millis(100));
assert_eq!(t3, SimTime::from_millis(150));
assert_eq!(e1, TestEvent::A(2));
assert_eq!(e2, TestEvent::A(1));
assert_eq!(e3, TestEvent::A(3));
}
#[test]
fn test_queue_ordering_by_seq_same_time() {
let mut queue = EventQueue::new();
let t = SimTime::from_millis(100);
queue.schedule(t, TestEvent::A(1));
queue.schedule(t, TestEvent::A(2));
queue.schedule(t, TestEvent::A(3));
let (_, _, e1) = queue.pop().unwrap();
let (_, _, e2) = queue.pop().unwrap();
let (_, _, e3) = queue.pop().unwrap();
assert_eq!(e1, TestEvent::A(1));
assert_eq!(e2, TestEvent::A(2));
assert_eq!(e3, TestEvent::A(3));
}
#[test]
fn test_peek() {
let mut queue = EventQueue::new();
assert!(queue.peek().is_none());
assert!(queue.peek_time().is_none());
queue.schedule(SimTime::from_millis(100), TestEvent::A(1));
queue.schedule(SimTime::from_millis(50), TestEvent::A(2));
let (t, e) = queue.peek().unwrap();
assert_eq!(t, SimTime::from_millis(50));
assert_eq!(e, &TestEvent::A(2));
assert_eq!(queue.len(), 2);
}
#[test]
fn test_pop_if_ready() {
let mut queue = EventQueue::new();
queue.schedule(SimTime::from_millis(100), TestEvent::A(1));
queue.schedule(SimTime::from_millis(200), TestEvent::A(2));
assert!(queue.pop_if_ready(SimTime::from_millis(50)).is_none());
let (t, _, e) = queue.pop_if_ready(SimTime::from_millis(100)).unwrap();
assert_eq!(t, SimTime::from_millis(100));
assert_eq!(e, TestEvent::A(1));
assert!(queue.pop_if_ready(SimTime::from_millis(100)).is_none());
let (t, _, e) = queue.pop_if_ready(SimTime::from_millis(200)).unwrap();
assert_eq!(t, SimTime::from_millis(200));
assert_eq!(e, TestEvent::A(2));
}
#[test]
fn test_pop_all_ready() {
let mut queue = EventQueue::new();
queue.schedule(SimTime::from_millis(50), TestEvent::A(1));
queue.schedule(SimTime::from_millis(100), TestEvent::A(2));
queue.schedule(SimTime::from_millis(100), TestEvent::A(3));
queue.schedule(SimTime::from_millis(200), TestEvent::A(4));
let ready = queue.pop_all_ready(SimTime::from_millis(100));
assert_eq!(ready.len(), 3);
assert_eq!(ready[0].2, TestEvent::A(1));
assert_eq!(ready[1].2, TestEvent::A(2));
assert_eq!(ready[2].2, TestEvent::A(3));
assert_eq!(queue.len(), 1);
}
#[test]
fn test_cancel_where() {
let mut queue = EventQueue::new();
queue.schedule(SimTime::from_millis(100), TestEvent::A(1));
queue.schedule(SimTime::from_millis(100), TestEvent::B(2));
queue.schedule(SimTime::from_millis(100), TestEvent::A(3));
let cancelled = queue.cancel_where(|e| matches!(e, TestEvent::A(_)));
assert_eq!(cancelled, 2);
assert_eq!(queue.len(), 1);
let (_, _, e) = queue.pop().unwrap();
assert_eq!(e, TestEvent::B(2));
}
#[test]
fn test_count_where() {
let mut queue = EventQueue::new();
queue.schedule(SimTime::from_millis(100), TestEvent::A(1));
queue.schedule(SimTime::from_millis(100), TestEvent::B(2));
queue.schedule(SimTime::from_millis(100), TestEvent::A(3));
let count_a = queue.count_where(|e| matches!(e, TestEvent::A(_)));
let count_b = queue.count_where(|e| matches!(e, TestEvent::B(_)));
assert_eq!(count_a, 2);
assert_eq!(count_b, 1);
}
}