Skip to main content

RingBuffer

Struct RingBuffer 

Source
pub struct RingBuffer<T> { /* private fields */ }
Expand description

pre-allocated ring buffer with runtime-configurable capacity.

the buffer stores events in a circular array. capacity must be a power of 2, which allows using bitwise AND instead of modulo for index calculations.

§type parameters

  • T - the event type to store

§example

use scatto::ringbuffer::RingBuffer;

// create a buffer for 1024 events
let buffer: RingBuffer<String> = RingBuffer::new(1024);

// with factory for pre-initialization
let buffer = RingBuffer::with_factory(1024, || String::with_capacity(256));

Implementations§

Source§

impl<T> RingBuffer<T>

Source

pub fn new(capacity: usize) -> Self

create a new ring buffer with the given capacity.

§arguments
  • capacity - number of slots (must be power of 2)
§panics

panics if capacity is not a power of 2 or is zero.

§example
use scatto::ringbuffer::RingBuffer;

let buffer: RingBuffer<u64> = RingBuffer::new(1024);
assert_eq!(buffer.capacity(), 1024);
use scatto::ringbuffer::RingBuffer;

// this will panic - 100 is not a power of 2
let buffer: RingBuffer<u64> = RingBuffer::new(100);
Source

pub fn with_factory<F>(capacity: usize, factory: F) -> Self
where F: Fn() -> T,

create a new ring buffer with pre-initialized slots.

the factory function is called once for each slot to initialize it. this is useful for pre-allocating resources (e.g. Vec with capacity).

§arguments
  • capacity - number of slots (must be power of 2)
  • factory - function to create initial values
§panics

panics if capacity is not a power of 2 or is zero.

§example
use scatto::ringbuffer::RingBuffer;

// Pre-allocate strings with capacity
let buffer = RingBuffer::with_factory(1024, || String::with_capacity(256));
Source

pub fn capacity(&self) -> usize

get the buffer capacity (number of slots).

Source

pub fn mask(&self) -> usize

get the index mask for modulo operations.

Source

pub fn index(&self, sequence: i64) -> usize

convert a sequence number to a slot index.

uses bitwise AND which is faster than modulo for power-of-2 sizes.

§example
use scatto::ringbuffer::RingBuffer;

let buffer: RingBuffer<u64> = RingBuffer::new(8);
assert_eq!(buffer.index(0), 0);
assert_eq!(buffer.index(7), 7);
assert_eq!(buffer.index(8), 0);  // wraps around
assert_eq!(buffer.index(9), 1);
Source

pub unsafe fn get_ptr_mut(&self, sequence: i64) -> *mut T

get a raw mutable pointer to the slot at the given sequence.

§safety

the caller must ensure:

  • exclusive access to this slot (no concurrent reads or writes)
  • the slot index is valid
§example
use scatto::ringbuffer::RingBuffer;

let buffer: RingBuffer<u64> = RingBuffer::new(8);
unsafe {
    let ptr = buffer.get_ptr_mut(0);
    ptr.write(42);
}
Source

pub unsafe fn get_ptr(&self, sequence: i64) -> *const T

get a raw const pointer to the slot at the given sequence.

§safety

the caller must ensure:

  • the slot has been initialized (written to)
  • no concurrent writes to this slot
§example
use scatto::ringbuffer::RingBuffer;

let buffer: RingBuffer<u64> = RingBuffer::new(8);
unsafe {
    buffer.write(0, 42);
    let ptr = buffer.get_ptr(0);
    assert_eq!(*ptr, 42);
}
Source

pub unsafe fn write(&self, sequence: i64, event: T)

write an event to the slot at the given sequence.

this overwrites any existing value without dropping it. for types that implement Drop, use write_and_drop.

§safety

the caller must ensure:

  • exclusive access to this slot
  • no concurrent reads while writing
§example
use scatto::ringbuffer::RingBuffer;

let buffer: RingBuffer<u64> = RingBuffer::new(8);
unsafe {
    buffer.write(0, 100);
    buffer.write(1, 200);
}
Source

pub unsafe fn write_and_drop(&self, sequence: i64, event: T)

write an event, dropping any existing value first.

use this for types that implement Drop when reusing slots.

§safety

the caller must ensure:

  • exclusive access to this slot
  • the slot was previously initialized (has a valid value to drop)
Source

pub unsafe fn get(&self, sequence: i64) -> &T

read a reference to the event at the given sequence.

§safety

the caller must ensure:

  • the slot has been initialized
  • no concurrent writes to this slot
  • the returned reference does not outlive concurrent access constraints
§example
use scatto::ringbuffer::RingBuffer;

let buffer: RingBuffer<u64> = RingBuffer::new(8);
unsafe {
    buffer.write(0, 42);
    let value = buffer.get(0);
    assert_eq!(*value, 42);
}
Source

pub unsafe fn get_mut(&self, sequence: i64) -> &mut T

get a mutable reference to the event at the given sequence.

this enables zero-copy in-place mutation.

§safety

the caller must ensure:

  • exclusive access to this slot
  • the slot has been initialized
  • no concurrent reads or writes
§example
use scatto::ringbuffer::RingBuffer;

let buffer = RingBuffer::with_factory(8, || String::new());
unsafe {
    // zero-copy: modify the event in place
    let event = buffer.get_mut(0);
    event.push_str("hello");
    assert_eq!(buffer.get(0), "hello");
}
Source

pub unsafe fn read(&self, sequence: i64) -> T

read and move the event out of the slot.

this performs a ptr::read which moves ownership to the caller. the slot is left in an uninitialized state.

§safety

the caller must ensure:

  • she slot has been initialized
  • no concurrent access to this slot
  • the slot wont be read again without being rewritten
Source

pub fn free_slots(&self, producer_seq: i64, consumer_seq: i64) -> usize

calculate free slots available for writing.

§arguments
  • producer_seq - current producer sequence (last written)
  • consumer_seq - current consumer sequence (last consumed)
§returns

number of slots available for the producer to write.

Trait Implementations§

Source§

impl<T: Debug> Debug for RingBuffer<T>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T> Drop for RingBuffer<T>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl<T: Send> Send for RingBuffer<T>

Source§

impl<T: Send> Sync for RingBuffer<T>

Auto Trait Implementations§

§

impl<T> Freeze for RingBuffer<T>

§

impl<T> !RefUnwindSafe for RingBuffer<T>

§

impl<T> Unpin for RingBuffer<T>

§

impl<T> UnsafeUnpin for RingBuffer<T>

§

impl<T> UnwindSafe for RingBuffer<T>
where T: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.