use crate::{
extension_traits::{AsOut, Transpose},
AsMaybeUninit,
};
use ::core::{
mem::{self, ManuallyDrop, MaybeUninit},
slice,
};
use core::{marker::PhantomData, ptr::NonNull};
#[derive(Debug)]
#[repr(transparent)]
pub struct Out<'out, T: 'out + ?Sized>(
) must not be written through this pointer.
NonNull<T>,
PhantomData<&'out mut T>,
);
unsafe impl<'out, T: ?Sized + 'out> Send for Out<'out, T> where &'out mut T: Send {}
unsafe impl<'out, T: ?Sized + 'out> Sync for Out<'out, T> where &'out mut T: Sync {}
impl<'out, T: 'out> From<&'out mut MaybeUninit<T>> for Out<'out, T> {
#[inline]
fn from(p: &'out mut MaybeUninit<T>) -> Out<'out, T> {
Out(NonNull::from(p).cast(), PhantomData)
}
}
impl<'out, T> From<&'out mut T> for Out<'out, T>
where
T: ?Sized + AsMaybeUninit + 'out,
T::SizedPart: Copy, {
#[inline]
fn from(p: &'out mut T) -> Out<'out, T> {
Out(NonNull::from(p), PhantomData)
}
}
#[cfg(doc)]
use crate::extension_traits::ManuallyDropMut;
impl<'out, T> From<&'out mut ManuallyDrop<T>> for Out<'out, T>
where
T: ?Sized + 'out,
{
#[inline]
fn from(p: &'out mut ManuallyDrop<T>) -> Out<'out, T> {
Out(NonNull::from(&mut **p), PhantomData)
}
}
impl<'out, T: 'out> From<&'out mut [ManuallyDrop<T>]> for Out<'out, [T]> {
#[inline]
fn from(slice: &'out mut [ManuallyDrop<T>]) -> Out<'out, [T]> {
unsafe {
Out(
NonNull::new_unchecked(slice as *mut _ as *mut [T]),
PhantomData,
)
}
}
}
impl<'out, T: 'out> From<&'out mut [MaybeUninit<T>]> for Out<'out, [T]> {
#[inline]
fn from(slice: &'out mut [MaybeUninit<T>]) -> Out<'out, [T]> {
unsafe {
Out(
NonNull::new_unchecked(slice as *mut _ as *mut [T]),
PhantomData,
)
}
}
}
impl<'out, T: 'out, const N: usize> From<Out<'out, [T; N]>> for Out<'out, [T]> {
#[inline]
fn from(value: Out<'out, [T; N]>) -> Self {
let slice: &mut [MaybeUninit<T>] = unsafe { value.as_mut_uninit().transpose() };
slice.into()
}
}
impl<'out, T: 'out, const N: usize> TryFrom<Out<'out, [T]>> for Out<'out, [T; N]> {
type Error = core::array::TryFromSliceError;
fn try_from(value: Out<'out, [T]>) -> Result<Self, Self::Error> {
let array: &mut [MaybeUninit<T>; N] = unsafe { value.as_mut_uninit() }.try_into()?;
Ok(array.transpose().into())
}
}
impl<'out, T: 'out + ?Sized> Out<'out, T>
where
T: AsMaybeUninit,
{
pub unsafe fn from_raw(raw: *mut T) -> Self {
unsafe { Out(NonNull::new_unchecked(raw), PhantomData) }
}
#[inline]
pub fn reborrow<'reborrow>(self: &'reborrow mut Out<'out, T>) -> Out<'reborrow, T>
where
'out: 'reborrow,
{
Out(self.0, PhantomData)
}
#[inline]
pub fn r<'reborrow>(self: &'reborrow mut Out<'out, T>) -> Out<'reborrow, T>
where
'out: 'reborrow,
{
self.reborrow()
}
#[inline]
pub fn as_mut_ptr(self: &'_ mut Out<'out, T>) -> *mut T {
self.0.as_ptr()
}
#[inline]
pub unsafe fn assume_init(mut self: Out<'out, T>) -> &'out mut T {
unsafe { &mut *self.as_mut_ptr() }
}
#[inline]
pub unsafe fn as_mut_uninit(self: Out<'out, T>) -> &'out mut T::Uninit {
unsafe { T::raw_mut_as_uninit(self.0.as_ptr()) }
}
#[inline]
pub fn as_ref_uninit(self: Out<'out, T>) -> &'out T::Uninit {
unsafe { T::raw_as_uninit(self.0.as_ptr()) }
}
#[cfg(feature = "zerocopy")]
#[cfg_attr(feature = "nightly", doc(cfg(feature = "zerocopy")))]
#[inline]
pub fn as_bytes_out(mut self: Out<'out, T>) -> Out<'out, [u8]>
where
T: zerocopy::FromBytes,
{
let size = mem::size_of_val(self.r().as_ref_uninit());
let p: *mut u8 = self.as_mut_ptr().cast();
unsafe {
Out::slice_from_raw_parts(p, size)
}
}
}
impl<'out, T: 'out> Out<'out, T> {
#[inline]
pub fn write(self: Out<'out, T>, value: T) -> &'out mut T {
unsafe {
self.0.as_ptr().write(value);
self.assume_init()
}
}
#[inline]
pub fn replace(mut self: Out<'out, T>, value: T) -> (MaybeUninit<T>, &'out mut T) {
unsafe {
(
mem::replace(self.r().as_mut_uninit(), MaybeUninit::new(value)),
self.assume_init(),
)
}
}
}
impl<'out, T: 'out> Default for Out<'out, [T]> {
#[inline]
fn default() -> Self {
<&mut [MaybeUninit<T>]>::into(&mut [])
}
}
impl<'out, T: 'out> Out<'out, [T]> {
#[inline]
pub fn from_out(out: Out<'out, T>) -> Out<'out, [T]> {
unsafe { slice::from_mut(out.as_mut_uninit()).as_out() }
}
#[inline]
pub fn get_out<Index>(self: Out<'out, [T]>, idx: Index) -> Option<Index::Output>
where
Index: UsizeOrRange<'out, T>, {
macro_rules! impl_SliceIndex {(
$($Range:ty),+ $(,)?
) => (
$(
impl<'out, T : 'out> SliceIndex<'out, T> for $Range {
type Output = Out<'out, [T]>;
#[inline]
fn idx (self: Self, slice: Out<'out, [T]>)
-> Option<Out<'out, [T]>>
{
unsafe {
slice.as_mut_uninit()
.get_mut(self)
.map(Out::from)
}
}
}
)*
)}
impl<'out, T: 'out> SliceIndex<'out, T> for usize {
type Output = Out<'out, T>;
#[inline]
fn idx(self: usize, slice: Out<'out, [T]>) -> Option<Out<'out, T>> {
unsafe {
slice.as_mut_uninit().get_mut(self).map(Out::from)
}
}
}
impl_SliceIndex! {
::core::ops::Range<usize>,
::core::ops::RangeInclusive<usize>,
::core::ops::RangeFrom<usize>,
::core::ops::RangeTo<usize>,
::core::ops::RangeToInclusive<usize>,
::core::ops::RangeFull,
}
idx.idx(self)
}
#[inline]
pub unsafe fn get_unchecked_out<Index>(self: Out<'out, [T]>, idx: Index) -> Index::Output
where
Index: UsizeOrRange<'out, T>, {
self.get_out(idx).unwrap_or_else(|| {
if cfg!(debug_assertions) {
panic!(concat!(
"Attempted to index out of bounds through unchecked ",
"indexing (this was detected thanks to a check still ",
"being present in debug mode).\n",
r"/!\ THIS IS A BUG AND A SOUNDNESS ISSUE /!\",
"\n",
"Please submit an issue ASAP.",
));
} else {
unsafe { ::core::hint::unreachable_unchecked() }
}
})
}
pub fn copy_from_slice(mut self: Out<'out, [T]>, source_slice: &'_ [T]) -> &'out mut [T]
where
T: Copy,
{
unsafe {
self.r()
.as_mut_uninit()
.copy_from_slice(source_slice.as_ref_uninit());
self.assume_init()
}
}
#[inline]
pub fn fill(self, value: T) -> &'out mut [T]
where
T: Clone,
{
self.fill_with(move || value.clone())
}
#[inline]
pub fn fill_with(mut self, mut f: impl FnMut() -> T) -> &'out mut [T] {
for out in self.iter_out() {
out.write(f());
}
unsafe {
self.assume_init()
}
}
#[inline]
pub fn fill_with_iter(
mut self: Out<'out, [T]>,
iterable: impl IntoIterator<Item = T>,
) -> &'out mut [T] {
let mut iter = iterable.into_iter();
let mut n = 0;
for out in self.iter_out() {
if let Some(val) = iter.next() {
out.write(val);
n += 1;
} else {
break;
}
}
unsafe {
self.get_unchecked_out(..n).assume_init()
}
}
#[inline]
#[deprecated = "use `fill_with_iter` instead"]
pub fn init_with(self: Out<'out, [T]>, iterable: impl IntoIterator<Item = T>) -> &'out mut [T] {
self.fill_with_iter(iterable)
}
#[inline]
pub fn iter_out<'reborrow>(self: &'reborrow mut Out<'out, [T]>) -> iter::IterOut<'reborrow, T> {
self.into_iter()
}
#[inline]
pub fn split_at_out(self: Out<'out, [T]>, idx: usize) -> (Out<'out, [T]>, Out<'out, [T]>) {
let (left, right) = unsafe { self.as_mut_uninit() }.split_at_mut(idx);
(left.as_out(), right.as_out())
}
pub unsafe fn slice_from_raw_parts(data: *mut T, len: usize) -> Out<'out, [T]> {
let mu_slice: &mut [MaybeUninit<T>] =
unsafe { slice::from_raw_parts_mut(data.cast(), len) };
mu_slice.into()
}
pub fn empty() -> Out<'static, [T]> {
let data: &mut [ManuallyDrop<T>] = &mut [];
data.into()
}
}
impl<'out, T: 'out, const N: usize> Out<'out, [T; N]> {
pub fn is_empty(&self) -> bool {
N == 0
}
pub fn len(&self) -> usize {
N
}
pub fn as_slice_out(self) -> Out<'out, [T]> {
self.into()
}
}
impl<'out, T: 'out> ::core::ops::Deref for Out<'out, [T]> {
type Target = [MaybeUninit<T>];
#[inline]
fn deref(&self) -> &[MaybeUninit<T>] {
unsafe { &*(self.0.as_ptr() as *const [MaybeUninit<T>]) }
}
}
use private::{SliceIndex, SliceIndex as UsizeOrRange};
mod private {
use super::*;
pub trait SliceIndex<'out, T> {
type Output: 'out;
fn idx(self: Self, slice: Out<'out, [T]>) -> Option<Self::Output>;
}
}
pub mod iter {
use super::*;
#[allow(missing_debug_implementations)]
pub struct IterOut<'out, T: 'out> {
slice: Out<'out, [T]>,
}
impl<'out, T: 'out> IterOut<'out, T> {
#[inline]
pub fn remaining(self: IterOut<'out, T>) -> Out<'out, [T]> {
self.slice
}
}
impl<'out, T: 'out> IntoIterator for Out<'out, [T]> {
type Item = Out<'out, T>;
type IntoIter = IterOut<'out, T>;
fn into_iter(self: Out<'out, [T]>) -> IterOut<'out, T> {
IterOut { slice: self }
}
}
impl<'out, 'inner: 'out, T: 'inner> IntoIterator for &'out mut Out<'inner, [T]> {
type Item = Out<'out, T>;
type IntoIter = IterOut<'out, T>;
#[inline]
fn into_iter(self: &'out mut Out<'inner, [T]>) -> IterOut<'out, T> {
self.reborrow().into_iter()
}
}
impl<'out, T: 'out> Iterator for IterOut<'out, T> {
type Item = Out<'out, T>;
#[inline]
fn next(self: &'_ mut IterOut<'out, T>) -> Option<Out<'out, T>> {
if self.slice.is_empty() {
return None;
}
let slice = mem::replace(&mut self.slice, Out::default());
let (first, rest) = slice.split_at_out(1);
self.slice = rest;
Some(unsafe { first.get_unchecked_out(0) })
}
}
}