1 | //! Lock-free SPSC FIFO ring buffer with direct access to inner data. |
2 | //! |
3 | //! # Features |
4 | //! |
5 | //! + Lock-free operations - they succeed or fail immediately without blocking or waiting. |
6 | //! + Arbitrary item type (not only [`Copy`]). |
7 | //! + Items can be inserted and removed one by one or many at once. |
8 | //! + Thread-safe direct access to the internal ring buffer memory. |
9 | //! + [`Read`](`std::io::Read`) and [`Write`](`std::io::Write`) implementation. |
10 | //! + Can be used without `std` and even without `alloc` (using only statically-allocated memory). |
11 | //! + [Experimental `async`/`.await` support](https://github.com/agerasev/async-ringbuf). |
12 | //! |
13 | //! # Usage |
14 | //! |
15 | //! At first you need to create the ring buffer itself. [`HeapRb`] is recommended but you may [choose another one](#types). |
16 | //! |
17 | //! After the ring buffer is created it may be splitted into pair of [`Producer`] and [`Consumer`]. |
18 | //! [`Producer`] is used to insert items to the ring buffer, [`Consumer`] - to remove items from it. |
19 | //! For [`SharedRb`] and its derivatives they can be used in different threads. |
20 | //! |
21 | //! Also you can use the ring buffer without splitting at all via methods provided by [`Rb`] trait. |
22 | //! |
23 | //! # Types |
24 | //! |
25 | //! There are several types of ring buffers provided: |
26 | //! |
27 | //! + [`LocalRb`]. Only for single-threaded use. |
28 | //! + [`SharedRb`]. Can be shared between threads. Its derivatives: |
29 | //! + [`HeapRb`]. Contents are stored in dynamic memory. *Recommended for use in most cases.* |
30 | //! + [`StaticRb`]. Contents can be stored in statically-allocated memory. |
31 | //! |
32 | //! # Performance |
33 | //! |
34 | //! [`SharedRb`] needs to synchronize CPU cache between CPU cores. This synchronization has some overhead. |
35 | //! To avoid multiple unnecessary synchronizations you may use postponed mode of operation (see description for [`Producer#mode`] and [`Consumer#mode`]) |
36 | //! or methods that operate many items at once ([`Producer::push_slice`]/[`Producer::push_iter`], [`Consumer::pop_slice`], etc.). |
37 | //! |
38 | //! For single-threaded usage [`LocalRb`] is recommended because it is faster than [`SharedRb`] due to absence of CPU cache synchronization. |
39 | //! |
40 | //! ## Benchmarks |
41 | //! |
42 | //! You may see typical performance of different methods in benchmarks: |
43 | //! |
44 | //! ```bash |
45 | //! cargo +nightly bench --features bench |
46 | //! ``` |
47 | //! |
48 | //! Nightly toolchain is required. |
49 | //! |
50 | //! # Examples |
51 | //! |
52 | #![cfg_attr ( |
53 | feature = "alloc" , |
54 | doc = r##" |
55 | ## Simple |
56 | |
57 | ```rust |
58 | use ringbuf::HeapRb; |
59 | |
60 | # fn main() { |
61 | let rb = HeapRb::<i32>::new(2); |
62 | let (mut prod, mut cons) = rb.split(); |
63 | |
64 | prod.push(0).unwrap(); |
65 | prod.push(1).unwrap(); |
66 | assert_eq!(prod.push(2), Err(2)); |
67 | |
68 | assert_eq!(cons.pop(), Some(0)); |
69 | |
70 | prod.push(2).unwrap(); |
71 | |
72 | assert_eq!(cons.pop(), Some(1)); |
73 | assert_eq!(cons.pop(), Some(2)); |
74 | assert_eq!(cons.pop(), None); |
75 | # } |
76 | ``` |
77 | "## |
78 | )] |
79 | #![doc = r##" |
80 | ## No heap |
81 | |
82 | ```rust |
83 | use ringbuf::StaticRb; |
84 | |
85 | # fn main() { |
86 | const RB_SIZE: usize = 1; |
87 | let mut rb = StaticRb::<i32, RB_SIZE>::default(); |
88 | let (mut prod, mut cons) = rb.split_ref(); |
89 | |
90 | assert_eq!(prod.push(123), Ok(())); |
91 | assert_eq!(prod.push(321), Err(321)); |
92 | |
93 | assert_eq!(cons.pop(), Some(123)); |
94 | assert_eq!(cons.pop(), None); |
95 | # } |
96 | ``` |
97 | "## ] |
98 | #![cfg_attr ( |
99 | feature = "std" , |
100 | doc = r##" |
101 | ## Overwrite |
102 | |
103 | Ring buffer can be used in overwriting mode when insertion overwrites the latest element if the buffer is full. |
104 | |
105 | ```rust |
106 | use ringbuf::{HeapRb, Rb}; |
107 | |
108 | # fn main() { |
109 | let mut rb = HeapRb::<i32>::new(2); |
110 | |
111 | assert_eq!(rb.push_overwrite(0), None); |
112 | assert_eq!(rb.push_overwrite(1), None); |
113 | assert_eq!(rb.push_overwrite(2), Some(0)); |
114 | |
115 | assert_eq!(rb.pop(), Some(1)); |
116 | assert_eq!(rb.pop(), Some(2)); |
117 | assert_eq!(rb.pop(), None); |
118 | # } |
119 | ``` |
120 | |
121 | Note that [`push_overwrite`](`Rb::push_overwrite`) requires exclusive access to the ring buffer |
122 | so to perform it concurrently you need to guard the ring buffer with [`Mutex`](`std::sync::Mutex`) or some other lock. |
123 | "## |
124 | )] |
125 | //! ## `async`/`.await` |
126 | //! |
127 | //! There is an experimental crate [`async-ringbuf`](https://github.com/agerasev/async-ringbuf) |
128 | //! which is built on top of `ringbuf` and implements asynchronous ring buffer operations. |
129 | //! |
130 | #![no_std ] |
131 | #![cfg_attr (feature = "bench" , feature(test))] |
132 | |
133 | #[cfg (feature = "alloc" )] |
134 | extern crate alloc; |
135 | #[cfg (feature = "std" )] |
136 | extern crate std; |
137 | |
138 | mod alias; |
139 | mod utils; |
140 | |
141 | /// [`Consumer`] and additional types. |
142 | pub mod consumer; |
143 | /// [`Producer`] and additional types. |
144 | pub mod producer; |
145 | /// Ring buffer traits and implementations. |
146 | pub mod ring_buffer; |
147 | mod transfer; |
148 | |
149 | #[cfg (feature = "alloc" )] |
150 | pub use alias::{HeapConsumer, HeapProducer, HeapRb}; |
151 | pub use alias::{StaticConsumer, StaticProducer, StaticRb}; |
152 | pub use consumer::Consumer; |
153 | pub use producer::Producer; |
154 | pub use ring_buffer::{LocalRb, Rb, SharedRb}; |
155 | pub use transfer::transfer; |
156 | |
157 | #[cfg (test)] |
158 | mod tests; |
159 | |
160 | #[cfg (feature = "bench" )] |
161 | extern crate test; |
162 | #[cfg (feature = "bench" )] |
163 | mod benchmarks; |
164 | |