| 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 | # 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 | |