use core::borrow::Borrow;
use core::marker::PhantomData;
use core::mem::{align_of, size_of, size_of_val, ManuallyDrop};
use core::ops::{Deref, DerefMut};
use core::ptr::NonNull;
use core::slice::{self, SliceIndex};
#[cfg(feature = "alloc")]
use alloc::borrow::Cow;
use crate::buf::{self, Buf, DefaultAlignment, Padder, StoreBuf};
use crate::endian::{ByteOrder, Native};
use crate::error::Error;
use crate::mem::MaybeUninit;
use crate::pointer::{DefaultSize, Ref, Size};
use crate::traits::{UnsizedZeroCopy, ZeroCopy};
pub struct SliceMut<'a, E = Native, O = DefaultSize>
where
E: ByteOrder,
O: Size,
{
data: NonNull<u8>,
len: usize,
capacity: usize,
requested: usize,
_marker: PhantomData<(&'a mut [u8], E, O)>,
}
impl<'a> SliceMut<'a> {
pub fn new(bytes: &'a mut [u8]) -> Self {
Self::with_alignment::<DefaultAlignment>(bytes)
}
pub fn with_alignment<T>(bytes: &'a mut [u8]) -> Self {
let align = align_of::<T>();
let capacity = bytes.len();
Self {
data: unsafe { NonNull::new_unchecked(bytes.as_mut_ptr()) },
len: 0,
capacity,
requested: align,
_marker: PhantomData,
}
}
}
impl<'a, E, O> SliceMut<'a, E, O>
where
E: ByteOrder,
O: Size,
{
#[inline]
pub fn with_size<U: Size>(self) -> SliceMut<'a, E, U> {
let this = ManuallyDrop::new(self);
SliceMut {
data: this.data,
len: this.len,
capacity: this.capacity,
requested: this.requested,
_marker: PhantomData,
}
}
#[inline]
pub fn with_byte_order<U>(self) -> SliceMut<'a, U, O>
where
U: ByteOrder,
{
let this = ManuallyDrop::new(self);
SliceMut {
data: this.data,
len: this.len,
capacity: this.capacity,
requested: this.requested,
_marker: PhantomData,
}
}
#[inline]
pub fn len(&self) -> usize {
self.len
}
#[inline]
pub fn clear(&mut self) {
self.len = 0;
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub fn capacity(&self) -> usize {
self.capacity
}
#[inline]
pub fn requested(&self) -> usize {
self.requested
}
#[inline]
pub fn reserve(&mut self, capacity: usize) {
let new_capacity = self.len + capacity;
self.ensure_capacity(new_capacity);
}
#[inline]
pub unsafe fn advance(&mut self, size: usize) {
self.len += size;
}
#[inline]
pub fn as_ptr(&self) -> *const u8 {
self.data.as_ptr() as *const _
}
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut u8 {
self.data.as_ptr()
}
#[inline]
pub fn as_slice(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.as_ptr(), self.len()) }
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len()) }
}
#[inline]
pub fn store_uninit<T>(&mut self) -> Ref<MaybeUninit<T>, E, O>
where
T: ZeroCopy,
{
unsafe {
self.next_offset_with_and_reserve(align_of::<T>(), size_of::<T>());
let offset = self.len;
self.data
.as_ptr()
.add(self.len)
.write_bytes(0, size_of::<T>());
self.len += size_of::<T>();
Ref::new(offset)
}
}
#[inline]
pub fn load_uninit_mut<T, U, I>(
&mut self,
reference: Ref<MaybeUninit<T>, U, I>,
) -> &mut MaybeUninit<T>
where
T: ZeroCopy,
U: ByteOrder,
I: Size,
{
let at = reference.offset();
assert!(at + size_of::<T>() <= self.len, "Length overflow");
unsafe { &mut *(self.data.as_ptr().add(at) as *mut MaybeUninit<T>) }
}
#[inline]
pub fn store<T>(&mut self, value: &T) -> Ref<T, E, O>
where
T: ZeroCopy,
{
self.next_offset_with_and_reserve(align_of::<T>(), size_of::<T>());
unsafe { self.store_unchecked(value) }
}
#[inline]
pub unsafe fn store_unchecked<T>(&mut self, value: &T) -> Ref<T, E, O>
where
T: ZeroCopy,
{
let offset = self.len;
let ptr = NonNull::new_unchecked(self.data.as_ptr().add(offset));
buf::store_unaligned(ptr, value);
self.len += size_of::<T>();
Ref::new(offset)
}
#[cfg(feature = "alloc")]
pub fn to_requested(&self) -> Cow<'_, Buf> {
self.to_aligned_with(self.requested)
}
#[inline]
pub fn store_unsized<T>(&mut self, value: &T) -> Ref<T, E, O>
where
T: ?Sized + UnsizedZeroCopy,
{
unsafe {
let size = size_of_val(value);
self.next_offset_with_and_reserve(T::ALIGN, size);
let offset = self.len;
let ptr = NonNull::new_unchecked(self.data.as_ptr().add(offset));
ptr.as_ptr().copy_from_nonoverlapping(value.as_ptr(), size);
if T::PADDED {
let mut padder = Padder::new(ptr);
value.pad(&mut padder);
padder.remaining_unsized(value);
}
self.len += size;
Ref::with_metadata(offset, value.metadata())
}
}
#[inline(always)]
pub fn store_slice<T>(&mut self, values: &[T]) -> Ref<[T], E, O>
where
T: ZeroCopy,
{
self.store_unsized(values)
}
pub fn extend_from_slice(&mut self, bytes: &[u8]) {
self.reserve(bytes.len());
unsafe {
self.store_bytes(bytes);
}
}
pub(crate) fn fill(&mut self, byte: u8, len: usize) {
self.reserve(len);
unsafe {
let ptr = self.data.as_ptr().add(self.len);
ptr.write_bytes(byte, len);
self.len += len;
}
}
#[inline]
pub(crate) unsafe fn store_bytes<T>(&mut self, values: &[T])
where
T: ZeroCopy,
{
let dst = self.as_mut_ptr().add(self.len);
dst.copy_from_nonoverlapping(values.as_ptr().cast(), size_of_val(values));
self.len += size_of_val(values);
}
#[inline]
pub fn request_align<T>(&mut self)
where
T: ZeroCopy,
{
self.requested = self.requested.max(align_of::<T>());
self.ensure_aligned_and_reserve(align_of::<T>(), size_of::<T>());
}
#[inline]
fn ensure_aligned_and_reserve(&mut self, align: usize, reserve: usize) {
let extra = buf::padding_to(self.len, align);
self.reserve(extra + reserve);
unsafe {
self.data.as_ptr().add(self.len).write_bytes(0, extra);
self.len += extra;
}
}
#[inline]
pub(crate) fn next_offset_with_and_reserve(&mut self, align: usize, reserve: usize) {
self.requested = self.requested.max(align);
self.ensure_aligned_and_reserve(align, reserve);
}
#[inline]
pub fn next_offset<T>(&mut self) -> usize {
self.next_offset_with_and_reserve(align_of::<T>(), size_of::<T>());
self.len
}
#[inline]
fn ensure_capacity(&mut self, new_capacity: usize) {
let new_capacity = new_capacity.max(self.requested);
if self.capacity < new_capacity {
panic!(
"Underlying slice has the capacity {}, but {} bytes are needed",
self.capacity, new_capacity
)
}
}
}
unsafe impl<'a> Send for SliceMut<'a> {}
unsafe impl<'a> Sync for SliceMut<'a> {}
impl<'a, E, O> Deref for SliceMut<'a, E, O>
where
E: ByteOrder,
O: Size,
{
type Target = Buf;
#[inline]
fn deref(&self) -> &Self::Target {
Buf::new(self.as_slice())
}
}
impl<'a, E, O> DerefMut for SliceMut<'a, E, O>
where
E: ByteOrder,
O: Size,
{
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
Buf::new_mut(self.as_mut_slice())
}
}
impl<'a, E, O> AsRef<Buf> for SliceMut<'a, E, O>
where
E: ByteOrder,
O: Size,
{
#[inline]
fn as_ref(&self) -> &Buf {
self
}
}
impl<'a, E, O> AsMut<Buf> for SliceMut<'a, E, O>
where
E: ByteOrder,
O: Size,
{
#[inline]
fn as_mut(&mut self) -> &mut Buf {
self
}
}
impl<'a, E, O> Borrow<Buf> for SliceMut<'a, E, O>
where
E: ByteOrder,
O: Size,
{
#[inline]
fn borrow(&self) -> &Buf {
self.as_ref()
}
}
impl<'a, E, O> StoreBuf for SliceMut<'a, E, O>
where
E: ByteOrder,
O: Size,
{
type ByteOrder = E;
type Size = O;
#[inline]
fn len(&self) -> usize {
SliceMut::len(self)
}
#[inline]
fn truncate(&mut self, len: usize) {
if self.len > len {
self.len = len;
}
}
#[inline]
fn store_unsized<T>(&mut self, value: &T) -> Ref<T, Self::ByteOrder, Self::Size>
where
T: ?Sized + UnsizedZeroCopy,
{
SliceMut::store_unsized(self, value)
}
#[inline]
fn store<T>(&mut self, value: &T) -> Ref<T, Self::ByteOrder, Self::Size>
where
T: ZeroCopy,
{
SliceMut::store(self, value)
}
#[inline]
fn swap<T>(
&mut self,
a: Ref<T, Self::ByteOrder, Self::Size>,
b: Ref<T, Self::ByteOrder, Self::Size>,
) -> Result<(), Error>
where
T: ZeroCopy,
{
Buf::swap(self, a, b)
}
#[inline]
fn align_in_place(&mut self) {
if !buf::is_aligned_with(self.as_ptr(), self.requested) {
panic!("Slice is not aligned by {}", self.requested);
}
}
#[inline]
fn next_offset<T>(&mut self) -> usize {
SliceMut::next_offset::<T>(self)
}
#[inline]
fn next_offset_with_and_reserve(&mut self, align: usize, reserve: usize) {
SliceMut::next_offset_with_and_reserve(self, align, reserve)
}
#[inline]
fn fill(&mut self, byte: u8, len: usize) {
SliceMut::fill(self, byte, len);
}
#[inline]
fn get<I>(&self, index: I) -> Option<&I::Output>
where
I: SliceIndex<[u8]>,
{
Buf::get(self, index)
}
#[inline]
fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
where
I: SliceIndex<[u8]>,
{
Buf::get_mut(self, index)
}
#[inline]
fn as_buf(&self) -> &Buf {
self
}
#[inline]
fn as_mut_buf(&mut self) -> &mut Buf {
self
}
}