Crates.io | direct_ring_buffer |
lib.rs | direct_ring_buffer |
version | 0.2.1 |
source | src |
created_at | 2024-05-30 01:23:45.810392 |
updated_at | 2024-10-22 17:20:09.406656 |
description | A high-performance, lock-free ring buffer for single-producer, single-consumer scenarios. |
homepage | https://github.com/ain1084/direct_ring_buffer |
repository | https://github.com/ain1084/direct_ring_buffer |
max_upload_size | |
id | 1256372 |
size | 56,106 |
This crate provides a high-performance, lock-free ring buffer for single-producer, single-consumer scenarios, where efficient writing and reading of elements is crucial.
A ring buffer is a fixed-size buffer that operates as a circular queue. This implementation uses a lock-free approach, making it suitable for real-time applications where minimal latency is important. The buffer supports efficient bulk operations through block-based reads and writes, making it ideal for scenarios with one producer and one consumer.
The buffer requires the type T
to implement the Copy
trait because it operates on uninitialized memory. The usage of Copy
depends on the operation:
read_slices
and write_slices
do not require Copy
, allowing direct memory access without copying elements.read_element
and write_element
require Copy
to safely handle the copying of individual elements.use direct_ring_buffer::{create_ring_buffer, Producer, Consumer};
let (mut producer, mut consumer) = create_ring_buffer::<u8>(5);
// Write data to the buffer in slices
producer.write_slices(|data, _offset| {
data[..3].copy_from_slice(&[1, 2, 3]);
3
}, None);
producer.write_slices(|data, _offset| {
data[..1].copy_from_slice(&[4]);
1
}, None);
// Read the data
consumer.read_slices(|data, _offset| {
assert_eq!(&data[..4], &[1, 2, 3, 4]);
4
}, None);
// Test wrap-around by writing more data
producer.write_slices(|data, offset| {
if offset == 0 {
data[..1].copy_from_slice(&[6]);
1
} else if offset == 1 {
data[..1].copy_from_slice(&[7]);
1
} else {
panic!("Unexpected offset: {}", offset);
}
}, None);
// Verify the wrap-around data
consumer.read_slices(|data, offset| {
if offset == 0 {
assert_eq!(data, &[6]); // Read the last part of the buffer
} else if offset == 1 {
assert_eq!(data, &[7]); // Read the wrapped-around part
} else {
panic!("Unexpected offset: {}", offset); // Ensure only 0 or 1 is valid
}
data.len()
}, None);
// Write 5 more values to test wrap-around in one go
let test_data = [8, 9, 10, 11, 12];
producer.write_slices(|data, offset| {
let write_len = data.len().min(test_data.len() - offset);
data[..write_len].copy_from_slice(&test_data[offset..offset + write_len]);
write_len
}, None);
// Read the newly written values to verify wrap-around
consumer.read_slices(|data, offset| {
let read_len = data.len().min(test_data.len() - offset);
assert_eq!(&data[..read_len], &test_data[offset..offset + read_len]);
read_len
}, None);
Note: For single element operations using read_element or write_element, see the documentation in lib.rs.
This implementation uses unsafe blocks with proper checks to ensure safe access to uninitialized memory. Atomic operations are utilized for synchronization, minimizing overhead and allowing for high-performance scenarios where low-latency and real-time constraints are critical.
This ring buffer is optimized for reading and writing multiple elements at once, reducing overhead for batch processing. While it supports single-element operations, bulk operations maximize performance and minimize overhead.
Licensed under either of
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.