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//!
9//! # Quick Start
10//!
11//! ```
12//! // SPSC - one producer, one consumer
13//! use nexus_queue::spsc;
14//!
15//! let (mut tx, mut rx) = spsc::ring_buffer::<u64>(1024);
16//! tx.push(42).unwrap();
17//! assert_eq!(rx.pop(), Some(42));
18//! ```
19//!
20//! ```
21//! // MPSC - multiple producers, one consumer
22//! use nexus_queue::mpsc;
23//!
24//! let (mut tx, mut rx) = mpsc::bounded::<u64>(1024);
25//! let mut tx2 = tx.clone(); // Clone for second producer
26//!
27//! tx.push(1).unwrap();
28//! tx2.push(2).unwrap();
29//!
30//! assert!(rx.pop().is_some());
31//! assert!(rx.pop().is_some());
32//! ```
33//!
34//! # Design
35//!
36//! ## SPSC
37//!
38//! Uses cached head/tail indices with separate cache lines to avoid false sharing.
39//! Producer and consumer each maintain a local copy of the other's index, only
40//! refreshing from the atomic when their cache indicates the queue is full
41//! (producer) or empty (consumer).
42//!
43//! ## MPSC
44//!
45//! Uses CAS-based slot claiming with Vyukov-style turn counters. Producers compete
46//! via CAS on the tail index, then wait for their slot's turn counter before
47//! writing. This provides backpressure (try_push fails when full) without blocking.
48//!
49//! Both designs perform well on multi-socket NUMA systems where cache line
50//! ownership is important for latency.
51
52#![deny(unsafe_op_in_unsafe_fn)]
53#![warn(missing_docs, missing_debug_implementations)]
54
55use core::fmt;
56
57pub mod mpsc;
58pub mod spsc;
59
60/// Error returned when pushing to a full queue.
61///
62/// Contains the value that could not be pushed, returning ownership to the caller.
63#[derive(Debug, Clone, Copy, PartialEq, Eq)]
64pub struct Full<T>(pub T);
65
66impl<T> Full<T> {
67 /// Returns the value that could not be pushed.
68 pub fn into_inner(self) -> T {
69 self.0
70 }
71}
72
73impl<T> fmt::Display for Full<T> {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 write!(f, "queue is full")
76 }
77}
78
79impl<T: fmt::Debug> std::error::Error for Full<T> {}