use crate::collection::LinearStorageLen;
use core::{
fmt::{Debug, Formatter},
marker::PhantomData,
ops::Deref,
ptr, slice,
};
pub type ShortSliceU8<'any, T> = ShortSlice<'any, u8, T>;
pub type ShortSliceU16<'any, T> = ShortSlice<'any, u16, T>;
#[expect(clippy::repr_packed_without_abi, reason = "only used internally")]
#[repr(packed)]
pub struct ShortSlice<'any, L, T> {
ptr: *const T,
len: L,
phantom: PhantomData<&'any T>,
}
impl<L, T> ShortSlice<'_, L, T>
where
L: LinearStorageLen,
{
const CHECK_LEN: () = { assert!(L::BYTES <= 2) };
}
impl<'any, T> ShortSliceU8<'any, T> {
#[inline]
#[expect(clippy::cast_possible_truncation, reason = "lack of const support")]
pub const fn new_truncated_u8(slice: &'any [T]) -> Self {
const { Self::CHECK_LEN }
Self {
len: if slice.len() <= 255 { slice.len() as u8 } else { 255 },
phantom: PhantomData,
ptr: slice.as_ptr(),
}
}
}
impl<L, T> AsRef<[T]> for ShortSlice<'_, L, T>
where
L: LinearStorageLen,
{
#[inline]
fn as_ref(&self) -> &[T] {
self
}
}
impl<L, T> Clone for ShortSlice<'_, L, T>
where
L: LinearStorageLen,
{
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<L, T> Copy for ShortSlice<'_, L, T> where L: LinearStorageLen {}
impl<L, T> Debug for ShortSlice<'_, L, T>
where
L: LinearStorageLen,
T: Debug,
{
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
(**self).fmt(f)
}
}
impl<L, T> Default for ShortSlice<'_, L, T>
where
L: LinearStorageLen,
{
#[inline]
fn default() -> Self {
Self { ptr: ptr::null(), len: L::ZERO, phantom: PhantomData }
}
}
impl<L, T> Deref for ShortSlice<'_, L, T>
where
L: LinearStorageLen,
{
type Target = [T];
#[inline]
fn deref(&self) -> &Self::Target {
let ptr = self.ptr;
let len = self.len;
unsafe { slice::from_raw_parts(ptr, len.usize()) }
}
}
impl<'any, T> From<&'any [T]> for ShortSliceU8<'any, T> {
#[inline]
fn from(value: &'any [T]) -> Self {
Self::new_truncated_u8(value)
}
}
impl<L, T> PartialEq for ShortSlice<'_, L, T>
where
L: LinearStorageLen,
T: PartialEq,
{
#[inline]
fn eq(&self, other: &Self) -> bool {
**self == **other
}
}
unsafe impl<L, T: Send> Send for ShortSlice<'_, L, T> {}
unsafe impl<L, T: Sync> Sync for ShortSlice<'_, L, T> {}
#[cfg(test)]
mod tests {
use crate::collection::ShortSliceU8;
use core::mem;
#[test]
fn empty_slice() {
let empty: &[u8] = &[];
let instance = ShortSliceU8::new_truncated_u8(empty);
assert!(instance.is_empty());
}
#[test]
fn new_truncated() {
let large_slice = &[0u8; 300];
let instance = ShortSliceU8::new_truncated_u8(large_slice);
assert_eq!(instance.len(), 255);
}
#[test]
fn size_of() {
assert!(mem::size_of::<ShortSliceU8<'_, u8>>() < 2usize * mem::size_of::<usize>());
}
#[test]
fn size_of_in_context() {
struct Foo<'any> {
_a: ShortSliceU8<'any, u8>,
_b: u32,
}
assert!(mem::size_of::<Foo<'_>>() <= 2usize * mem::size_of::<usize>());
}
#[test]
fn static_instance() {
static FOO: ShortSliceU8<'static, u8> = ShortSliceU8::new_truncated_u8(&[1, 2, 3]);
assert_eq!(&*FOO, &[1, 2, 3]);
}
}