#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum EventPriority {
Low,
Normal,
High,
Critical,
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct QueuedEvent {
pub event_id: u64,
pub priority: EventPriority,
pub timestamp: f64,
pub(crate) seq: u64,
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct EventQueueConfig {
pub capacity: usize,
}
#[allow(dead_code)]
pub struct EventQueue {
pub config: EventQueueConfig,
events: Vec<QueuedEvent>,
next_seq: u64,
}
fn event_sort_key(e: &QueuedEvent) -> (u8, u64, u64) {
let prio_inv = u8::MAX - event_priority_value(e.priority);
let ts_bits = e.timestamp.to_bits();
(prio_inv, ts_bits, e.seq)
}
#[allow(dead_code)]
pub fn default_event_queue_config() -> EventQueueConfig {
EventQueueConfig { capacity: 0 }
}
#[allow(dead_code)]
pub fn new_event_queue(cfg: &EventQueueConfig) -> EventQueue {
EventQueue {
config: cfg.clone(),
events: Vec::new(),
next_seq: 0,
}
}
#[allow(dead_code)]
pub fn enqueue_event(
q: &mut EventQueue,
event_id: u64,
priority: EventPriority,
timestamp: f64,
) {
let seq = q.next_seq;
q.next_seq += 1;
let ev = QueuedEvent { event_id, priority, timestamp, seq };
let key = event_sort_key(&ev);
let pos = q.events.partition_point(|e| event_sort_key(e) <= key);
q.events.insert(pos, ev);
if q.config.capacity > 0 && q.events.len() > q.config.capacity {
q.events.pop();
}
}
#[allow(dead_code)]
pub fn dequeue_event(q: &mut EventQueue) -> Option<QueuedEvent> {
if q.events.is_empty() {
None
} else {
Some(q.events.remove(0))
}
}
#[allow(dead_code)]
pub fn peek_event(q: &EventQueue) -> Option<&QueuedEvent> {
q.events.first()
}
#[allow(dead_code)]
pub fn event_queue_len(q: &EventQueue) -> usize {
q.events.len()
}
#[allow(dead_code)]
pub fn clear_event_queue(q: &mut EventQueue) {
q.events.clear();
}
#[allow(dead_code)]
pub fn drain_events_by_priority(
q: &mut EventQueue,
priority: EventPriority,
) -> Vec<QueuedEvent> {
let mut drained = Vec::new();
let mut i = 0;
while i < q.events.len() {
if q.events[i].priority == priority {
drained.push(q.events.remove(i));
} else {
i += 1;
}
}
drained
}
#[allow(dead_code)]
pub fn event_priority_value(p: EventPriority) -> u8 {
match p {
EventPriority::Low => 0,
EventPriority::Normal => 1,
EventPriority::High => 2,
EventPriority::Critical => 3,
}
}
#[allow(dead_code)]
pub fn event_queue_is_empty(q: &EventQueue) -> bool {
q.events.is_empty()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_empty_queue() {
let cfg = default_event_queue_config();
let q = new_event_queue(&cfg);
assert!(event_queue_is_empty(&q));
assert_eq!(event_queue_len(&q), 0);
}
#[test]
fn test_enqueue_dequeue_order() {
let cfg = default_event_queue_config();
let mut q = new_event_queue(&cfg);
enqueue_event(&mut q, 1, EventPriority::Low, 1.0);
enqueue_event(&mut q, 2, EventPriority::Critical, 2.0);
enqueue_event(&mut q, 3, EventPriority::Normal, 0.5);
let first = dequeue_event(&mut q).expect("should succeed");
assert_eq!(first.priority, EventPriority::Critical);
}
#[test]
fn test_peek_does_not_remove() {
let cfg = default_event_queue_config();
let mut q = new_event_queue(&cfg);
enqueue_event(&mut q, 42, EventPriority::High, 0.0);
let _ = peek_event(&q);
assert_eq!(event_queue_len(&q), 1);
}
#[test]
fn test_clear_event_queue() {
let cfg = default_event_queue_config();
let mut q = new_event_queue(&cfg);
enqueue_event(&mut q, 1, EventPriority::Normal, 0.0);
enqueue_event(&mut q, 2, EventPriority::High, 0.0);
clear_event_queue(&mut q);
assert!(event_queue_is_empty(&q));
}
#[test]
fn test_drain_events_by_priority() {
let cfg = default_event_queue_config();
let mut q = new_event_queue(&cfg);
enqueue_event(&mut q, 1, EventPriority::Normal, 0.0);
enqueue_event(&mut q, 2, EventPriority::High, 1.0);
enqueue_event(&mut q, 3, EventPriority::Normal, 2.0);
let drained = drain_events_by_priority(&mut q, EventPriority::Normal);
assert_eq!(drained.len(), 2);
assert_eq!(event_queue_len(&q), 1);
}
#[test]
fn test_priority_values_ordered() {
assert!(event_priority_value(EventPriority::Low) < event_priority_value(EventPriority::Normal));
assert!(event_priority_value(EventPriority::Normal) < event_priority_value(EventPriority::High));
assert!(event_priority_value(EventPriority::High) < event_priority_value(EventPriority::Critical));
}
#[test]
fn test_capacity_enforcement() {
let cfg = EventQueueConfig { capacity: 2 };
let mut q = new_event_queue(&cfg);
enqueue_event(&mut q, 1, EventPriority::Low, 0.0);
enqueue_event(&mut q, 2, EventPriority::High, 0.0);
enqueue_event(&mut q, 3, EventPriority::Normal, 0.0);
assert!(event_queue_len(&q) <= 2);
}
#[test]
fn test_fifo_within_same_priority_and_timestamp() {
let cfg = default_event_queue_config();
let mut q = new_event_queue(&cfg);
enqueue_event(&mut q, 10, EventPriority::Normal, 0.0);
enqueue_event(&mut q, 20, EventPriority::Normal, 0.0);
let first = dequeue_event(&mut q).expect("should succeed");
let second = dequeue_event(&mut q).expect("should succeed");
assert_eq!(first.event_id, 10);
assert_eq!(second.event_id, 20);
}
}