bbqueue/queue.rs
1use core::marker::PhantomData;
2
3use crate::{
4 prod_cons::{
5 framed::{FramedConsumer, FramedProducer},
6 stream::{StreamConsumer, StreamProducer},
7 },
8 traits::{
9 coordination::Coord,
10 notifier::Notifier,
11 storage::{ConstStorage, Storage},
12 },
13};
14
15#[cfg(feature = "alloc")]
16use crate::traits::bbqhdl::BbqHandle;
17
18/// A standard bbqueue
19pub struct BBQueue<S, C, N> {
20 pub(crate) sto: S,
21 pub(crate) cor: C,
22 pub(crate) not: N,
23}
24
25impl<S: Storage, C: Coord, N: Notifier> BBQueue<S, C, N> {
26 /// Create a new [`BBQueue`] with the given [`Storage`] impl
27 pub fn new_with_storage(sto: S) -> Self {
28 Self {
29 sto,
30 cor: C::INIT,
31 not: N::INIT,
32 }
33 }
34}
35
36/// A BBQueue wrapped in an Arc
37#[cfg(feature = "alloc")]
38pub struct ArcBBQueue<S, C, N>(pub(crate) alloc::sync::Arc<BBQueue<S, C, N>>);
39
40#[cfg(feature = "alloc")]
41impl<S: Storage, C: Coord, N: Notifier> ArcBBQueue<S, C, N> {
42 /// Create a new [`BBQueue`] with the given [`Storage`] impl
43 pub fn new_with_storage(sto: S) -> Self {
44 Self(alloc::sync::Arc::new(BBQueue::new_with_storage(sto)))
45 }
46}
47
48#[allow(clippy::new_without_default)]
49impl<S: ConstStorage, C: Coord, N: Notifier> BBQueue<S, C, N> {
50 /// Create a new `BBQueue` in a const context
51 pub const fn new() -> Self {
52 Self {
53 sto: S::INIT,
54 cor: C::INIT,
55 not: N::INIT,
56 }
57 }
58}
59
60impl<S: Storage, C: Coord, N: Notifier> BBQueue<S, C, N> {
61 /// Create a new [`FramedProducer`] for this [`BBQueue`]
62 ///
63 /// Although mixing stream and framed consumer/producers will not result in UB,
64 /// it will also not work correctly.
65 pub const fn framed_producer(&self) -> FramedProducer<&'_ Self> {
66 FramedProducer {
67 bbq: self,
68 pd: PhantomData,
69 }
70 }
71
72 /// Create a new [`FramedConsumer`] for this [`BBQueue`]
73 ///
74 /// Although mixing stream and framed consumer/producers will not result in UB,
75 /// it will also not work correctly.
76 pub const fn framed_consumer(&self) -> FramedConsumer<&'_ Self> {
77 FramedConsumer {
78 bbq: self,
79 pd: PhantomData,
80 }
81 }
82
83 /// Create a new [`StreamProducer`] for this [`BBQueue`]
84 ///
85 /// Although mixing stream and framed consumer/producers will not result in UB,
86 /// it will also not work correctly.
87 pub const fn stream_producer(&self) -> StreamProducer<&'_ Self> {
88 StreamProducer { bbq: self }
89 }
90
91 /// Create a new [`StreamConsumer`] for this [`BBQueue`]
92 ///
93 /// Although mixing stream and framed consumer/producers will not result in UB,
94 /// it will also not work correctly.
95 pub const fn stream_consumer(&self) -> StreamConsumer<&'_ Self> {
96 StreamConsumer { bbq: self }
97 }
98
99 /// Get the total capacity of the buffer, e.g. how much space is present in [`Storage`]
100 #[inline(always)]
101 pub fn capacity(&self) -> usize {
102 // SAFETY: capacity never changes, therefore reading the len is safe
103 unsafe {
104 self.sto.ptr_len().1
105 }
106 }
107
108 /// Get access to the internal storage implementation details
109 ///
110 /// NOTE: Although this method is safe, use of the `Storage` methods are not.
111 /// You should *never* attempt to access or modify the underlying data contained
112 /// in a storage implementation while the bbqueue is live. That will IMMEDIATELY
113 /// lead to undefined behavior.
114 ///
115 /// As far as I am aware, the only reasonable use for this is for cases where you
116 /// have a custom `Storage` implementation that has unique teardown/drop in place
117 /// requirements. Treat any uses of this function with *extreme* caution!
118 #[inline(always)]
119 pub fn storage(&self) -> &S {
120 &self.sto
121 }
122}
123
124#[cfg(feature = "alloc")]
125impl<S: Storage, C: Coord, N: Notifier> crate::queue::ArcBBQueue<S, C, N> {
126 /// Create a new [`FramedProducer`] for this [`BBQueue`]
127 ///
128 /// Although mixing stream and framed consumer/producers will not result in UB,
129 /// it will also not work correctly.
130 pub fn framed_producer(&self) -> FramedProducer<alloc::sync::Arc<BBQueue<S, C, N>>> {
131 FramedProducer {
132 bbq: self.0.bbq_ref(),
133 pd: PhantomData,
134 }
135 }
136
137 /// Create a new [`FramedConsumer`] for this [`BBQueue`]
138 ///
139 /// Although mixing stream and framed consumer/producers will not result in UB,
140 /// it will also not work correctly.
141 pub fn framed_consumer(&self) -> FramedConsumer<alloc::sync::Arc<BBQueue<S, C, N>>> {
142 FramedConsumer {
143 bbq: self.0.bbq_ref(),
144 pd: PhantomData,
145 }
146 }
147
148 /// Create a new [`StreamProducer`] for this [`BBQueue`]
149 ///
150 /// Although mixing stream and framed consumer/producers will not result in UB,
151 /// it will also not work correctly.
152 pub fn stream_producer(&self) -> StreamProducer<alloc::sync::Arc<BBQueue<S, C, N>>> {
153 StreamProducer {
154 bbq: self.0.bbq_ref(),
155 }
156 }
157
158 /// Create a new [`StreamConsumer`] for this [`BBQueue`]
159 ///
160 /// Although mixing stream and framed consumer/producers will not result in UB,
161 /// it will also not work correctly.
162 pub fn stream_consumer(&self) -> StreamConsumer<alloc::sync::Arc<BBQueue<S, C, N>>> {
163 StreamConsumer {
164 bbq: self.0.bbq_ref(),
165 }
166 }
167
168 /// Get the total capacity of the buffer, e.g. how much space is present in [`Storage`]
169 #[inline(always)]
170 pub fn capacity(&self) -> usize {
171 // SAFETY: capacity never changes, therefore reading the len is safe
172 unsafe {
173 self.0.sto.ptr_len().1
174 }
175 }
176
177 /// Get access to the internal storage implementation details
178 ///
179 /// NOTE: Although this method is safe, use of the `Storage` methods are not.
180 /// You should *never* attempt to access or modify the underlying data contained
181 /// in a storage implementation while the bbqueue is live. That will IMMEDIATELY
182 /// lead to undefined behavior.
183 ///
184 /// As far as I am aware, the only reasonable use for this is for cases where you
185 /// have a custom `Storage` implementation that has unique teardown/drop in place
186 /// requirements. Treat any uses of this function with *extreme* caution!
187 #[inline(always)]
188 pub fn storage(&self) -> &S {
189 &self.0.sto
190 }
191}
192
193#[cfg(test)]
194mod test {
195 use crate::traits::{
196 coordination::cas::AtomicCoord, notifier::polling::Polling, storage::Inline,
197 };
198
199 use super::*;
200
201 type Queue = BBQueue<Inline<4096>, AtomicCoord, Polling>;
202 static QUEUE: Queue = BBQueue::new();
203 static PRODUCER: FramedProducer<&'static Queue, u16> = QUEUE.framed_producer();
204 static CONSUMER: FramedConsumer<&'static Queue, u16> = QUEUE.framed_consumer();
205
206 #[test]
207 fn handles() {
208 let mut wgr = PRODUCER.grant(16).unwrap();
209 wgr.iter_mut().for_each(|w| *w = 123);
210 wgr.commit(16);
211
212 let rgr = CONSUMER.read().unwrap();
213 assert_eq!(rgr.len(), 16);
214 for b in rgr.iter() {
215 assert_eq!(*b, 123);
216 }
217 rgr.release();
218 }
219}