51
51
//! // scope.
52
52
//! let queue: &'static mut Queue<Event, 4> = {
53
53
//! static mut Q: Queue<Event, 4> = Queue::new();
54
+ //! // SAFETY: `Q` is only accessible in this scope
55
+ //! // and `main` is only called once.
54
56
//! unsafe { &mut Q }
55
57
//! };
56
58
//!
@@ -128,16 +130,21 @@ pub struct QueueInner<T, S: Storage> {
128
130
pub ( crate ) buffer : S :: Buffer < UnsafeCell < MaybeUninit < T > > > ,
129
131
}
130
132
131
- /// A statically allocated single producer single consumer queue with a capacity of `N - 1` elements
133
+ /// A statically allocated single producer, single consumer queue with a capacity of `N - 1` elements.
132
134
///
133
- /// *IMPORTANT*: To get better performance use a value for `N` that is a power of 2 (e.g. `16`, `32`,
134
- /// etc.).
135
+ /// >
136
+ /// <div class="warning">
137
+ ///
138
+ /// To get better performance use a value for `N` that is a power of 2, e.g. 16, 32, etc.
139
+ ///
140
+ /// </div>
141
+ ///
142
+ /// You will likely want to use [`split`](QueueInner::split) to create a producer and consumer handle.
135
143
pub type Queue < T , const N : usize > = QueueInner < T , OwnedStorage < N > > ;
136
144
137
- /// Asingle producer single consumer queue
145
+ /// A [`Queue`] with dynamic capacity.
138
146
///
139
- /// *IMPORTANT*: To get better performance use a value for `N` that is a power of 2 (e.g. `16`, `32`,
140
- /// etc.).
147
+ /// [`Queue`] coerces to `QueueView`. `QueueView` is `!Sized`, meaning it can only ever be used by reference.
141
148
pub type QueueView < T > = QueueInner < T , ViewStorage > ;
142
149
143
150
impl < T , const N : usize > Queue < T , N > {
@@ -362,8 +369,110 @@ impl<T, S: Storage> QueueInner<T, S> {
362
369
self . inner_dequeue_unchecked ( )
363
370
}
364
371
365
- /// Splits a queue into producer and consumer endpoints
366
- pub fn split ( & mut self ) -> ( ProducerInner < ' _ , T , S > , ConsumerInner < ' _ , T , S > ) {
372
+ /// Splits a queue into producer and consumer endpoints.
373
+ ///
374
+ /// # Examples
375
+ ///
376
+ /// Create a queue at compile time, split it at runtime,
377
+ /// and pass it to an interrupt handler via a mutex.
378
+ ///
379
+ /// ```
380
+ /// use core::cell::RefCell;
381
+ /// use critical_section::Mutex;
382
+ /// use heapless::spsc::{Producer, Queue};
383
+ ///
384
+ /// static PRODUCER: Mutex<RefCell<Option<Producer<'static, (), 4>>>> =
385
+ /// Mutex::new(RefCell::new(None));
386
+ ///
387
+ /// fn interrupt() {
388
+ /// let mut producer = {
389
+ /// static mut P: Option<Producer<'static, (), 4>> = None;
390
+ /// // SAFETY: Mutable access to `P` is allowed exclusively in this scope
391
+ /// // and `interrupt` cannot be called directly or preempt itself.
392
+ /// unsafe { &mut P }
393
+ /// }
394
+ /// .get_or_insert_with(|| {
395
+ /// critical_section::with(|cs| PRODUCER.borrow_ref_mut(cs).take().unwrap())
396
+ /// });
397
+ ///
398
+ /// producer.enqueue(()).unwrap();
399
+ /// }
400
+ ///
401
+ /// fn main() {
402
+ /// let mut consumer = {
403
+ /// let (p, c) = {
404
+ /// static mut Q: Queue<(), 4> = Queue::new();
405
+ /// // SAFETY: `Q` is only accessible in this scope
406
+ /// // and `main` is only called once.
407
+ /// #[allow(static_mut_refs)]
408
+ /// unsafe {
409
+ /// Q.split()
410
+ /// }
411
+ /// };
412
+ ///
413
+ /// critical_section::with(move |cs| {
414
+ /// let mut producer = PRODUCER.borrow_ref_mut(cs);
415
+ /// *producer = Some(p);
416
+ /// });
417
+ ///
418
+ /// c
419
+ /// };
420
+ ///
421
+ /// // Interrupt occurs.
422
+ /// # interrupt();
423
+ ///
424
+ /// consumer.dequeue().unwrap();
425
+ /// }
426
+ /// ```
427
+ ///
428
+ /// Create and split a queue at compile time, and pass it to the main
429
+ /// function and an interrupt handler via a mutex at runtime.
430
+ ///
431
+ /// ```
432
+ /// use core::cell::RefCell;
433
+ ///
434
+ /// use critical_section::Mutex;
435
+ /// use heapless::spsc::{Consumer, Producer, Queue};
436
+ ///
437
+ /// static PC: (
438
+ /// Mutex<RefCell<Option<Producer<'_, (), 4>>>>,
439
+ /// Mutex<RefCell<Option<Consumer<'_, (), 4>>>>,
440
+ /// ) = {
441
+ /// static mut Q: Queue<(), 4> = Queue::new();
442
+ /// // SAFETY: `Q` is only accessible in this scope.
443
+ /// #[allow(static_mut_refs)]
444
+ /// let (p, c) = unsafe { Q.split() };
445
+ ///
446
+ /// (
447
+ /// Mutex::new(RefCell::new(Some(p))),
448
+ /// Mutex::new(RefCell::new(Some(c))),
449
+ /// )
450
+ /// };
451
+ ///
452
+ /// fn interrupt() {
453
+ /// let mut producer = {
454
+ /// static mut P: Option<Producer<'_, (), 4>> = None;
455
+ /// // SAFETY: Mutable access to `P` is allowed exclusively in this scope
456
+ /// // and `interrupt` cannot be called directly or preempt itself.
457
+ /// unsafe { &mut P }
458
+ /// }
459
+ /// .get_or_insert_with(|| {
460
+ /// critical_section::with(|cs| PC.0.borrow_ref_mut(cs).take().unwrap())
461
+ /// });
462
+ ///
463
+ /// producer.enqueue(()).unwrap();
464
+ /// }
465
+ ///
466
+ /// fn main() {
467
+ /// let mut consumer = critical_section::with(|cs| PC.1.borrow_ref_mut(cs).take().unwrap());
468
+ ///
469
+ /// // Interrupt occurs.
470
+ /// # interrupt();
471
+ ///
472
+ /// consumer.dequeue().unwrap();
473
+ /// }
474
+ /// ```
475
+ pub const fn split ( & mut self ) -> ( ProducerInner < ' _ , T , S > , ConsumerInner < ' _ , T , S > ) {
367
476
( ProducerInner { rb : self } , ConsumerInner { rb : self } )
368
477
}
369
478
}
@@ -382,9 +491,9 @@ where
382
491
let mut new: Self = Self :: new ( ) ;
383
492
384
493
for s in self . iter ( ) {
494
+ // SAFETY: `new.capacity() == self.capacity() >= self.len()`,
495
+ // so no overflow is possible.
385
496
unsafe {
386
- // NOTE(unsafe) new.capacity() == self.capacity() >= self.len()
387
- // no overflow possible
388
497
new. enqueue_unchecked ( s. clone ( ) ) ;
389
498
}
390
499
}
@@ -744,6 +853,38 @@ mod tests {
744
853
// Ensure a `Consumer` containing `!Send` values stays `!Send` itself.
745
854
assert_not_impl_any ! ( Consumer <* const ( ) , 4 >: Send ) ;
746
855
856
+ #[ test]
857
+ fn const_split ( ) {
858
+ use critical_section:: Mutex ;
859
+ use std:: cell:: RefCell ;
860
+
861
+ use super :: { Consumer , Producer } ;
862
+
863
+ #[ allow( clippy:: type_complexity) ]
864
+ static PC : (
865
+ Mutex < RefCell < Option < Producer < ' _ , ( ) , 4 > > > > ,
866
+ Mutex < RefCell < Option < Consumer < ' _ , ( ) , 4 > > > > ,
867
+ ) = {
868
+ static mut Q : Queue < ( ) , 4 > = Queue :: new ( ) ;
869
+ // SAFETY: `Q` is only accessible in this scope.
870
+ #[ allow( static_mut_refs) ]
871
+ let ( p, c) = unsafe { Q . split ( ) } ;
872
+
873
+ (
874
+ Mutex :: new ( RefCell :: new ( Some ( p) ) ) ,
875
+ Mutex :: new ( RefCell :: new ( Some ( c) ) ) ,
876
+ )
877
+ } ;
878
+ let producer = critical_section:: with ( |cs| PC . 0 . borrow_ref_mut ( cs) . take ( ) . unwrap ( ) ) ;
879
+ let consumer = critical_section:: with ( |cs| PC . 1 . borrow_ref_mut ( cs) . take ( ) . unwrap ( ) ) ;
880
+
881
+ let mut producer: Producer < ' static , ( ) , 4 > = producer;
882
+ let mut consumer: Consumer < ' static , ( ) , 4 > = consumer;
883
+
884
+ assert_eq ! ( producer. enqueue( ( ) ) , Ok ( ( ) ) ) ;
885
+ assert_eq ! ( consumer. dequeue( ) , Some ( ( ) ) ) ;
886
+ }
887
+
747
888
#[ test]
748
889
fn full ( ) {
749
890
let mut rb: Queue < i32 , 3 > = Queue :: new ( ) ;
0 commit comments