use bumpalo::Bump;
use std::{alloc::Layout, fmt};
pub type ThinSlice<T> = RawThinSlice<(), T>;
pub struct RawThinSlice<H, T> {
skel: ThinSliceSkeleton<H, T>,
_opaque: OpaqueListContents,
}
#[repr(C)]
struct ThinSliceSkeleton<H, T> {
header: H,
len: usize,
data: [T; 0],
}
#[cfg(not(feature = "nightly"))]
type OpaqueListContents = ();
#[cfg(feature = "nightly")]
unsafe extern "C" {
type OpaqueListContents;
}
impl<H, T> RawThinSlice<H, T> {
#[inline]
pub fn header(&self) -> &H {
&self.skel.header
}
#[inline]
pub fn header_mut(&mut self) -> &mut H {
&mut self.skel.header
}
#[inline]
#[expect(clippy::mut_from_ref)] pub(super) fn from_arena<'a>(arena: &'a Bump, header: H, slice: &[T]) -> &'a mut Self {
let mem = Self::alloc_from_arena(arena, slice.len());
unsafe { Self::init(mem, header, slice) }
}
#[inline]
#[expect(clippy::mut_from_ref)] pub(super) fn from_arena_with(
arena: &Bump,
header: H,
len: usize,
f: impl FnMut(usize) -> T,
) -> &mut Self {
let mem = Self::alloc_from_arena(arena, len);
unsafe { Self::init_with(mem, header, len, f) }
}
#[inline]
fn alloc_from_arena(arena: &Bump, len: usize) -> *mut Self {
let (layout, _offset) = Layout::new::<ThinSliceSkeleton<H, T>>()
.extend(Layout::array::<T>(len).unwrap())
.unwrap();
arena.alloc_layout(layout).as_ptr() as *mut Self
}
#[inline]
unsafe fn init<'a>(mem: *mut Self, header: H, slice: &[T]) -> &'a mut Self {
unsafe {
(&raw mut (*mem).skel.header).write(header);
(&raw mut (*mem).skel.len).write(slice.len());
(&raw mut (*mem).skel.data)
.cast::<T>()
.copy_from_nonoverlapping(slice.as_ptr(), slice.len());
&mut *mem
}
}
#[inline]
unsafe fn init_with<'a>(
mem: *mut Self,
header: H,
len: usize,
mut f: impl FnMut(usize) -> T,
) -> &'a mut Self {
unsafe {
(&raw mut (*mem).skel.header).write(header);
(&raw mut (*mem).skel.len).write(len);
for i in 0..len {
(&raw mut (*mem).skel.data).cast::<T>().add(i).write(f(i));
}
&mut *mem
}
}
#[inline(always)]
pub fn len(&self) -> usize {
self.skel.len
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.skel.len == 0
}
#[inline(always)]
pub fn as_slice(&self) -> &[T] {
self
}
#[inline(always)]
pub fn as_mut_slice(&mut self) -> &mut [T] {
self
}
}
unsafe impl<H: Send, T: Send> Send for RawThinSlice<H, T> {}
unsafe impl<H: Sync, T: Sync> Sync for RawThinSlice<H, T> {}
impl<H, T> std::ops::Deref for RawThinSlice<H, T> {
type Target = [T];
#[inline(always)]
fn deref(&self) -> &Self::Target {
let data_ptr = (&raw const self.skel.data).cast::<T>();
unsafe { std::slice::from_raw_parts(data_ptr, self.len()) }
}
}
impl<H, T> std::ops::DerefMut for RawThinSlice<H, T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
let data_ptr = (&raw mut self.skel.data).cast::<T>();
unsafe { std::slice::from_raw_parts_mut(data_ptr, self.len()) }
}
}
impl<T> Default for &RawThinSlice<(), T> {
#[inline(always)]
fn default() -> Self {
assert!(align_of::<T>() <= align_of::<MaxAlign>());
unsafe { &*((&raw const EMPTY) as *const RawThinSlice<(), T>) }
}
}
impl<T> Default for &mut RawThinSlice<(), T> {
#[inline(always)]
fn default() -> Self {
assert!(align_of::<T>() <= align_of::<MaxAlign>());
unsafe { &mut *((&raw mut EMPTY) as *mut RawThinSlice<(), T>) }
}
}
#[repr(align(64))]
struct MaxAlign;
static mut EMPTY: ThinSliceSkeleton<(), MaxAlign> =
ThinSliceSkeleton { header: (), len: 0, data: [] };
impl<H, T: fmt::Debug> fmt::Debug for RawThinSlice<H, T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
impl<H, T: PartialEq> PartialEq for RawThinSlice<H, T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.as_slice() == other.as_slice()
}
}
impl<H, T: Eq> Eq for RawThinSlice<H, T> {}
impl<H, T: PartialOrd> PartialOrd for RawThinSlice<H, T> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.as_slice().partial_cmp(other.as_slice())
}
}
impl<H, T: Ord> Ord for RawThinSlice<H, T> {
#[inline]
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.as_slice().cmp(other.as_slice())
}
}
impl<H, T: std::hash::Hash> std::hash::Hash for RawThinSlice<H, T> {
#[inline]
fn hash<Hasher: std::hash::Hasher>(&self, state: &mut Hasher) {
self.as_slice().hash(state)
}
}
impl<'a, H, T> IntoIterator for &'a RawThinSlice<H, T> {
type Item = &'a T;
type IntoIter = std::slice::Iter<'a, T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, H, T> IntoIterator for &'a mut RawThinSlice<H, T> {
type Item = &'a mut T;
type IntoIter = std::slice::IterMut<'a, T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty() {
let thin_slice = <&ThinSlice<u64>>::default();
assert_eq!(thin_slice.len(), 0);
assert_eq!(thin_slice.as_slice().len(), 0);
assert!(thin_slice.is_empty());
let thin_slice = <&mut ThinSlice<u64>>::default();
assert_eq!(thin_slice.len(), 0);
assert_eq!(thin_slice.as_slice().len(), 0);
assert!(thin_slice.is_empty());
}
}