1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! Lock-free single-producer single-consumer (SPSC) FIFO ring buffer with direct access to inner data.
//!
//! # Overview
//!
//! `RingBuffer` is the initial structure representing ring buffer itself.
//! Ring buffer can be splitted into pair of `Producer` and `Consumer`.
//!
//! `Producer` and `Consumer` are used to append/remove elements to/from the ring buffer accordingly. They can be safely transfered between threads.
//! Operations with `Producer` and `Consumer` are lock-free - they're succeded or failed immediately without blocking or waiting.
//!
//! Elements can be effectively appended/removed one by one or many at once.
//! Also data could be loaded/stored directly into/from [`Read`]/[`Write`] instances.
//! And finally, there are `unsafe` methods allowing thread-safe direct access in place to the inner memory being appended/removed.
//!
//! [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
//! [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
//!
//! When building with nightly toolchain it is possible to run benchmarks via `cargo bench --features benchmark`.
//!
//! # Examples
//!
//! ## Simple example
//!
//! ```rust
//! # extern crate ringbuf;
//! use ringbuf::RingBuffer;
//! # fn main() {
//! let rb = RingBuffer::<i32>::new(2);
//! let (mut prod, mut cons) = rb.split();
//!
//! prod.push(0).unwrap();
//! prod.push(1).unwrap();
//! assert_eq!(prod.push(2), Err(2));
//!
//! assert_eq!(cons.pop().unwrap(), 0);
//!
//! prod.push(2).unwrap();
//!
//! assert_eq!(cons.pop().unwrap(), 1);
//! assert_eq!(cons.pop().unwrap(), 2);
//! assert_eq!(cons.pop(), None);
//! # }
//! ```
//!
//! ## Message transfer
//!
//! This is more complicated example of transfering text message between threads.
//!
//! ```rust
//! # extern crate ringbuf;
//! use std::io::Read;
//! use std::thread;
//! use std::time::Duration;
//!
//! use ringbuf::RingBuffer;
//!
//! # fn main() {
//! let buf = RingBuffer::<u8>::new(10);
//! let (mut prod, mut cons) = buf.split();
//!
//! let smsg = "The quick brown fox jumps over the lazy dog";
//!
//! let pjh = thread::spawn(move || {
//!     println!("-> sending message: '{}'", smsg);
//!
//!     let zero = [0 as u8];
//!     let mut bytes = smsg.as_bytes().chain(&zero[..]);
//!     loop {
//!         if prod.is_full() {
//!             println!("-> buffer is full, waiting");
//!             thread::sleep(Duration::from_millis(1));
//!         } else {
//!             let n = prod.read_from(&mut bytes, None).unwrap();
//!             if n == 0 {
//!                 break;
//!             }
//!             println!("-> {} bytes sent", n);
//!         }
//!     }
//!
//!     println!("-> message sent");
//! });
//!
//! let cjh = thread::spawn(move || {
//!     println!("<- receiving message");
//!
//!     let mut bytes = Vec::<u8>::new();
//!     loop {
//!         if cons.is_empty() {
//!             if bytes.ends_with(&[0]) {
//!                 break;
//!             } else {
//!                 println!("<- buffer is empty, waiting");
//!                 thread::sleep(Duration::from_millis(1));
//!             }
//!         } else {
//!             let n = cons.write_into(&mut bytes, None).unwrap();
//!             println!("<- {} bytes received", n);
//!         }
//!     }
//!
//!     assert_eq!(bytes.pop().unwrap(), 0);
//!     let msg = String::from_utf8(bytes).unwrap();
//!     println!("<- message received: '{}'", msg);
//!
//!     msg
//! });
//!
//! pjh.join().unwrap();
//! let rmsg = cjh.join().unwrap();
//!
//! assert_eq!(smsg, rmsg);
//! # }
//! ```
//!

#![cfg_attr(feature = "benchmark", feature(test))]

#[cfg(feature = "benchmark")]
extern crate test;

#[cfg(feature = "benchmark")]
mod benchmark;

#[cfg(test)]
mod tests;

mod consumer;
mod producer;
mod ring_buffer;

pub use consumer::*;
pub use producer::*;
pub use ring_buffer::*;