11 releases

0.3.3 Aug 28, 2023
0.3.2 Aug 22, 2023
0.2.1 Aug 20, 2023
0.1.4 Aug 19, 2023

#410 in Embedded development

Download history 2/week @ 2024-02-14 10/week @ 2024-02-21 4/week @ 2024-02-28 1/week @ 2024-03-06 17/week @ 2024-03-13 24/week @ 2024-03-27 38/week @ 2024-04-03

62 downloads per month

MIT license

20KB
202 lines

fring ("fast ring") is a fast, lightweight circular buffer, designed for embedded systems and other no_std targets. The memory footprint is the buffer itself plus two usize indices, and that's it. 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. Compared to other Rust ring buffers (such as bbqueue), fring is less flexible, but offers reduced storage and computational overhead.


lib.rs:

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);
}

No runtime deps