use crate::utils::ring_buffer_ranges;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use core::{cell::UnsafeCell, marker::PhantomData, mem::MaybeUninit, num::NonZeroUsize, slice};
pub unsafe trait Container<T> {
type Internal;
fn into_internal(self) -> Self::Internal;
unsafe fn from_internal(this: Self::Internal) -> Self;
fn as_mut_ptr(this: &Self::Internal) -> *mut MaybeUninit<T>;
fn len(this: &Self::Internal) -> usize;
}
unsafe impl<'a, T> Container<T> for &'a mut [MaybeUninit<T>] {
type Internal = (*mut MaybeUninit<T>, usize);
fn into_internal(self) -> Self::Internal {
(self.as_mut_ptr(), self.len())
}
unsafe fn from_internal(this: Self::Internal) -> Self {
slice::from_raw_parts_mut(this.0, this.1)
}
#[inline]
fn as_mut_ptr(this: &Self::Internal) -> *mut MaybeUninit<T> {
this.0
}
#[inline]
fn len(this: &Self::Internal) -> usize {
this.1
}
}
unsafe impl<T, const N: usize> Container<T> for [MaybeUninit<T>; N] {
type Internal = UnsafeCell<[MaybeUninit<T>; N]>;
fn into_internal(self) -> Self::Internal {
UnsafeCell::new(self)
}
unsafe fn from_internal(this: Self::Internal) -> Self {
this.into_inner()
}
#[inline]
fn as_mut_ptr(this: &Self::Internal) -> *mut MaybeUninit<T> {
this.get() as *mut _
}
#[inline]
fn len(_: &Self::Internal) -> usize {
N
}
}
#[cfg(feature = "alloc")]
unsafe impl<T> Container<T> for Vec<MaybeUninit<T>> {
type Internal = Self;
fn into_internal(self) -> Self::Internal {
self
}
unsafe fn from_internal(this: Self::Internal) -> Self {
this
}
#[inline]
fn as_mut_ptr(this: &Self::Internal) -> *mut MaybeUninit<T> {
this.as_ptr() as *mut _
}
#[inline]
fn len(this: &Self::Internal) -> usize {
this.len()
}
}
pub(crate) struct SharedStorage<T, C: Container<T>> {
container: C::Internal,
_p: PhantomData<T>,
}
unsafe impl<T, C: Container<T>> Sync for SharedStorage<T, C> where T: Send {}
impl<T, C: Container<T>> SharedStorage<T, C> {
pub fn new(container: C) -> Self {
let internal = container.into_internal();
assert!(C::len(&internal) > 0);
Self {
container: internal,
_p: PhantomData,
}
}
#[inline]
pub fn len(&self) -> NonZeroUsize {
unsafe { NonZeroUsize::new_unchecked(C::len(&self.container)) }
}
pub unsafe fn as_mut_slices(
&self,
head: usize,
tail: usize,
) -> (&mut [MaybeUninit<T>], &mut [MaybeUninit<T>]) {
let ranges = ring_buffer_ranges(self.len(), head, tail);
let ptr = C::as_mut_ptr(&self.container);
(
slice::from_raw_parts_mut(ptr.add(ranges.0.start), ranges.0.len()),
slice::from_raw_parts_mut(ptr.add(ranges.1.start), ranges.1.len()),
)
}
pub fn into_inner(self) -> C {
unsafe { C::from_internal(self.container) }
}
}