@@ -95,6 +95,8 @@ use portable_atomic as atomic;
9595
9696use atomic:: Ordering ;
9797
98+ use crate :: storage:: { OwnedStorage , Storage , ViewStorage } ;
99+
98100#[ cfg( feature = "mpmc_large" ) ]
99101type AtomicTargetSize = atomic:: AtomicUsize ;
100102#[ cfg( not( feature = "mpmc_large" ) ) ]
@@ -128,17 +130,27 @@ pub type Q32<T> = MpMcQueue<T, 32>;
128130/// MPMC queue with a capability for 64 elements.
129131pub type Q64 < T > = MpMcQueue < T , 64 > ;
130132
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 > {
136138 dequeue_pos : AtomicTargetSize ,
137139 enqueue_pos : AtomicTargetSize ,
140+ buffer : UnsafeCell < S :: Buffer < Cell < T > > > ,
138141}
139142
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+
140153impl < T , const N : usize > MpMcQueue < T , N > {
141- const MASK : UintSize = ( N - 1 ) as UintSize ;
142154 const EMPTY_CELL : Cell < T > = Cell :: new ( 0 ) ;
143155
144156 const ASSERT : [ ( ) ; 1 ] = [ ( ) ] ;
@@ -167,10 +179,56 @@ impl<T, const N: usize> MpMcQueue<T, N> {
167179 enqueue_pos : AtomicTargetSize :: new ( 0 ) ,
168180 }
169181 }
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+ }
170228
171229 /// Returns the item in the front of the queue, or `None` if the queue is empty
172230 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 ( ) ) }
174232 }
175233
176234 /// Adds an `item` to the end of the queue
@@ -179,9 +237,9 @@ impl<T, const N: usize> MpMcQueue<T, N> {
179237 pub fn enqueue ( & self , item : T ) -> Result < ( ) , T > {
180238 unsafe {
181239 enqueue (
182- self . buffer . get ( ) as * mut _ ,
240+ S :: as_ptr ( self . buffer . get ( ) ) ,
183241 & self . enqueue_pos ,
184- Self :: MASK ,
242+ self . mask ( ) ,
185243 item,
186244 )
187245 }
@@ -194,14 +252,14 @@ impl<T, const N: usize> Default for MpMcQueue<T, N> {
194252 }
195253}
196254
197- impl < T , const N : usize > Drop for MpMcQueue < T , N > {
255+ impl < T , S : Storage > Drop for MpMcQueueInner < T , S > {
198256 fn drop ( & mut self ) {
199257 // drop all contents currently in the queue
200258 while self . dequeue ( ) . is_some ( ) { }
201259 }
202260}
203261
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 { }
205263
206264struct Cell < T > {
207265 data : MaybeUninit < T > ,
0 commit comments