prosa_utils/queue.rs
1//! Module for ProSA internal queueing utilitary
2
3/// Atomic queue implementation
4pub(crate) mod lockfree;
5
6/// Queue for single producer and multiple consumers
7pub mod spmc;
8
9/// Queue for Multiple producers and single consumer
10pub mod mpsc;
11
12/// Error define for Queues
13/// Use by utilitary queues an their implementation in ProSA.
14#[derive(Debug, Eq, thiserror::Error, PartialOrd, PartialEq)]
15pub enum QueueError<T> {
16 /// Error indicating that the queue is empty
17 #[error("The queue is empty")]
18 Empty,
19 /// Error indicating that the queue is full
20 #[error("The queue is full, it contain {1} items")]
21 Full(T, usize),
22 /// Can't retrieve the element
23 #[error("Can't retrieve the element {0}")]
24 Retrieve(usize),
25}
26
27/// Trait to define all information getter from the queue
28///
29/// ```no_run
30/// use prosa_utils::queue::QueueChecker;
31///
32/// fn queue_checker<Q>(queue: Q)
33/// where
34/// Q: QueueChecker<usize>,
35/// {
36/// if queue.is_empty() {
37/// assert!(!queue.is_full());
38/// assert_eq!(0, queue.len());
39/// } else if queue.is_full() {
40/// assert!(!queue.is_empty());
41/// assert_eq!(queue.max_capacity(), queue.len());
42/// }
43/// }
44/// ```
45pub trait QueueChecker<P> {
46 /// Checks if the queue is empty.
47 /// Prefer this method over `len() != 0`
48 fn is_empty(&self) -> bool;
49 /// Checks if the queue is full.
50 /// Prefer this method over `len() != max_capacity()`
51 fn is_full(&self) -> bool;
52 /// Returns the number of item in the queue.
53 fn len(&self) -> P;
54 /// Returns the maximum item capacity of the queue.
55 fn max_capacity(&self) -> P;
56}
57
58/// Macro to define queue inner method related to `QueueChecker` trait
59macro_rules! impl_queue_checker {
60 ( $p:ty ) => {
61 fn is_empty(&self) -> bool {
62 self.get_head() == self.get_tail()
63 }
64
65 fn is_full(&self) -> bool {
66 (self.get_tail() + 1) % (N as $p) == self.get_head()
67 }
68
69 fn len(&self) -> $p {
70 let head = self.get_head();
71 let tail = self.get_tail();
72
73 if tail >= head {
74 tail - head
75 } else {
76 (self.max_capacity() - head) + tail
77 }
78 }
79
80 fn max_capacity(&self) -> $p {
81 N as $p
82 }
83 };
84}
85pub(crate) use impl_queue_checker;
86
87#[macro_export]
88/// Macro of an expression to know if an id is still contain by the queue that have a circular buffer
89///
90/// The buffer have two pointer that indicate head and tail.
91/// Every ID in this range is considered for the queue.
92///
93/// In the following example:
94/// - `o` represent active items
95/// - `-` represent inactive items
96///
97/// If the head is before the tail:
98/// ```text
99/// [ |start |end ]
100/// [------oooooooooooo------]
101/// ```
102///
103/// If the head is after the tail:
104/// ```text
105/// [ |end |start]
106/// [oooooo------------oooooo]
107/// ```
108macro_rules! id_in_queue {
109 ( $id:ident, $head:ident, $tail:ident ) => {
110 ($head > $tail && ($id >= $head || $id < $tail)) || ($id >= $head && $id < $tail)
111 };
112}
113pub use id_in_queue;