Expand description
Fixed capacity Single Producer Single Consumer (SPSC) queue
Implementation based on https://www.codeproject.com/Articles/43510/Lock-Free-Single-Producer-Single-Consumer-Circular
§Portability
This module requires CAS atomic instructions which are not available on all architectures
(e.g.  ARMv6-M (thumbv6m-none-eabi) and MSP430 (msp430-none-elf)). These atomics can be
emulated however with portable-atomic, which is
enabled with the cas feature and is enabled by default for thumbv6m-none-eabi and riscv32
targets.
§Examples
Queuecan be used as a plain queue
use heapless::spsc::Queue;
let mut rb: Queue<u8, 4> = Queue::new();
assert!(rb.enqueue(0).is_ok());
assert!(rb.enqueue(1).is_ok());
assert!(rb.enqueue(2).is_ok());
assert!(rb.enqueue(3).is_err()); // full
assert_eq!(rb.dequeue(), Some(0));Queuecan besplitand then be used in Single Producer Single Consumer mode.
“no alloc” applications can create a &'static mut reference to a Queue – using a static
variable – and then split it: this consumes the static reference. The resulting Consumer
and Producer can then be moved into different execution contexts (threads, interrupt handlers,
etc.)
use heapless::spsc::{Producer, Queue};
enum Event { A, B }
fn main() {
    let queue: &'static mut Queue<Event, 4> = {
        static mut Q: Queue<Event, 4> = Queue::new();
        unsafe { &mut Q }
    };
    let (producer, mut consumer) = queue.split();
    // `producer` can be moved into `interrupt_handler` using a static mutex or the mechanism
    // provided by the concurrency framework you are using (e.g. a resource in RTIC)
    loop {
        match consumer.dequeue() {
            Some(Event::A) => { /* .. */ },
            Some(Event::B) => { /* .. */ },
            None => { /* sleep */ },
        }
    }
}
// this is a different execution context that can preempt `main`
fn interrupt_handler(producer: &mut Producer<'static, Event, 4>) {
    // ..
    if condition {
        producer.enqueue(Event::A).ok().unwrap();
    } else {
        producer.enqueue(Event::B).ok().unwrap();
    }
    // ..
}§Benchmarks
Measured on a ARM Cortex-M3 core running at 8 MHz and with zero Flash wait cycles
-C opt-level | 3 | 
|---|---|
Consumer<u8>::dequeue | 15 | 
Queue<u8>::dequeue | 12 | 
Producer<u8>::enqueue | 16 | 
Queue<u8>::enqueue | 14 | 
- All execution times are in clock cycles. 1 clock cycle = 125 ns.
 - Execution time is dependent of 
mem::size_of::<T>(). Both operations include onememcpy(T)in their successful path. - The optimization level is indicated in the first row.
 - The numbers reported correspond to the successful path (i.e. 
Someis returned bydequeueandOkis returned byenqueue). 
Structs§
- A queue “consumer”; it can dequeue items from the queue NOTE the consumer semantically owns the
headpointer of the queue - An iterator over the items of a queue
 - A mutable iterator over the items of a queue
 - A queue “producer”; it can enqueue items into the queue NOTE the producer semantically owns the
tailpointer of the queue - A statically allocated single producer single consumer queue with a capacity of
N - 1elements