Skip to main content

Crate quetzalcoatl

Crate quetzalcoatl 

Source
Expand description

Lock-free ring buffers for high-performance concurrent communication.

Quetzalcoatl provides four ring buffer variants, each optimized for a different producer/consumer topology:

ModuleProducersConsumersBest for
spscSingleSinglePipelines, audio, networking
mpscMultipleSingleFan-in from worker threads
spmcSingleMultipleWork distribution / fan-out
broadcastMultipleMultiplePub/sub, event distribution

All variants are fully lock-free (no mutexes), use fixed-size power-of-two buffers, and provide both a cloning pop() and a zero-copy pop_ref() / reserve()write()commit() API.

§Quick start

Every buffer follows the same pattern: create a capacity::Capacity, construct the ring buffer, and split() into producer + consumer handles.

§MPSC (multi-producer, single-consumer)

use quetzalcoatl::mpsc::RingBuffer;
use quetzalcoatl::capacity::Capacity;

let (producer, mut consumer) = RingBuffer::new(Capacity::exact(64)).split();

// Clone the producer for multiple threads
let p2 = producer.clone();
let handle = std::thread::spawn(move || { p2.push(1u64).unwrap(); });

producer.push(2).unwrap();
handle.join().unwrap();

let mut values = vec![];
while let Some(v) = consumer.pop() { values.push(v); }
assert!(values.contains(&1));
assert!(values.contains(&2));

§SPSC (single-producer, single-consumer)

use quetzalcoatl::spsc::RingBuffer;
use quetzalcoatl::capacity::Capacity;

let (producer, mut consumer) = RingBuffer::new(Capacity::exact(64)).split();

producer.push(42u64).unwrap();
assert_eq!(consumer.pop(), Some(42));

§SPMC (single-producer, multiple-consumer)

use quetzalcoatl::spmc::RingBuffer;
use quetzalcoatl::capacity::Capacity;

let (producer, consumer) = RingBuffer::new(Capacity::exact(64)).split();

// Clone the consumer for multiple threads
let c2 = consumer.clone();
std::thread::spawn(move || { assert!(c2.pop().is_some()); });

producer.push(1u64).unwrap();
producer.push(2).unwrap();

// Each item is consumed by exactly one consumer

§Broadcast (multi-producer, multi-consumer)

Every consumer sees every item published after it subscribes.

use quetzalcoatl::broadcast::RingBuffer;
use quetzalcoatl::capacity::Capacity;

// max_consumers = 4
let (producer, mut c1) = RingBuffer::new(Capacity::exact(64), 4).split();
let mut c2 = c1.clone(); // new consumer, sees future items

producer.push(99u64).unwrap();

assert_eq!(c1.pop(), Some(99));
assert_eq!(c2.pop(), Some(99)); // both see the same item

§Zero-copy API

For large types, avoid copying with reserve() (producer) and pop_ref() (consumer). The reserve() API uses a typestate patternwrite() consumes the SlotWriter and returns a WrittenSlot that can be safely committed:

use quetzalcoatl::spsc::RingBuffer;
use quetzalcoatl::capacity::Capacity;

let (mut producer, mut consumer) = RingBuffer::<[u8; 4096]>::new(Capacity::exact(4)).split();

// Write directly into the slot
let writer = producer.reserve().unwrap();
writer.write([0xAB; 4096]).commit();

// Read without copying
let reader = consumer.pop_ref().unwrap();
assert_eq!(reader[0], 0xAB);
// slot is released when `reader` drops

§Choosing a buffer type

  • spsc: Lowest overhead. No atomics on the hot path beyond a single Acquire/Release pair. Use when you have exactly one producer and one consumer.

  • mpsc: Multiple producers claim slots via fetch-and-add (FAA), eliminating inter-producer contention on the tail pointer. Single consumer pops lock-free. Use for fan-in patterns (many writers, one reader). For high-throughput bulk consumption, use mpsc::Consumer::drain which amortizes the head pointer update across an entire batch.

  • spmc: Single producer writes lock-free. Multiple consumers share a CAS loop to claim items. Each item goes to exactly one consumer. Use for work-distribution / fan-out patterns.

  • broadcast: Multiple producers (FAA) and multiple consumers. Each consumer maintains its own read cursor. Items require T: Clone for pop(), or use pop_ref() for zero-copy reads. Use for pub/sub or event fan-out. For large types with many consumers, see broadcast::arc::ArcRingBuffer which wraps values in Arc<T> for O(1) consumer clones.

Modules§

broadcast
Multi-producer, multi-consumer (MPMC) broadcast ring buffer.
capacity
mpmc
Multi-producer, multi-consumer ring with relaxed-FIFO ordering.
mpsc
Multi-producer, single-consumer (MPSC) lock-free ring buffer.
spmc
Single-producer, multiple-consumer (SPMC) lock-free ring buffer.
spsc
Single-producer, single-consumer (SPSC) lock-free ring buffer.