use core::marker::PhantomData;
use core::mem::size_of;
use crate::buf::{Buf, Load};
use crate::endian::{ByteOrder, DefaultEndian, Native};
use crate::error::{CoerceError, CoerceErrorKind, Error};
use crate::pointer::{Pointee, 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, E = DefaultEndian, O = DefaultSize, L = DefaultSize>
where
T: ?Sized,
E: ByteOrder,
O: Size,
L: Size,
{
offset: O,
len: L,
#[zero_copy(ignore)]
_marker: PhantomData<(E, T)>,
}
impl<T, E, O, L> Slice<T> for Packed<[T], E, O, L>
where
T: ZeroCopy,
O: Size + TryFrom<usize>,
L: Size + TryFrom<usize>,
E: ByteOrder,
{
type ItemRef = Ref<T, E, usize>;
#[inline]
fn try_from_ref<A, B>(slice: Ref<[T], A, B>) -> Result<Self, CoerceError>
where
A: ByteOrder,
B: Size,
{
Self::try_with_metadata(slice.offset(), slice.len())
}
#[inline]
fn try_with_metadata(offset: usize, len: usize) -> Result<Self, CoerceError> {
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) -> Result<(Self, Self), CoerceError> {
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, E, O, L> Packed<[T], E, O, L>
where
T: ZeroCopy,
O: Size,
L: Size,
E: ByteOrder,
{
#[inline]
pub fn from_ref<A, B>(slice: Ref<[T], A, B>) -> Self
where
T: ZeroCopy,
A: ByteOrder,
B: Size,
{
Self::from_raw_parts(slice.offset(), slice.len())
}
#[inline]
pub fn from_raw_parts(offset: usize, len: usize) -> Self {
match Self::try_from_raw_parts(offset, len) {
Ok(slice) => slice,
Err(error) => panic!("{error}"),
}
}
#[inline]
pub fn try_from_raw_parts(offset: usize, len: usize) -> Result<Self, CoerceError> {
<[T]>::check_layout(offset, len)?;
Ok(Self {
offset: O::try_from(offset)?.swap_bytes::<E>(),
len: L::try_from(len)?.swap_bytes::<E>(),
_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) -> Result<(Self, Self), CoerceError> {
let offset = self.offset.swap_bytes::<E>().as_usize();
let len = self.len.swap_bytes::<E>().as_usize();
if at > len {
return Err(CoerceError::new(CoerceErrorKind::SplitAt { at, len }));
}
let a = Self::try_from_raw_parts(offset, at)?;
let b = Self::try_from_raw_parts(offset + at * size_of::<T>(), len - at)?;
Ok((a, b))
}
#[inline]
pub fn get_unchecked(self, index: usize) -> Ref<T, E, usize> {
let offset = self.offset.swap_bytes::<E>().as_usize() + size_of::<T>() * index;
Ref::new(offset)
}
pub fn offset(self) -> usize {
self.offset.swap_bytes::<E>().as_usize()
}
#[inline]
pub fn len(self) -> usize {
self.len.swap_bytes::<E>().as_usize()
}
#[inline]
pub fn is_empty(self) -> bool {
self.len.is_zero()
}
}
impl<T, E, O, L> Load for Packed<[T], E, O, L>
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> {
let r = unsafe {
Ref::<[T], Native, usize>::new_unchecked(
self.offset.swap_bytes::<E>().as_usize(),
self.len.swap_bytes::<E>().as_usize(),
)
};
buf.load(r)
}
}
impl<T, E, O, L> Clone for Packed<[T], E, O, L>
where
O: Size,
L: Size,
E: ByteOrder,
{
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<T, E, O, L> Copy for Packed<[T], E, O, L>
where
O: Size,
L: Size,
E: ByteOrder,
{
}