@@ -95,6 +95,8 @@ use portable_atomic as atomic;
95
95
96
96
use atomic:: Ordering ;
97
97
98
+ use crate :: storage:: { OwnedStorage , Storage , ViewStorage } ;
99
+
98
100
#[ cfg( feature = "mpmc_large" ) ]
99
101
type AtomicTargetSize = atomic:: AtomicUsize ;
100
102
#[ cfg( not( feature = "mpmc_large" ) ) ]
@@ -128,17 +130,27 @@ pub type Q32<T> = MpMcQueue<T, 32>;
128
130
/// MPMC queue with a capability for 64 elements.
129
131
pub type Q64 < T > = MpMcQueue < T , 64 > ;
130
132
131
- /// MPMC queue with a capacity for N elements
132
- /// N must be a power of 2
133
- /// The max value of N is u8::MAX - 1 if `mpmc_large` feature is not enabled.
134
- pub struct MpMcQueue < T , const N : usize > {
135
- buffer : UnsafeCell < [ Cell < T > ; N ] > ,
133
+ /// Base struct for [`MpMcQueue`] and [`MpMcQueueView`], generic over the [`Storage`].
134
+ ///
135
+ /// In most cases you should use [`MpMcQueue`] or [`MpMcQueueView`] directly. Only use this
136
+ /// struct if you want to write code that's generic over both.
137
+ pub struct MpMcQueueInner < T , S : Storage > {
136
138
dequeue_pos : AtomicTargetSize ,
137
139
enqueue_pos : AtomicTargetSize ,
140
+ buffer : UnsafeCell < S :: Buffer < Cell < T > > > ,
138
141
}
139
142
143
+ /// MPMC queue with a capacity for N elements
144
+ /// N must be a power of 2
145
+ /// The max value of N is u8::MAX - 1 if `mpmc_large` feature is not enabled.
146
+ pub type MpMcQueue < T , const N : usize > = MpMcQueueInner < T , OwnedStorage < N > > ;
147
+
148
+ /// MPMC queue with a capacity for N elements
149
+ /// N must be a power of 2
150
+ /// The max value of N is u8::MAX - 1 if `mpmc_large` feature is not enabled.
151
+ pub type MpMcQueueView < T > = MpMcQueueInner < T , ViewStorage > ;
152
+
140
153
impl < T , const N : usize > MpMcQueue < T , N > {
141
- const MASK : UintSize = ( N - 1 ) as UintSize ;
142
154
const EMPTY_CELL : Cell < T > = Cell :: new ( 0 ) ;
143
155
144
156
const ASSERT : [ ( ) ; 1 ] = [ ( ) ] ;
@@ -167,10 +179,56 @@ impl<T, const N: usize> MpMcQueue<T, N> {
167
179
enqueue_pos : AtomicTargetSize :: new ( 0 ) ,
168
180
}
169
181
}
182
+ /// Get a reference to the `MpMcQueue`, erasing the `N` const-generic.
183
+ ///
184
+ ///
185
+ /// ```rust
186
+ /// # use heapless::mpmc::{MpMcQueue, MpMcQueueView};
187
+ /// let queue: MpMcQueue<u8, 2> = MpMcQueue::new();
188
+ /// let view: &MpMcQueueView<u8> = queue.as_view();
189
+ /// ```
190
+ ///
191
+ /// It is often preferable to do the same through type coerction, since `MpMcQueue<T, N>` implements `Unsize<MpMcQueueView<T>>`:
192
+ ///
193
+ /// ```rust
194
+ /// # use heapless::mpmc::{MpMcQueue, MpMcQueueView};
195
+ /// let queue: MpMcQueue<u8, 2> = MpMcQueue::new();
196
+ /// let view: &MpMcQueueView<u8> = &queue;
197
+ /// ```
198
+ #[ inline]
199
+ pub const fn as_view ( & self ) -> & MpMcQueueView < T > {
200
+ self
201
+ }
202
+
203
+ /// Get a mutable reference to the `MpMcQueue`, erasing the `N` const-generic.
204
+ ///
205
+ /// ```rust
206
+ /// # use heapless::mpmc::{MpMcQueue, MpMcQueueView};
207
+ /// let mut queue: MpMcQueue<u8, 2> = MpMcQueue::new();
208
+ /// let view: &mut MpMcQueueView<u8> = queue.as_mut_view();
209
+ /// ```
210
+ ///
211
+ /// It is often preferable to do the same through type coerction, since `MpMcQueue<T, N>` implements `Unsize<MpMcQueueView<T>>`:
212
+ ///
213
+ /// ```rust
214
+ /// # use heapless::mpmc::{MpMcQueue, MpMcQueueView};
215
+ /// let mut queue: MpMcQueue<u8, 2> = MpMcQueue::new();
216
+ /// let view: &mut MpMcQueueView<u8> = &mut queue;
217
+ /// ```
218
+ #[ inline]
219
+ pub fn as_mut_view ( & mut self ) -> & mut MpMcQueueView < T > {
220
+ self
221
+ }
222
+ }
223
+
224
+ impl < T , S : Storage > MpMcQueueInner < T , S > {
225
+ fn mask ( & self ) -> UintSize {
226
+ ( S :: len ( self . buffer . get ( ) ) - 1 ) as _
227
+ }
170
228
171
229
/// Returns the item in the front of the queue, or `None` if the queue is empty
172
230
pub fn dequeue ( & self ) -> Option < T > {
173
- unsafe { dequeue ( self . buffer . get ( ) as * mut _ , & self . dequeue_pos , Self :: MASK ) }
231
+ unsafe { dequeue ( S :: as_ptr ( self . buffer . get ( ) ) , & self . dequeue_pos , self . mask ( ) ) }
174
232
}
175
233
176
234
/// Adds an `item` to the end of the queue
@@ -179,9 +237,9 @@ impl<T, const N: usize> MpMcQueue<T, N> {
179
237
pub fn enqueue ( & self , item : T ) -> Result < ( ) , T > {
180
238
unsafe {
181
239
enqueue (
182
- self . buffer . get ( ) as * mut _ ,
240
+ S :: as_ptr ( self . buffer . get ( ) ) ,
183
241
& self . enqueue_pos ,
184
- Self :: MASK ,
242
+ self . mask ( ) ,
185
243
item,
186
244
)
187
245
}
@@ -194,14 +252,14 @@ impl<T, const N: usize> Default for MpMcQueue<T, N> {
194
252
}
195
253
}
196
254
197
- impl < T , const N : usize > Drop for MpMcQueue < T , N > {
255
+ impl < T , S : Storage > Drop for MpMcQueueInner < T , S > {
198
256
fn drop ( & mut self ) {
199
257
// drop all contents currently in the queue
200
258
while self . dequeue ( ) . is_some ( ) { }
201
259
}
202
260
}
203
261
204
- unsafe impl < T , const N : usize > Sync for MpMcQueue < T , N > where T : Send { }
262
+ unsafe impl < T , S : Storage > Sync for MpMcQueueInner < T , S > where T : Send { }
205
263
206
264
struct Cell < T > {
207
265
data : MaybeUninit < T > ,
0 commit comments