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;