1- //! # A fixed capacity Single Producer Single Consumer (SPSC) queue.
1+ //! A fixed capacity single-producer, single-consumer (SPSC) queue.
22//!
3- //! Implementation based on <https://www.codeproject.com/Articles/43510/Lock-Free-Single-Producer-Single-Consumer-Circular>
3+ //! Implementation based on <https://www.codeproject.com/Articles/43510/Lock-Free-Single-Producer-Single-Consumer-Circular>.
44//!
5- //! ## Portability
5+ //! # Portability
66//!
7- //! This module requires CAS atomic instructions which are not available on all architectures
8- //! ( e.g. ARMv6-M (`thumbv6m-none-eabi`) and MSP430 (`msp430-none-elf`) ). These atomics can be
7+ //! This module requires CAS atomic instructions which are not available on all architectures,
8+ //! e.g. ARMv6-M (`thumbv6m-none-eabi`) and MSP430 (`msp430-none-elf`). These atomics can be
99//! emulated however with [`portable-atomic`](https://crates.io/crates/portable-atomic), which is
1010//! enabled with the `cas` feature and is enabled by default for `thumbv6m-none-eabi` and `riscv32`
1111//! targets.
1212//!
13- //! ## Examples
13+ //! # Examples
1414//!
15- //! - [ Queue] can be used as a plain queue
15+ //! [` Queue` ] can be used as a plain queue.
1616//!
1717//! ```
1818//! use heapless::spsc::Queue;
1919//!
20- //! let mut rb : Queue<u8, 4> = Queue::new();
20+ //! let mut queue : Queue<u8, 4> = Queue::new();
2121//!
22- //! assert!(rb .enqueue(0).is_ok());
23- //! assert!(rb .enqueue(1).is_ok());
24- //! assert!(rb .enqueue(2).is_ok());
25- //! assert!(rb .enqueue(3).is_err()); // full
22+ //! assert!(queue .enqueue(0).is_ok());
23+ //! assert!(queue .enqueue(1).is_ok());
24+ //! assert!(queue .enqueue(2).is_ok());
25+ //! assert!(queue .enqueue(3).is_err()); // Queue is full.
2626//!
27- //! assert_eq!(rb .dequeue(), Some(0));
27+ //! assert_eq!(queue .dequeue(), Some(0));
2828//! ```
2929//!
30- //! - [ Queue] can be [`Queue:: split`] and then be used in Single Producer Single Consumer mode.
30+ //! [` Queue` ] can be [`split`](QueueInner::split) and then be used in single-producer, single-consumer mode.
3131//!
3232//! "no alloc" applications can create a `&'static mut` reference to a `Queue` -- using a static
33- //! variable -- and then `split` it: this consumes the static reference. The resulting `Consumer`
34- //! and `Producer` can then be moved into different execution contexts (threads, interrupt handlers,
35- //! etc.).
36- //!
37- //! Alternatively, you can also create the Queue statically in the global scope by wrapping it with
38- //! a [static_cell](https://docs.rs/static_cell/latest/static_cell/)
39- //!
33+ //! variable and then `split` it, which consumes the static reference. The resulting `Producer`
34+ //! and `Consumer` can then be moved into different execution contexts, e.g. threads, interrupt handlers,
35+ //! etc.
4036//!
4137//! ```
4238//! use heapless::spsc::{Producer, Queue};
4339//!
40+ //! #[derive(Debug)]
4441//! enum Event {
4542//! A,
4643//! B,
4744//! }
4845//!
4946//! fn main() {
50- //! // Alternatively, use something like `static_cell` to create the `Queue` in the global
51- //! // scope.
5247//! let queue: &'static mut Queue<Event, 4> = {
5348//! static mut Q: Queue<Event, 4> = Queue::new();
5449//! // SAFETY: `Q` is only accessible in this scope
5954//! let (producer, mut consumer) = queue.split();
6055//!
6156//! // `producer` can be moved into `interrupt_handler` using a static mutex or the mechanism
62- //! // provided by the concurrency framework you are using (e.g. a resource in RTIC)
57+ //! // provided by the concurrency framework you are using, e.g. a resource in RTIC.
58+ //! # let mut producer = producer;
59+ //! # interrupt_handler(&mut producer);
6360//!
6461//! loop {
6562//! match consumer.dequeue() {
6663//! Some(Event::A) => { /* .. */ }
6764//! Some(Event::B) => { /* .. */ }
68- //! None => { /* sleep */ }
65+ //! None => { /* Sleep. */ }
6966//! }
7067//! # break
7168//! }
7269//! }
7370//!
74- //! // this is a different execution context that can preempt `main`
71+ //! // This is a different execution context that can preempt `main`.
7572//! fn interrupt_handler(producer: &mut Producer<'static, Event, 4>) {
7673//! # let condition = true;
7774//!
7875//! // ..
7976//!
8077//! if condition {
81- //! producer.enqueue(Event::A).ok(). unwrap();
78+ //! producer.enqueue(Event::A).unwrap();
8279//! } else {
83- //! producer.enqueue(Event::B).ok(). unwrap();
80+ //! producer.enqueue(Event::B).unwrap();
8481//! }
8582//!
8683//! // ..
8986//!
9087//! # Benchmarks
9188//!
92- //! Measured on a ARM Cortex-M3 core running at 8 MHz and with zero Flash wait cycles
89+ //! Measured on an ARM Cortex-M3 core running at 8 MHz and with zero flash wait cycles, compiled with `-C opt-level=3`:
9390//!
94- //! `-C opt-level` |`3` |
95- //! -----------------------|---|
96- //! `Consumer <u8>::dequeue`| 15 |
97- //! `Queue<u8>::dequeue ` | 12 |
98- //! `Producer <u8>::enqueue`| 16 |
99- //! `Queue<u8>::enqueue ` | 14 |
91+ //! Method | Time |
92+ //! ------------------------ |-----: |
93+ //! `Producer <u8>::enqueue` | 16 |
94+ //! `Queue<u8>::enqueue ` | 14 |
95+ //! `Consumer <u8>::dequeue` | 15 |
96+ //! `Queue<u8>::dequeue ` | 12 |
10097//!
10198//! - All execution times are in clock cycles. 1 clock cycle = 125 ns.
102- //! - Execution time is *dependent* of `mem::size_of::<T>()`. Both operations include one
103- //! `memcpy(T)` in their successful path.
104- //! - The optimization level is indicated in the first row.
105- //! - The numbers reported correspond to the successful path (i.e. `Some` is returned by `dequeue`
106- //! and `Ok` is returned by `enqueue`).
99+ //! - Execution time is *dependent* on `mem::size_of::<T>()`, as both operations include
100+ //! `ptr::read::<T>()` or `ptr::write::<T>()` in their successful path.
101+ //! - The numbers reported correspond to the successful path, i.e. `Some` is returned by `dequeue`
102+ //! and `Ok` is returned by `enqueue`.
107103
108104use core:: { borrow:: Borrow , cell:: UnsafeCell , fmt, hash, mem:: MaybeUninit , ptr} ;
109105
@@ -130,16 +126,15 @@ pub struct QueueInner<T, S: Storage> {
130126 pub ( crate ) buffer : S :: Buffer < UnsafeCell < MaybeUninit < T > > > ,
131127}
132128
133- /// A statically allocated single producer, single consumer queue with a capacity of `N - 1` elements.
129+ /// A statically allocated single- producer, single- consumer queue with a capacity of `N - 1` elements.
134130///
135- /// >
136131/// <div class="warning">
137132///
138133/// To get better performance use a value for `N` that is a power of 2, e.g. 16, 32, etc.
139134///
140135/// </div>
141136///
142- /// You will likely want to use [`split`](QueueInner::split) to create a producer and consumer handle .
137+ /// You will likely want to use [`split`](QueueInner::split) to create a producer- consumer pair .
143138pub type Queue < T , const N : usize > = QueueInner < T , OwnedStorage < N > > ;
144139
145140/// A [`Queue`] with dynamic capacity.
0 commit comments