use std::{
cmp::Ordering,
collections::BinaryHeap,
sync::atomic::{AtomicU64, Ordering as AtomicOrdering},
};
use crate::{arch::sync::Mutex, ipc::DynEvent};
pub const DEFAULT_CAPACITY: usize = 256;
struct PriorityEntry {
priority: u32,
sequence: u64,
event: DynEvent,
}
#[cfg_attr(coverage_nightly, coverage(off))]
impl PartialEq for PriorityEntry {
fn eq(&self, other: &Self) -> bool {
self.priority == other.priority && self.sequence == other.sequence
}
}
impl Eq for PriorityEntry {}
impl PartialOrd for PriorityEntry {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for PriorityEntry {
fn cmp(&self, other: &Self) -> Ordering {
match other.priority.cmp(&self.priority) {
Ordering::Equal => other.sequence.cmp(&self.sequence),
ord => ord,
}
}
}
pub struct PriorityQueue {
heap: Mutex<BinaryHeap<PriorityEntry>>,
sequence: AtomicU64,
capacity: usize,
}
impl PriorityQueue {
#[must_use]
pub fn new() -> Self {
Self::with_capacity(DEFAULT_CAPACITY)
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self {
heap: Mutex::new(BinaryHeap::with_capacity(capacity.min(4096))),
sequence: AtomicU64::new(0),
capacity,
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
pub fn push(&self, event: DynEvent) -> bool {
let mut heap = self.heap.lock();
if self.capacity > 0 && heap.len() >= self.capacity {
return false;
}
let entry = PriorityEntry {
priority: event.priority(),
sequence: self.sequence.fetch_add(1, AtomicOrdering::Relaxed),
event,
};
heap.push(entry);
true
}
#[must_use]
pub fn pop(&self) -> Option<DynEvent> {
self.heap.lock().pop().map(|e| e.event)
}
#[must_use]
pub fn peek_priority(&self) -> Option<u32> {
self.heap.lock().peek().map(|e| e.priority)
}
#[must_use]
pub fn len(&self) -> usize {
self.heap.lock().len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.heap.lock().is_empty()
}
#[inline]
#[must_use]
pub const fn capacity(&self) -> usize {
self.capacity
}
pub fn clear(&self) {
self.heap.lock().clear();
}
#[must_use]
pub fn drain(&self) -> Vec<DynEvent> {
let mut heap = self.heap.lock();
let mut result = Vec::with_capacity(heap.len());
while let Some(entry) = heap.pop() {
result.push(entry.event);
}
result
}
}
impl Default for PriorityQueue {
fn default() -> Self {
Self::new()
}
}
impl std::fmt::Debug for PriorityQueue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PriorityQueue")
.field("len", &self.len())
.field("capacity", &self.capacity)
.field("peek_priority", &self.peek_priority())
.finish_non_exhaustive()
}
}