#[cfg(feature = "alloc")] use alloc::{boxed::Box, vec::Vec}; use core::{cell::UnsafeCell, marker::PhantomData, mem::MaybeUninit, ops::Range, ptr::NonNull, slice}; #[cfg(feature = "alloc")] use core::{mem::ManuallyDrop, ptr}; /// Abstract storage for the ring buffer. /// /// Storage items must be stored as a contiguous array. /// /// # Safety /// /// Must not alias with its contents /// (it must be safe to store mutable references to storage itself and to its data at the same time). /// /// [`Self::as_mut_ptr`] must point to underlying data. /// /// [`Self::len`] must always return the same value. pub unsafe trait Storage { /// Stored item. type Item: Sized; /// Length of the storage. fn len(&self) -> usize; fn is_empty(&self) -> bool { self.len() == 0 } /// Return pointer to the beginning of the storage items. fn as_ptr(&self) -> *const MaybeUninit { self.as_mut_ptr().cast_const() } /// Return mutable pointer to the beginning of the storage items. fn as_mut_ptr(&self) -> *mut MaybeUninit; /// Returns a mutable slice of storage in specified `range`. /// /// # Safety /// /// Slice must not overlab with existing mutable slices. /// /// Non-`Sync` items must not be accessed concurrently. unsafe fn slice(&self, range: Range) -> &[MaybeUninit] { unsafe { slice::from_raw_parts(self.as_ptr().add(range.start), range.len()) } } /// Returns a mutable slice of storage in specified `range`. /// /// # Safety /// /// Slices must not overlap. #[allow(clippy::mut_from_ref)] unsafe fn slice_mut(&self, range: Range) -> &mut [MaybeUninit] { unsafe { slice::from_raw_parts_mut(self.as_mut_ptr().add(range.start), range.len()) } } } pub struct Ref<'a, T> { _ghost: PhantomData<&'a mut [T]>, ptr: *mut MaybeUninit, len: usize, } unsafe impl Send for Ref<'_, T> where T: Send {} unsafe impl Sync for Ref<'_, T> where T: Send {} unsafe impl Storage for Ref<'_, T> { type Item = T; #[inline] fn as_mut_ptr(&self) -> *mut MaybeUninit { self.ptr } #[inline] fn len(&self) -> usize { self.len } } impl<'a, T> From<&'a mut [MaybeUninit]> for Ref<'a, T> { fn from(value: &'a mut [MaybeUninit]) -> Self { Self { _ghost: PhantomData, ptr: value.as_mut_ptr(), len: value.len(), } } } impl<'a, T> From> for &'a mut [MaybeUninit] { fn from(value: Ref<'a, T>) -> Self { unsafe { slice::from_raw_parts_mut(value.ptr, value.len) } } } pub struct Owning { data: UnsafeCell, } unsafe impl Sync for Owning where T: Send {} impl From for Owning { fn from(value: T) -> Self { Self { data: UnsafeCell::new(value), } } } pub type Array = Owning<[MaybeUninit; N]>; unsafe impl Storage for Array { type Item = T; #[inline] fn as_mut_ptr(&self) -> *mut MaybeUninit { self.data.get().cast() } #[inline] fn len(&self) -> usize { N } } impl From> for [MaybeUninit; N] { fn from(value: Array) -> Self { value.data.into_inner() } } pub type Slice = Owning<[MaybeUninit]>; unsafe impl Storage for Slice { type Item = T; #[inline] fn as_mut_ptr(&self) -> *mut MaybeUninit { self.data.get().cast() } #[inline] fn len(&self) -> usize { unsafe { NonNull::new_unchecked(self.data.get()) }.len() } } #[cfg(feature = "alloc")] pub struct Heap { ptr: *mut MaybeUninit, len: usize, } #[cfg(feature = "alloc")] unsafe impl Send for Heap where T: Send {} #[cfg(feature = "alloc")] unsafe impl Sync for Heap where T: Send {} #[cfg(feature = "alloc")] unsafe impl Storage for Heap { type Item = T; #[inline] fn as_mut_ptr(&self) -> *mut MaybeUninit { self.ptr } #[inline] fn len(&self) -> usize { self.len } } #[cfg(feature = "alloc")] impl Heap { /// Create a new heap storage with exact capacity. pub fn new(capacity: usize) -> Self { let mut data = Vec::>::with_capacity(capacity); // `data.capacity()` is not guaranteed to be equal to `capacity`. // We enforce that by `set_len` and converting to boxed slice. unsafe { data.set_len(capacity) }; Self::from(data.into_boxed_slice()) } } #[cfg(feature = "alloc")] impl From>> for Heap { fn from(mut value: Vec>) -> Self { // Convert `value` to boxed slice of length equals to `value.capacity()` // except for zero-sized types - for them length will be `value.len()` because `Vec::capacity` for ZST is undefined // (see ). if core::mem::size_of::() != 0 { unsafe { value.set_len(value.capacity()) }; } Self::from(value.into_boxed_slice()) } } #[cfg(feature = "alloc")] impl From]>> for Heap { fn from(value: Box<[MaybeUninit]>) -> Self { Self { len: value.len(), ptr: Box::into_raw(value).cast(), } } } #[cfg(feature = "alloc")] impl From> for Box<[MaybeUninit]> { fn from(value: Heap) -> Self { let value = ManuallyDrop::new(value); unsafe { Box::from_raw(ptr::slice_from_raw_parts_mut(value.ptr, value.len)) } } } #[cfg(feature = "alloc")] impl Drop for Heap { fn drop(&mut self) { drop(unsafe { Box::from_raw(ptr::slice_from_raw_parts_mut(self.ptr, self.len)) }); } } #[cfg(test)] mod tests { use super::*; use core::{cell::Cell, marker::PhantomData}; struct Check(PhantomData); #[allow(dead_code)] fn check_send_sync() { let _: Check>>; let _: Check, 4>>; let _: Check>>; #[cfg(feature = "alloc")] let _: Check>>; } }