use core::marker::PhantomData;
use core::ptr::{self, NonNull};
use core::{mem, str};
use super::drop_entry::{DropEntry, DropFn, drop_shim};
use super::in_chunk::InChunk;
pub(crate) struct Uninit<'a, T: ?Sized> {
ptr: InChunk<T>,
_phantom: PhantomData<&'a mut T>,
}
impl<T: ?Sized> Uninit<'_, T> {
#[inline]
pub(super) fn new(ptr: InChunk<T>) -> Self {
Self {
ptr,
_phantom: PhantomData,
}
}
}
impl<T: ?Sized> Uninit<'_, T> {
#[inline]
pub(crate) unsafe fn rebind<'b>(self) -> Uninit<'b, T> {
Uninit {
ptr: self.ptr,
_phantom: PhantomData,
}
}
}
impl<T: ?Sized> UninitDrop<'_, T> {
#[inline]
pub(crate) unsafe fn rebind<'b>(self) -> UninitDrop<'b, T> {
UninitDrop {
value: self.value,
drop_slot: self.drop_slot,
_phantom: PhantomData,
}
}
}
impl<'a, T> Uninit<'a, T> {
#[inline]
pub(crate) fn init(self, value: T) -> &'a mut T {
let ptr = self.init_raw(value);
unsafe { &mut *ptr.as_ptr() }
}
#[inline]
pub(crate) fn init_raw(self, value: T) -> NonNull<T> {
let raw = self.ptr.as_ptr();
unsafe {
ptr::write(raw, value);
NonNull::new_unchecked(raw)
}
}
}
impl<'a> Uninit<'a, [u8]> {
#[inline]
pub(crate) fn init_copy_from_str(self, src: &str) -> &'a mut str {
let dst = self.init_copy_from_slice(src.as_bytes());
unsafe { str::from_utf8_unchecked_mut(dst) }
}
}
impl<'a, T> Uninit<'a, [T]> {
#[inline]
pub(crate) fn init_copy_from_slice(self, src: &[T]) -> &'a mut [T]
where
T: Copy,
{
let mut slice_ptr = self.init_copy_from_slice_ptr(src);
unsafe { slice_ptr.as_mut() }
}
#[inline]
pub(crate) fn init_copy_from_slice_ptr(self, src: &[T]) -> NonNull<[T]>
where
T: Copy,
{
let slice_ptr = self.ptr.as_non_null();
let len = slice_ptr.len();
debug_assert_eq!(src.len(), len, "init_copy_from_slice: source length must match reservation");
unsafe {
let dst = slice_ptr.as_ptr().cast::<T>();
ptr::copy_nonoverlapping(src.as_ptr(), dst, len);
}
slice_ptr
}
#[inline]
pub(crate) fn init_clone_from_slice(self, src: &[T]) -> &'a mut [T]
where
T: Clone,
{
debug_assert_eq!(
src.len(),
self.ptr.as_non_null().len(),
"init_clone_from_slice: source length must match reservation"
);
self.init_with(|i| src[i].clone())
}
#[inline]
pub(crate) fn init_with<F>(self, f: F) -> &'a mut [T]
where
F: FnMut(usize) -> T,
{
let mut slice_ptr = self.init_with_ptr(f);
unsafe { slice_ptr.as_mut() }
}
#[inline]
#[cfg_attr(test, mutants::skip)] pub(crate) fn init_with_ptr<F>(self, mut f: F) -> NonNull<[T]>
where
F: FnMut(usize) -> T,
{
let slice_ptr = self.ptr.as_non_null();
let len = slice_ptr.len();
unsafe {
let dst = slice_ptr.as_ptr().cast::<T>();
let mut guard = InitGuard { dst, initialized: 0 };
while guard.initialized < len {
dst.add(guard.initialized).write(f(guard.initialized));
guard.initialized += 1;
}
mem::forget(guard);
}
slice_ptr
}
#[inline]
pub(crate) fn init_from_iter<I>(self, iter: I) -> &'a mut [T]
where
I: Iterator<Item = T>,
{
let mut slice_ptr = self.init_from_iter_ptr(iter);
unsafe { slice_ptr.as_mut() }
}
#[inline]
pub(crate) fn init_from_iter_ptr<I>(self, mut iter: I) -> NonNull<[T]>
where
I: Iterator<Item = T>,
{
self.init_with_ptr(|_| {
iter.next()
.expect("iterator yielded fewer elements than ExactSizeIterator::len() reported")
})
}
#[inline]
pub(crate) fn into_raw_buffer(self) -> (NonNull<T>, usize) {
let slice_ptr = self.ptr.as_non_null();
let len = slice_ptr.len();
(slice_ptr.cast::<T>(), len)
}
}
struct InitGuard<T> {
dst: *mut T,
initialized: usize,
}
impl<T> Drop for InitGuard<T> {
#[inline]
fn drop(&mut self) {
unsafe {
ptr::drop_in_place(ptr::slice_from_raw_parts_mut(self.dst, self.initialized));
}
}
}
pub(crate) struct UninitDrop<'a, T: ?Sized> {
value: InChunk<T>,
drop_slot: InChunk<DropEntry>,
_phantom: PhantomData<&'a mut T>,
}
impl<T: ?Sized> UninitDrop<'_, T> {
#[inline]
pub(super) fn new(value: InChunk<T>, drop_slot: InChunk<DropEntry>) -> Self {
Self {
value,
drop_slot,
_phantom: PhantomData,
}
}
}
impl<'a, T> UninitDrop<'a, T> {
#[inline]
pub(crate) fn init(self, value: T) -> &'a mut T {
let ptr = self.init_raw(value);
unsafe { &mut *ptr.as_ptr() }
}
#[inline]
pub(crate) fn init_raw(self, value: T) -> NonNull<T> {
let raw = self.value.as_ptr();
let entry = self.drop_slot.as_ptr();
unsafe {
ptr::write(raw, value);
(*entry).commit_drop_fn(drop_shim::<T> as DropFn);
NonNull::new_unchecked(raw)
}
}
}
impl<'a, T> UninitDrop<'a, [T]> {
#[inline]
pub(crate) fn init_clone_from_slice(self, src: &[T]) -> &'a mut [T]
where
T: Clone,
{
debug_assert_eq!(
src.len(),
self.value.as_non_null().len(),
"init_clone_from_slice: source length must match reservation"
);
self.init_with(|i| src[i].clone())
}
#[inline]
pub(crate) fn init_with<F>(self, f: F) -> &'a mut [T]
where
F: FnMut(usize) -> T,
{
let mut slice_ptr = self.init_with_ptr(f);
unsafe { slice_ptr.as_mut() }
}
#[inline]
#[cfg_attr(test, mutants::skip)] pub(crate) fn init_with_ptr<F>(self, mut f: F) -> NonNull<[T]>
where
F: FnMut(usize) -> T,
{
let slice_ptr = self.value.as_non_null();
let len = slice_ptr.len();
let entry = self.drop_slot.as_ptr();
unsafe {
let dst = slice_ptr.as_ptr().cast::<T>();
let mut guard = InitGuard { dst, initialized: 0 };
while guard.initialized < len {
dst.add(guard.initialized).write(f(guard.initialized));
guard.initialized += 1;
}
mem::forget(guard);
(*entry).commit_drop_fn(drop_shim::<T> as DropFn);
}
slice_ptr
}
#[inline]
pub(crate) fn init_from_iter<I>(self, mut iter: I) -> &'a mut [T]
where
I: Iterator<Item = T>,
{
self.init_with(|_| {
iter.next()
.expect("iterator yielded fewer elements than ExactSizeIterator::len() reported")
})
}
}