bufferring 0.0.2

Ring buffers for Rust
Documentation
//! Ringbuffer data storage.
//!
//! This module provides [`Storage`] and its implementors, which are used by the
//! crate's ring buffer types for the backing data buffer.  Data could be stored
//! in different locations: [`ArrayStorage`] stores it on the stack, for `const`
//! capacities, while [`HeapStorage`] allocates it on the heap.

use core::cell::UnsafeCell;
use core::mem::MaybeUninit;
use core::pin::Pin;

mod array;
pub use array::ArrayStorage;

#[cfg(feature = "alloc")]
mod heap;

#[cfg(feature = "alloc")]
pub use heap::HeapStorage;

/// Storage for a ring buffer.
///
/// The storage should represent a slice of items, some of which may not be
/// initialized.  It is the responsibility of the ring buffer using the storage
/// to track which items are initialized and also to drop them appropriately.
///
/// This is an `unsafe` trait: every implementation of it must satisfy certain
/// invariants, else risk undefined behaviour:
///
/// - [`Pin`] safety: [`get()`], [`get_mut()`], and [`get_pin()`] return the
///   same slice (i.e. the same pointer address) for the same `self` address.
/// - [`get()`], [`get_mut()`], and [`get_pin()`] always return a slice with the
///   same length; the length cannot change for the duration of the object.
/// - The length of the stored slice is non-zero.
/// - The referenced slice's contents must not change externally; they are only
///   mutated by the containing ring buffer.  Interior mutation is not allowed.
///   - The ring buffer is free to assume that modifications it makes to the
///     slice will persist until they are overriden by newer modifications.
///
/// [`get()`]: Self::get()
/// [`get_mut()`]: Self::get_mut()
/// [`get_pin()`]: Self::get_pin()
pub unsafe trait Storage {
    /// The type of the items stored by the buffer.
    type Item;

    /// The capacity of this storage.
    fn cap(&self) -> usize {
        self.get().len()
    }

    /// Get a shared reference to the data.
    fn get(&self) -> &[Slot<Self::Item>];

    /// Get a unique reference to the data.
    fn get_mut(&mut self) -> &mut [Slot<Self::Item>];

    /// Get a pinned reference to the data.
    fn get_pin(self: Pin<&mut Self>) -> Pin<&mut [Slot<Self::Item>]>;
}

/// A slot for storing a single ring buffer item.
///
/// According to the [`Storage`] API, individual slots in the data buffer can be
/// initialized or uninitialized, and some may be borrowed mutably.  This is a
/// convienience wrapper which provides both of these properties, combining both
/// [`MaybeUninit`] and [`UnsafeCell`] with a useful API.
///
/// Slots do not require initialization, like [`MaybeUninit`]; they are valid
/// even if constructed uninitialized.  This allows them to be created in arrays
/// and the like without any work.
#[repr(transparent)]
pub struct Slot<T> {
    data: MaybeUninit<UnsafeCell<T>>,
}

impl<T> Slot<T> {
    /// Create a new, uninitialized slot.
    pub fn uninit() -> Self {
        Self { data: MaybeUninit::uninit() }
    }

    /// Create a new slot containing the given item.
    pub fn new(item: T) -> Self {
        Self { data: MaybeUninit::new(UnsafeCell::new(item)) }
    }

    /// Extract the contained item by value.
    ///
    /// This is an `unsafe` function; it can only be called if the slot is known
    /// to be initialized.
    pub unsafe fn get(self) -> T {
        self.data.assume_init().into_inner()
    }

    /// Get a shared reference to the item.
    ///
    /// This is an `unsafe` function; it can only be called if the slot is known
    /// to be initialized, and if no unique references to the item (e.g. due to
    /// [`get_int_mut()`](Self::get_int_mut())) already exist.
    pub unsafe fn get_ref(&self) -> &T {
        &*self.data.assume_init_ref().get()
    }

    /// Get a unique reference to the item.
    ///
    /// This is an `unsafe` function; it can only be called if the slot is known
    /// to be initialized.
    pub unsafe fn get_mut(&mut self) -> &mut T {
        self.data.assume_init_mut().get_mut()
    }

    /// Get an interior-mutable reference to the item.
    ///
    /// This is an `unsafe` function; it can only be called if the slot is known
    /// to be initialized, and if no unique references to the item (e.g. due to
    /// [`get_int_mut()`](Self::get_int_mut())) already exist.
    pub unsafe fn get_int_mut(&self) -> &mut T {
        &mut *self.data.assume_init_ref().get()
    }

    /// Take the item, leaving uninitialized data behind.
    ///
    /// This is an `unsafe` function; it can only be called if the slot is known
    /// to be initialized.
    pub unsafe fn take(&mut self) -> T {
        self.data.assume_init_read().into_inner()
    }

    /// Drop the item contained in this slot.
    ///
    /// This is an `unsafe` function; it can only be called if the slot is known
    /// to be initialized.
    pub unsafe fn drop_in_place(&mut self) {
        self.data.assume_init_mut().get().drop_in_place()
    }
}

unsafe impl<T: Sync> Sync for Slot<T> {}