Crate fring

Source
Expand description

Fast ring buffer intended for no_std targets.

fring (“fast ring”) is a fast and lightweight circular buffer, designed for embedded systems and other no_std targets. (“Circular buffer” means it is a FIFO queue, stored as an array, and the data wraps back to the beginning of the array once it reaches the end.) The memory footprint of a fring::Buffer is the buffer itself plus two usize indices.

The buffer allows a single producer and a single consumer, which may operate concurrently. Memory safety and thread safety are enforced at compile time; the buffer is lock-free at runtime. The buffer length is required to be a power of two, and the only arithmetic operations used by buffer operations are addition/subtraction and bitwise and.

The only way to use a Buffer is to split it into a Producer and a Consumer. Then one may call Producer.write() and Consumer.read(), or various other methods which are provided by Producer and Consumer.

Example of safe threaded use:

fn main() {
    let mut buffer = fring::Buffer::<N>::new();
    let (producer, consumer) = buffer.split();
    std::thread::scope(|s| {
        s.spawn(|| {
            make_data(producer);
        });
        use_data(consumer);
    });
}

Example of static use (requires unsafe):

static BUFFER: fring::Buffer<N> = fring::Buffer::new();

fn interrupt_handler() {
    // UNSAFE: this is safe because this is the only place we ever
    // call BUFFER.producer(), and interrupt_handler() is not reentrant
    let producer = unsafe { BUFFER.producer() };
    write_data(producer);
}

fn main() {
    // UNSAFE: this is safe because this is the only place we ever
    // call BUFFER.consumer(), and main() is not reentrant
    let consumer = unsafe { BUFFER.consumer() };
    use_data(consumer);
}

Structs§

Buffer
A Buffer<N> consists of a [u8; N] array along with two usize indices into the array. N must be a power of two. (If you need more flexibility with sizing, consider using a bbqueue::BBBuffer instead.) A Buffer<N> can hold N bytes of data and guarantees FIFO ordering. The only way to use a Buffer is to split it into a Producer and a Consumer, which may then be passed to different threads or contexts.
Consumer
A Consumer is a smart pointer to a Buffer, which is endowed with the right to remove data from the buffer. Only one Consumer may exist at one time for any given buffer. The methods of a Consumer are the only way to read data out of a Buffer.
Producer
A Producer is a smart pointer to a Buffer, which is endowed with the right to add data into the buffer. Only one Producer may exist at one time for any given buffer. The methods of a Producer are the only way to insert data into a Buffer.
Region
A Region is a smart pointer to a specific region of data in a Buffer. The Region derefs to [u8] and may generally be used in the same way as a slice (e.g. region[i], region.len()). When a Region is dropped, it updates the associated Buffer to indicate that this section of the buffer is finished being read or written. If a Region is forgotten instead of dropped, the buffer will not be updated and the same region will be re-issued by the next read/write.