@@ -128,17 +128,77 @@ pub type Q32<T> = MpMcQueue<T, 32>;
128128/// MPMC queue with a capability for 64 elements.
129129pub type Q64 < T > = MpMcQueue < T , 64 > ;
130130
131+ mod private {
132+ use core:: marker:: PhantomData ;
133+
134+ use super :: * ;
135+
136+ /// <div class="warn">This is private API and should not be used</div>
137+ pub struct Owned < T , const N : usize > ( PhantomData < [ T ; N ] > ) ;
138+ /// <div class="warn">This is private API and should not be used</div>
139+ pub struct View < T > ( PhantomData < [ T ] > ) ;
140+
141+ /// <div class="warn">This is private API and should not be used</div>
142+ pub struct MpMcQueueInner < B : MpMcQueueBuffer + ?Sized > {
143+ pub ( super ) dequeue_pos : AtomicTargetSize ,
144+ pub ( super ) enqueue_pos : AtomicTargetSize ,
145+ pub ( super ) buffer : UnsafeCell < B :: Buffer > ,
146+ }
147+ pub trait MpMcQueueBuffer {
148+ type Buffer : ?Sized ;
149+ type T ;
150+
151+ fn as_view ( this : & private:: MpMcQueueInner < Self > ) -> & MpMcQueueView < Self :: T > ;
152+ fn as_mut_view ( this : & mut private:: MpMcQueueInner < Self > ) -> & mut MpMcQueueView < Self :: T > ;
153+ }
154+
155+ impl < T , const N : usize > MpMcQueueBuffer for private:: Owned < T , N > {
156+ type Buffer = [ Cell < T > ; N ] ;
157+ type T = T ;
158+ fn as_view ( this : & private:: MpMcQueueInner < Self > ) -> & MpMcQueueView < Self :: T > {
159+ this
160+ }
161+ fn as_mut_view ( this : & mut private:: MpMcQueueInner < Self > ) -> & mut MpMcQueueView < Self :: T > {
162+ this
163+ }
164+ }
165+
166+ impl < T > MpMcQueueBuffer for private:: View < T > {
167+ type Buffer = [ Cell < T > ] ;
168+ type T = T ;
169+ fn as_view ( this : & private:: MpMcQueueInner < Self > ) -> & MpMcQueueView < Self :: T > {
170+ this
171+ }
172+ fn as_mut_view ( this : & mut private:: MpMcQueueInner < Self > ) -> & mut MpMcQueueView < Self :: T > {
173+ this
174+ }
175+ }
176+
177+ // Cell is sealed to satisfy the compiler's requirement of not leaking private types through the MpMcQueueBuffer trait implementations
178+ pub struct Cell < T > {
179+ pub ( super ) data : MaybeUninit < T > ,
180+ pub ( super ) sequence : AtomicTargetSize ,
181+ }
182+ }
183+
184+ // Workaround https://github.com/rust-lang/rust/issues/119015. This is required so that the methods on `VecView` and `Vec` are properly documented.
185+ // cfg(doc) prevents `MpMcQueueInner` being part of the public API.
186+ // doc(hidden) prevents the `pub use vec::VecInner` from being visible in the documentation.
187+ #[ cfg( doc) ]
188+ #[ doc( hidden) ]
189+ pub use private:: MpMcQueueInner as _;
190+
191+ use private:: Cell ;
192+
131193/// MPMC queue with a capacity for N elements
132194/// N must be a power of 2
133195/// 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 ] > ,
136- dequeue_pos : AtomicTargetSize ,
137- enqueue_pos : AtomicTargetSize ,
138- }
196+ pub type MpMcQueue < T , const N : usize > = private:: MpMcQueueInner < private:: Owned < T , N > > ;
197+
198+ /// MPMC queue with a capacity for a dynamic number of element
199+ pub type MpMcQueueView < T > = private:: MpMcQueueInner < private:: View < T > > ;
139200
140201impl < T , const N : usize > MpMcQueue < T , N > {
141- const MASK : UintSize = ( N - 1 ) as UintSize ;
142202 const EMPTY_CELL : Cell < T > = Cell :: new ( 0 ) ;
143203
144204 const ASSERT : [ ( ) ; 1 ] = [ ( ) ] ;
@@ -170,7 +230,66 @@ impl<T, const N: usize> MpMcQueue<T, N> {
170230
171231 /// Returns the item in the front of the queue, or `None` if the queue is empty
172232 pub fn dequeue ( & self ) -> Option < T > {
173- unsafe { dequeue ( self . buffer . get ( ) as * mut _ , & self . dequeue_pos , Self :: MASK ) }
233+ self . as_view ( ) . dequeue ( )
234+ }
235+
236+ /// Adds an `item` to the end of the queue
237+ ///
238+ /// Returns back the `item` if the queue is full
239+ pub fn enqueue ( & self , item : T ) -> Result < ( ) , T > {
240+ self . as_view ( ) . enqueue ( item)
241+ }
242+
243+ /// Get a reference to the `MpMcQueue`, erasing the `N` const-generic.
244+ ///
245+ /// ```rust
246+ /// # use heapless::mpmc::{MpMcQueue, MpMcQueueView, Q2};
247+ /// let q: MpMcQueue<u8, 2> = Q2::new();
248+ /// let view: &MpMcQueueView<u8> = q.as_view();
249+ /// ```
250+ ///
251+ /// It is often preferable to do the same through type coerction, since `MpMcQueue<T, N>` implements `Unsize<MpMcQueue<T>>`:
252+ ///
253+ /// ```rust
254+ /// # use heapless::mpmc::{MpMcQueue, MpMcQueueView, Q2};
255+ /// let q: MpMcQueue<u8, 2> = Q2::new();
256+ /// let view: &MpMcQueueView<u8> = &q;
257+ /// ```
258+ pub fn as_view ( & self ) -> & MpMcQueueView < T > {
259+ self
260+ }
261+
262+ /// Get a mutable reference to the `MpMcQueue`, erasing the `N` const-generic.
263+ ///
264+ /// ```rust
265+ /// # use heapless::mpmc::{MpMcQueue, MpMcQueueView, Q2};
266+ /// let mut q: MpMcQueue<u8, 2> = Q2::new();
267+ /// let view: &mut MpMcQueueView<u8> = q.as_mut_view();
268+ /// ```
269+ ///
270+ /// It is often preferable to do the same through type coerction, since `MpMcQueue<T, N>` implements `Unsize<MpMcQueue<T>>`:
271+ ///
272+ /// ```rust
273+ /// # use heapless::mpmc::{MpMcQueue, MpMcQueueView, Q2};
274+ /// let mut q: MpMcQueue<u8, 2> = Q2::new();
275+ /// let view: &mut MpMcQueueView<u8> = &mut q;
276+ /// ```
277+ pub fn as_mut_view ( & mut self ) -> & mut MpMcQueueView < T > {
278+ self
279+ }
280+ }
281+
282+ impl < T > MpMcQueueView < T > {
283+ fn mask ( & self ) -> UintSize {
284+ let ptr: * const [ ( ) ] = self . buffer . get ( ) as _ ;
285+ // SAFETY: There is no aliasing as () is zero-sized
286+ let slice: & [ ( ) ] = unsafe { & * ptr } ;
287+ ( slice. len ( ) - 1 ) as _
288+ }
289+
290+ /// Returns the item in the front of the queue, or `None` if the queue is empty
291+ pub fn dequeue ( & self ) -> Option < T > {
292+ unsafe { dequeue ( self . buffer . get ( ) as * mut _ , & self . dequeue_pos , self . mask ( ) ) }
174293 }
175294
176295 /// Adds an `item` to the end of the queue
@@ -181,7 +300,7 @@ impl<T, const N: usize> MpMcQueue<T, N> {
181300 enqueue (
182301 self . buffer . get ( ) as * mut _ ,
183302 & self . enqueue_pos ,
184- Self :: MASK ,
303+ self . mask ( ) ,
185304 item,
186305 )
187306 }
@@ -194,19 +313,16 @@ impl<T, const N: usize> Default for MpMcQueue<T, N> {
194313 }
195314}
196315
197- impl < T , const N : usize > Drop for MpMcQueue < T , N > {
316+ impl < B : private :: MpMcQueueBuffer + ? Sized > Drop for private :: MpMcQueueInner < B > {
198317 fn drop ( & mut self ) {
318+ let this = B :: as_mut_view ( self ) ;
199319 // drop all contents currently in the queue
200- while self . dequeue ( ) . is_some ( ) { }
320+ while this . dequeue ( ) . is_some ( ) { }
201321 }
202322}
203323
204324unsafe impl < T , const N : usize > Sync for MpMcQueue < T , N > where T : Send { }
205-
206- struct Cell < T > {
207- data : MaybeUninit < T > ,
208- sequence : AtomicTargetSize ,
209- }
325+ unsafe impl < T > Sync for MpMcQueueView < T > where T : Send { }
210326
211327impl < T > Cell < T > {
212328 const fn new ( seq : usize ) -> Self {
0 commit comments