use core::marker::PhantomData;
use core::mem::size_of;
use crate::buf::{Buf, Load};
use crate::endian::{ByteOrder, Native};
use crate::error::{Error, ErrorKind, IntoRepr};
use crate::pointer::{Ref, Size};
use crate::slice::Slice;
use crate::{DefaultSize, ZeroCopy};
#[derive(ZeroCopy)]
#[zero_copy(crate, bounds = {O: ZeroCopy, L: ZeroCopy})]
#[repr(C, packed)]
pub struct Packed<T, O = DefaultSize, L = DefaultSize, E = Native>
where
T: ?Sized,
O: Size,
L: Size,
E: ByteOrder,
{
offset: O,
len: L,
#[zero_copy(ignore)]
_marker: PhantomData<(E, T)>,
}
impl<T, O, L, E> Slice for Packed<[T], O, L, E>
where
T: ZeroCopy,
O: Size + TryFrom<usize>,
L: Size + TryFrom<usize>,
E: ByteOrder,
{
type Item = T;
type ItemRef = Ref<T, E, usize>;
#[inline]
fn from_ref<A: ByteOrder, B: Size>(slice: Ref<[T], A, B>) -> Self
where
T: ZeroCopy,
{
Self::with_metadata(slice.offset(), slice.len())
}
#[inline]
fn try_from_ref<A: ByteOrder, B: Size>(slice: Ref<[T], A, B>) -> Result<Self, Error>
where
T: ZeroCopy,
{
Self::try_with_metadata(slice.offset(), slice.len())
}
#[inline]
fn with_metadata(offset: usize, len: usize) -> Self {
Packed::from_raw_parts(offset, len)
}
#[inline]
fn try_with_metadata(offset: usize, len: usize) -> Result<Self, Error> {
Packed::try_from_raw_parts(offset, len)
}
#[inline]
fn get(self, index: usize) -> Option<Self::ItemRef> {
Packed::get(self, index)
}
#[inline]
fn split_at(self, at: usize) -> (Self, Self) {
Packed::split_at(self, at)
}
#[inline]
fn get_unchecked(self, index: usize) -> Self::ItemRef {
Packed::get_unchecked(self, index)
}
#[inline]
fn offset(self) -> usize {
Packed::offset(self)
}
#[inline]
fn len(self) -> usize {
Packed::len(self)
}
#[inline]
fn is_empty(self) -> bool {
Packed::is_empty(self)
}
}
impl<T, O, L, E> Packed<[T], O, L, E>
where
T: ZeroCopy,
O: Size,
L: Size,
E: ByteOrder,
{
#[inline]
pub fn from_ref<A: ByteOrder, B: Size>(slice: Ref<[T], A, B>) -> Self
where
T: ZeroCopy,
{
Self::from_raw_parts(slice.offset(), slice.len())
}
#[inline]
pub fn from_raw_parts(offset: usize, len: usize) -> Self
where
O: TryFrom<usize>,
L: TryFrom<usize>,
{
let Some(offset) = O::try_from(offset).ok() else {
panic!("Offset {offset:?} not in legal range 0-{}", O::MAX);
};
let Some(len) = L::try_from(len).ok() else {
panic!("Length {len:?} not in legal range 0-{}", L::MAX);
};
Self {
offset: O::swap_bytes::<E>(offset),
len: L::swap_bytes::<E>(len),
_marker: PhantomData,
}
}
#[inline]
pub fn try_from_raw_parts(offset: usize, len: usize) -> Result<Self, Error>
where
O: TryFrom<usize> + IntoRepr,
L: TryFrom<usize> + IntoRepr,
{
let Some(offset) = O::try_from(offset).ok() else {
return Err(Error::new(ErrorKind::InvalidOffsetRange {
offset: usize::into_repr(offset),
max: O::into_repr(O::MAX),
}));
};
let Some(len) = L::try_from(len).ok() else {
return Err(Error::new(ErrorKind::InvalidMetadataRange {
metadata: usize::into_repr(len),
max: L::into_repr(L::MAX),
}));
};
Ok(Self {
offset: O::swap_bytes::<E>(offset),
len: L::swap_bytes::<E>(len),
_marker: PhantomData,
})
}
#[inline]
pub fn get(self, index: usize) -> Option<Ref<T, E, usize>> {
if index >= self.len() {
return None;
}
Some(self.get_unchecked(index))
}
#[inline]
pub fn split_at(self, at: usize) -> (Self, Self) {
let offset = self.offset.as_usize::<E>();
let len = self.len.as_usize::<E>();
assert!(at <= len, "Split point {at} is out of bounds 0..={len}");
let a = Self::from_raw_parts(offset, at);
let b = Self::from_raw_parts(offset + at * size_of::<T>(), len - at);
(a, b)
}
#[inline]
pub fn get_unchecked(self, index: usize) -> Ref<T, E, usize> {
let offset = self.offset.as_usize::<E>() + size_of::<T>() * index;
Ref::new(offset)
}
pub fn offset(self) -> usize {
self.offset.as_usize::<E>()
}
#[inline]
pub fn len(self) -> usize {
self.len.as_usize::<E>()
}
#[inline]
pub fn is_empty(self) -> bool {
self.len.is_zero()
}
}
impl<T, O, L, E> Load for Packed<[T], O, L, E>
where
T: ZeroCopy,
O: Size,
L: Size,
E: ByteOrder,
{
type Target = [T];
#[inline]
fn load<'buf>(&self, buf: &'buf Buf) -> Result<&'buf Self::Target, Error> {
buf.load(Ref::<[T], Native, usize>::with_metadata(
self.offset.as_usize::<E>(),
self.len.as_usize::<E>(),
))
}
}
impl<T, O, L, E> Clone for Packed<[T], O, L, E>
where
O: Size,
L: Size,
E: ByteOrder,
{
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<T, O, L, E> Copy for Packed<[T], O, L, E>
where
O: Size,
L: Size,
E: ByteOrder,
{
}