bufferring 0.0.2

Ring buffers for Rust
Documentation
use core::fmt::{self, Debug};
use core::num::NonZeroUsize;
use core::pin::Pin;

extern crate alloc;
use alloc::{boxed::Box, vec::Vec};

use super::{Slot, Storage};

/// Storage for ring buffers on the heap.
///
/// The underlying data buffer is allocated using the standard [`alloc`] crate,
/// so that it lives on the heap.  A capacity is assigned upon creation, and it
/// cannot be changed afterwards.
pub struct HeapStorage<T> {
    /// The underlying data.
    data: Box<[Slot<T>]>,
}

impl<T> HeapStorage<T> {
    /// Create a new [`HeapStorage`] with the given non-zero capacity.
    pub fn with_capacity(cap: NonZeroUsize) -> Self {
        // SAFETY: 'cap' is guaranteed to be non-zero.
        unsafe { Self::with_capacity_unchecked(cap.get()) }
    }

    /// Create a new [`HeapStorage`] with the given capacity, assuming that it
    /// is non-zero.
    ///
    /// If this is called with a zero capacity, undefined behaviour will occur.
    pub unsafe fn with_capacity_unchecked(cap: usize) -> Self {
        // Allocate the slice using [`Vec`], then convert to a [`Box`].
        // NOTE: Use [`Box::new_uninit_slice()`] if/when it stabilizes.
        let mut data = Vec::new();
        data.reserve_exact(cap);
        // SAFETY: [`Slot`] does not require initialization.
        unsafe { data.set_len(cap); }
        Self { data: data.into_boxed_slice() }
    }
}

// SAFETY:
// - The same slice is returned by get(), get_mut(), and get_pin().
// - There is no way to modify the slice externally.
unsafe impl<T> Storage for HeapStorage<T> {
    type Item = T;

    fn cap(&self) -> usize {
        self.data.len()
    }

    fn get(&self) -> &[Slot<Self::Item>] {
        &self.data
    }

    fn get_mut(&mut self) -> &mut [Slot<Self::Item>] {
        &mut self.data
    }

    fn get_pin(self: Pin<&mut Self>) -> Pin<&mut [Slot<Self::Item>]> {
        // NOTE: We could use the pin-project crate, but there's no need for a
        // new dependency when we already have 'unsafe' code all over.

        // SAFETY: The slice is a pinned part of the object.
        unsafe { self.map_unchecked_mut(|this| &mut *this.data) }
    }
}

impl<T> Clone for HeapStorage<T> {
    fn clone(&self) -> Self {
        // SAFETY: A `HeapStorage` with this capacity already exists.
        unsafe { Self::with_capacity_unchecked(self.cap()) }
    }
}

impl<T> Debug for HeapStorage<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "HeapStorage")
    }
}