Skip to main content

async_priority_lock/
queue.rs

1//! Contains the [PriorityQueue] trait and builtin impls when features are enabled.
2//!
3//! Provided queues are [BoxQueue] and [ArenaQueue].
4#[cfg(feature = "box-queue")]
5pub mod boxed;
6#[cfg(feature = "box-queue")]
7pub use boxed::*;
8#[cfg(feature = "arena-queue")]
9pub mod arena;
10#[cfg(feature = "arena-queue")]
11pub use arena::*;
12
13use crate::Priority;
14
15/// A PriorityQueue is a queue which orders entries by priority - higher priority first.
16///
17/// This is marked as unsafe as some associated types exist which must behave correctly, in
18/// particular:
19/// - An enqueued node will return a Self::Handle
20/// - Until that handle is dequeued via self.dequeue, we must be able to lookup the node - even if
21///   that node is repositioned.
22/// - "shared" handles - these allow us to lookup nodes without owning them or retaining a
23///   reference to the queue (allowing us to update them, but not remove them)
24///
25/// Any lookups via a handle which was not returned from enqueue or other functions is UB.
26/// Implementers can choose to panic or simply assume that all handles provided will be valid.
27///
28/// Additionally, it is required that all nodes be dequeued before the queue is dropped - so
29/// the queue should not have any entries when it is dropped.
30pub unsafe trait PriorityQueue<P: Priority>: Default {
31    type Handle: PriorityQueueHandle<P>;
32    type SharedHandle: AsRef<Self::Handle>;
33
34    /// Enqueue an entry with provided data.  This must return a unique handle for this node.
35    fn enqueue(&mut self, data: P) -> Self::Handle;
36    /// Dequeue an entry by its handle
37    fn dequeue(&mut self, handle: Self::Handle) -> (Option<&P>, Option<Self::SharedHandle>);
38
39    /// Get an entry's data by its handle
40    fn get_by_handle(&self, handle: &Self::Handle) -> &P;
41
42    #[inline(always)]
43    /// Iterate through the queue from the start.
44    fn iter<'a>(&'a self) -> impl Iterator<Item = &'a P>
45    where
46        P: 'a,
47    {
48        self.iter_at(None)
49    }
50
51    /// Iterate through the queue starting at a provided handle (or None to start with the head
52    /// node) (including the provided value)
53    fn iter_at<'a>(&'a self, handle: Option<&Self::Handle>) -> impl Iterator<Item = &'a P>
54    where
55        P: 'a;
56
57    /// Returns true if the queue is empty
58    #[inline]
59    fn is_empty(&self) -> bool {
60        self.iter().next().is_none()
61    }
62
63    /// Update a node via handle ref.  `update` is a fn that should return true if the node's
64    /// priority changed.  i.e. if `update` returns false, the queue does not need to consider
65    /// repositioning the changed node.
66    fn update_node(&mut self, handle: &Self::Handle, update: impl FnOnce(&mut P) -> bool);
67
68    #[inline]
69    /// Get the first node in the queue
70    fn head(&self) -> Option<&P> {
71        self.iter().next()
72    }
73
74    /// Get a SharedHandle for the first node in the queue
75    fn head_handle(&self) -> Option<Self::SharedHandle>;
76
77    /// Get the handle for the next node after an input handle (or None if the provided handle is
78    /// the tail node)
79    fn get_next_handle(&self, handle: &Self::Handle) -> Option<Self::SharedHandle>;
80}
81
82/// The "handle" for an entry in a [PriorityQueue].
83///
84/// Allows for skipping a read lock on the owning [PriorityQueue] if a reference to the data can be
85/// retrieved without a reference to the owning queue.
86pub trait PriorityQueueHandle<D: Priority> {
87    /// If the entry can be loaded with only the handle (without needing access to the queue
88    /// itself), then this can optionally be set to a function which loads it directly.
89    ///
90    /// It is up to the caller to ensure that none of the referenced data used can be changed while
91    /// a ref is held (e.g. make sure that update_node is not called on the node, or if it is
92    /// called, none of the data referenced will be mutated)
93    const LOAD_PURE: Option<unsafe fn(&Self) -> &D> = None;
94}