ringbuf/lib.rs
1//! Lock-free SPSC FIFO ring buffer with direct access to inner data.
2//!
3//! # Usage
4//!
5//! At first you need to create the ring buffer itself. [`HeapRb`] is recommended but you may [choose another one](#types).
6//!
7//! After the ring buffer is created it may be splitted into pair of [`Producer`](`traits::Producer`) and [`Consumer`](`traits::Consumer`).
8//! Producer is used to insert items to the ring buffer, consumer - to remove items from it.
9//!
10//! # Types
11//!
12//! There are several types of ring buffers provided:
13//!
14//! + [`LocalRb`]. Only for single-threaded use.
15//! + [`SharedRb`]. Can be shared between threads. Its frequently used instances:
16//! + [`HeapRb`]. Contents are stored in dynamic memory. *Recommended for use in most cases.*
17//! + [`StaticRb`]. Contents can be stored in statically-allocated memory.
18//!
19//! You may also provide your own generic parameters.
20//!
21//! # Performance
22//!
23//! [`SharedRb`] needs to synchronize CPU cache between CPU cores. This synchronization has some overhead.
24//! To avoid multiple unnecessary synchronizations you may use methods that operate many items at once
25//! ([`push_slice`](`traits::Producer::push_slice`)/[`push_iter`](`traits::Producer::push_iter`), [`pop_slice`](`traits::Consumer::pop_slice`)/[`pop_iter`](`traits::Consumer::pop_iter`), etc.)
26//! or you can `freeze` [producer](`Prod::freeze`) or [consumer](`Cons::freeze`) and then synchronize threads manually (see items in [`frozen`](`wrap::frozen`) module).
27//!
28//! For single-threaded usage [`LocalRb`] is recommended because it is slightly faster than [`SharedRb`] due to absence of CPU cache synchronization.
29//!
30//! # Examples
31//!
32#![cfg_attr(
33 feature = "alloc",
34 doc = r##"
35## Simple
36
37```rust
38use ringbuf::{traits::*, HeapRb};
39
40# fn main() {
41let rb = HeapRb::<i32>::new(2);
42let (mut prod, mut cons) = rb.split();
43
44prod.try_push(0).unwrap();
45prod.try_push(1).unwrap();
46assert_eq!(prod.try_push(2), Err(2));
47
48assert_eq!(cons.try_pop(), Some(0));
49
50prod.try_push(2).unwrap();
51
52assert_eq!(cons.try_pop(), Some(1));
53assert_eq!(cons.try_pop(), Some(2));
54assert_eq!(cons.try_pop(), None);
55# }
56```
57"##
58)]
59#![doc = r##"
60## No heap
61
62```rust
63use ringbuf::{traits::*, StaticRb};
64
65# fn main() {
66const RB_SIZE: usize = 1;
67let mut rb = StaticRb::<i32, RB_SIZE>::default();
68let (mut prod, mut cons) = rb.split_ref();
69
70assert_eq!(prod.try_push(123), Ok(()));
71assert_eq!(prod.try_push(321), Err(321));
72
73assert_eq!(cons.try_pop(), Some(123));
74assert_eq!(cons.try_pop(), None);
75# }
76```
77"##]
78# requires exclusive access to the ring buffer
102so to perform it concurrently you need to guard the ring buffer with mutex or some other lock.
103"##
104)]
105//!
106//! # Implementation details
107//!
108//! Each ring buffer here consists of the following parts:
109//!
110//! + Storage
111//! + Indices
112//! + Hold flags
113//!
114//! ## Storage
115//!
116//! [`Storage`](`storage::Storage`) is a place where ring buffer items are actually stored.
117//! It must span a single contiguous memory area (e.g. we can obtain a slice or subslice of it).
118//! Ring buffer can own its storage or it can hold only a mutable reference to it.
119//! Storage length is refered as `capacity`.
120//!
121//! ## Indices
122//!
123//! Ring buffer also contains two indices: `read` and `write`.
124//!
125//! `read % capacity` points to the oldest item in the storage.
126//! `write % capacity` points to empty slot next to the most recently inserted item.
127//!
128//! When an item is extracted from the ring buffer it is taken from the `read % capacity` slot and then `read` index is incremented.
129//! New item is put into the `write % capacity` slot and `write` index is incremented after that.
130//!
131//! Slots with indices between (in modular arithmetic) `(read % capacity)` (including) and
132//! `(write % capacity)` (excluding) contain items (are initialized).
133//! All other slots do not contain items (are uninitialized).
134//!
135//! The actual values of `read` and `write` indices are modulo `2 * capacity` instead of just `capacity`.
136//! It allows us to distinguish situations when the buffer is empty (`read == write`)
137//! and when the buffer is full (`(write - read) % (2 * capacity) == capacity`)
138//! without using an extra slot in container that cannot be occupied.
139//!
140//! But this causes the existense of invalid combinations of indices.
141//! For example, we cannot store more than `capacity` items in the buffer,
142//! so `(write - read) % (2 * capacity)` is not allowed to be greater than `capacity`.
143//!
144//! ## Hold flags
145//!
146//! Ring buffer can have at most one producer and at most one consumer at the same time.
147//! These flags indicates whether it's safe to obtain a new producer or a consumer.
148//!
149#![no_std]
150#![allow(clippy::type_complexity)]
151#![cfg_attr(feature = "bench", feature(test))]
152
153#[cfg(feature = "alloc")]
154extern crate alloc;
155#[cfg(feature = "std")]
156extern crate std;
157
158/// Shortcuts for frequently used types.
159mod alias;
160/// Ring buffer implementations.
161pub mod rb;
162/// Storage types.
163pub mod storage;
164/// Ring buffer traits.
165pub mod traits;
166/// Items transfer between ring buffers.
167mod transfer;
168/// Internal utilities.
169mod utils;
170/// Producer and consumer implementations.
171pub mod wrap;
172
173#[cfg(test)]
174mod tests;
175
176pub use alias::*;
177pub use rb::{LocalRb, SharedRb};
178pub use traits::{consumer, producer};
179pub use transfer::transfer;
180pub use wrap::{CachingCons, CachingProd, Cons, Obs, Prod};
181
182#[cfg(feature = "bench")]
183extern crate test;
184#[cfg(feature = "bench")]
185mod benchmarks;