Skip to main content

nexus_queue/
lib.rs

1//! High-performance lock-free queues for latency-critical applications.
2//!
3//! `nexus-queue` provides bounded queues optimized for trading systems and other
4//! low-latency workloads:
5//!
6//! - [`spsc`]: Single-producer single-consumer queue with cached indices
7//! - [`mpsc`]: Multi-producer single-consumer queue with Vyukov-style turn counters
8//! - [`spmc`]: Single-producer multi-consumer queue for fan-out workloads
9//!
10//! # Quick Start
11//!
12//! ```
13//! // SPSC - one producer, one consumer
14//! use nexus_queue::spsc;
15//!
16//! let (mut tx, mut rx) = spsc::ring_buffer::<u64>(1024);
17//! tx.push(42).unwrap();
18//! assert_eq!(rx.pop(), Some(42));
19//! ```
20//!
21//! ```
22//! // MPSC - multiple producers, one consumer
23//! use nexus_queue::mpsc;
24//!
25//! let (mut tx, mut rx) = mpsc::bounded::<u64>(1024);
26//! let mut tx2 = tx.clone();  // Clone for second producer
27//!
28//! tx.push(1).unwrap();
29//! tx2.push(2).unwrap();
30//!
31//! assert!(rx.pop().is_some());
32//! assert!(rx.pop().is_some());
33//! ```
34//!
35//! ```
36//! // SPMC - one producer, multiple consumers
37//! use nexus_queue::spmc;
38//!
39//! let (mut tx, mut rx) = spmc::bounded::<u64>(1024);
40//! let mut rx2 = rx.clone();  // Clone for second consumer
41//!
42//! tx.push(1).unwrap();
43//! tx.push(2).unwrap();
44//!
45//! // Each value consumed by exactly one consumer
46//! assert!(rx.pop().is_some());
47//! assert!(rx2.pop().is_some());
48//! ```
49//!
50//! # Design
51//!
52//! ## SPSC
53//!
54//! Uses cached head/tail indices with separate cache lines to avoid false sharing.
55//! Producer and consumer each maintain a local copy of the other's index, only
56//! refreshing from the atomic when their cache indicates the queue is full
57//! (producer) or empty (consumer).
58//!
59//! ## MPSC
60//!
61//! Uses CAS-based slot claiming with Vyukov-style turn counters. Producers compete
62//! via CAS on the tail index, then wait for their slot's turn counter before
63//! writing. This provides backpressure (try_push fails when full) without blocking.
64//!
65//! ## SPMC
66//!
67//! Mirror of MPSC with roles swapped. The single producer writes directly (no CAS),
68//! while consumers compete via CAS on the head index. Eliminates producer-side
69//! contention for fan-out workloads like 1 IO thread → N parser threads.
70//!
71//! All designs perform well on multi-socket NUMA systems where cache line
72//! ownership is important for latency.
73
74#![deny(unsafe_op_in_unsafe_fn)]
75#![warn(missing_docs, missing_debug_implementations)]
76
77use core::fmt;
78
79pub mod mpsc;
80pub mod spmc;
81pub mod spsc;
82
83/// Error returned when pushing to a full queue.
84///
85/// Contains the value that could not be pushed, returning ownership to the caller.
86#[derive(Debug, Clone, Copy, PartialEq, Eq)]
87pub struct Full<T>(pub T);
88
89impl<T> Full<T> {
90    /// Returns the value that could not be pushed.
91    pub fn into_inner(self) -> T {
92        self.0
93    }
94}
95
96impl<T> fmt::Display for Full<T> {
97    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98        write!(f, "queue is full")
99    }
100}
101
102impl<T: fmt::Debug> std::error::Error for Full<T> {}