Skip to main content

async_priority_lock/
priority.rs

1//! Contains the [Priority] trait responsible for establishing entry position in [PriorityQueue].
2#[cfg(doc)]
3use crate::queue::PriorityQueue;
4#[cfg(feature = "const-default")]
5use const_default::ConstDefault;
6use core::cmp::Ordering;
7
8/// Trait used by [PriorityQueue] to determine the order by which nodes should be enqueued.
9pub trait Priority {
10    /// Compare a (possibly new) priority to an already queued one.
11    ///
12    /// The meaning for the results is as follows:
13    /// - `Less`: Lower priority (i.e. should place after `other`)
14    /// - `Equal`: Same priority - same priority; can be placed before or after `other`
15    /// - `Greater`: Higher priority - Higher priority
16    ///
17    /// This **must** be transitive.
18    fn compare(&self, other: &Self) -> Ordering;
19
20    /// Compare a new (not in a queue) priority with an already queued one (old).
21    ///
22    /// [PriorityQueue]  implementers must always use this function when enqueueing or re-queueing
23    /// an entry to compare it with existing ones.
24    ///
25    /// This does not need to be transitive (and often shouldn't be).
26    ///
27    /// This **must** return the same as [compare](Self::compare) if the result of [compare](Self::compare)
28    /// isn't [Ordering::Equal].
29    ///
30    /// # Example (logic used in [FIFO]):
31    /// ```
32    /// fn compare_new(&self, old: &Self) -> Ordering {
33    ///     // If priority is Equal, then return Less (as `old` was queued first)
34    ///     self.0.compare(&old.0).then(Ordering::Less)
35    /// }
36    /// ```
37    #[inline]
38    fn compare_new(&self, old: &Self) -> Ordering {
39        self.compare(old)
40    }
41}
42
43impl<O: Ord> Priority for O {
44    #[inline(always)]
45    fn compare(&self, other: &Self) -> Ordering {
46        self.cmp(other)
47    }
48}
49
50/// A redundant type alias existing to have parity with LowestFirst (as the default [Priority] impl
51/// for [Ord] is highest first)
52pub type HighestFirst<O> = O;
53
54/// Reverses the result of [Ord::cmp] for `O`. [Less](Ordering::Less) -> [Greater][Ordering::Greater] and
55/// [Greater](Ordering::Greater) -> [Less](Ordering::Less).
56///
57/// This *would* use [Reverse](core::cmp::Reverse), however that does not impl [`From<O>`] - which would make
58/// locking more verbse. e.g. instead of `.acqurie_from(priority)` you'd need
59/// `.acquire(core::cmp::Reverse(priority))`.
60#[derive(Default, Debug, Clone, Copy)]
61#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
62#[repr(transparent)]
63pub struct LowestFirst<O: Ord>(O);
64
65#[cfg(feature = "const-default")]
66impl<O: Ord + ConstDefault> ConstDefault for LowestFirst<O> {
67    const DEFAULT: Self = Self(O::DEFAULT);
68}
69
70impl<O: Ord> Priority for LowestFirst<O> {
71    #[inline]
72    fn compare(&self, other: &Self) -> Ordering {
73        other.0.cmp(&self.0)
74    }
75}
76
77impl<O: Ord> From<O> for LowestFirst<O> {
78    #[inline]
79    fn from(value: O) -> Self {
80        Self(value)
81    }
82}
83
84/// A priority wrapper where newer entries with the same priority are placed after existing entries.
85#[derive(Default, Debug, Clone, Copy)]
86#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
87#[repr(transparent)]
88pub struct FIFO<P: Priority>(P);
89
90impl<P: Priority> Priority for FIFO<P> {
91    #[inline]
92    fn compare(&self, other: &Self) -> Ordering {
93        self.0.compare(&other.0)
94    }
95
96    #[inline]
97    fn compare_new(&self, old: &Self) -> Ordering {
98        // specifically use `compare_new` here as the inner logic may have its own logic that
99        // either only needs to be run for new nodes.
100        //
101        // For fifo, if the old entry is the same priority, then we should place after.
102        // thus, same priority = lower priority
103        self.0.compare_new(&old.0).then(Ordering::Less)
104    }
105}
106
107impl<O: Ord> From<O> for FIFO<LowestFirst<O>> {
108    #[inline]
109    fn from(value: O) -> Self {
110        Self(value.into())
111    }
112}
113
114impl<P: Priority> From<P> for FIFO<P> {
115    #[inline]
116    fn from(value: P) -> Self {
117        Self(value)
118    }
119}
120
121#[cfg(feature = "const-default")]
122impl<P: Priority + ConstDefault> ConstDefault for FIFO<P> {
123    const DEFAULT: Self = Self(P::DEFAULT);
124}
125
126/// A priority wrapper where newer entries with the same priority are placed before existing entries.
127#[derive(Default, Debug, Clone, Copy)]
128#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
129#[repr(transparent)]
130pub struct LIFO<P: Priority>(P);
131
132impl<P: Priority> Priority for LIFO<P> {
133    #[inline]
134    fn compare(&self, other: &Self) -> Ordering {
135        self.0.compare(&other.0)
136    }
137
138    #[inline]
139    fn compare_new(&self, old: &Self) -> Ordering {
140        // specifically use `compare_new` here as the inner logic may have its own logic that
141        // either only needs to be run for new nodes.
142        //
143        // Opposite of fifo - if the new entry has the same priority as the old one, then we
144        // consider it a higher priority
145        self.0.compare_new(&old.0).then(Ordering::Greater)
146    }
147}
148
149impl<P: Priority> From<P> for LIFO<P> {
150    #[inline]
151    fn from(value: P) -> Self {
152        Self(value)
153    }
154}
155
156impl<O: Ord> From<O> for LIFO<LowestFirst<O>> {
157    #[inline]
158    fn from(value: O) -> Self {
159        Self(value.into())
160    }
161}
162
163#[cfg(feature = "const-default")]
164impl<P: Priority + ConstDefault> ConstDefault for LIFO<P> {
165    const DEFAULT: Self = Self(P::DEFAULT);
166}