use core::{fmt, mem, slice, ptr};
use core::alloc::Layout;
use core::marker::PhantomData;
use crate::boxed::Box;
#[must_use = "This is a pointer-like type that has no effect on its own. Use `init` to insert a value."]
pub struct Uninit<'a, T: ?Sized> {
view: UninitView<'a, T>,
mutable: PhantomData<&'a mut ()>,
}
#[must_use = "This is a pointer-like type that has no effect on its own."]
pub struct UninitView<'a, T: ?Sized> {
ptr: ptr::NonNull<u8>,
len: usize,
lifetime: PhantomData<&'a ()>,
typed: PhantomData<*mut T>,
}
impl Uninit<'_, ()> {
pub unsafe fn from_memory(ptr: ptr::NonNull<u8>, len: usize) -> Self {
Uninit::from_presumed_mutable_view(UninitView {
ptr,
len,
lifetime: PhantomData,
typed: PhantomData,
})
}
pub fn split_layout(&mut self, layout: Layout) -> Option<Self> {
self.view.split_layout(layout)
.map(Self::from_presumed_mutable_view)
}
}
impl<'a> Uninit<'a, ()> {
fn decast<T: ?Sized>(uninit: Uninit<'a, T>) -> Self {
Uninit::from_presumed_mutable_view(UninitView {
ptr: uninit.view.ptr.cast(),
len: uninit.view.len,
lifetime: PhantomData,
typed: PhantomData,
})
}
pub fn split_cast<U>(&mut self) -> Option<Uninit<'a, U>> {
let split = self.split_layout(Layout::new::<U>())?;
let cast = split.cast::<U>().unwrap();
Some(cast)
}
pub fn split_slice<U>(&mut self) -> Option<Uninit<'a, [U]>> {
let layout = Layout::for_value::<[U]>(&[]);
let split = self.split_layout(layout)?;
let cast = split.cast_slice::<U>().unwrap();
Some(cast)
}
}
impl<T> Uninit<'_, T> {
pub fn invent_for_zst() -> Self {
unsafe { Uninit::from_view(UninitView::invent_for_zst()) }
}
}
impl<'a, T> Uninit<'a, T> {
pub unsafe fn from_view(view: UninitView<'a, T>) -> Self {
Self::from_presumed_mutable_view(view)
}
pub fn from_maybe_uninit(mem: &'a mut mem::MaybeUninit<T>) -> Self {
let ptr = ptr::NonNull::new(mem.as_mut_ptr()).unwrap();
let raw = unsafe {
Uninit::from_memory(ptr.cast(), mem::size_of_val(mem))
};
raw.cast().unwrap()
}
pub fn split_at_byte(&mut self, at: usize) -> Option<Uninit<'a, ()>> {
self.view.split_at_byte(at)
.map(Uninit::from_presumed_mutable_view)
}
pub fn cast<U>(self) -> Result<Uninit<'a, U>, Self> {
self.view.cast()
.map(Uninit::from_presumed_mutable_view)
.map_err(Self::from_presumed_mutable_view)
}
pub fn cast_slice<U>(self) -> Result<Uninit<'a, [U]>, Self> {
self.view.cast_slice::<U>()
.map(Uninit::from_presumed_mutable_view)
.map_err(Self::from_presumed_mutable_view)
}
pub fn split_to_fit(&mut self) -> Uninit<'a, ()> {
self.split_at_byte(mem::size_of::<T>()).unwrap()
}
pub fn init(self, val: T) -> &'a mut T {
let ptr = self.as_ptr();
unsafe {
ptr::write(ptr, val);
&mut *ptr
}
}
pub const fn as_ptr(&self) -> *mut T {
self.view.ptr.cast().as_ptr()
}
pub const fn as_non_null(&self) -> ptr::NonNull<T> {
self.view.ptr.cast()
}
pub unsafe fn as_ref(&self) -> &T {
self.view.as_ref()
}
pub unsafe fn as_mut(&mut self) -> &mut T {
&mut *self.as_ptr()
}
pub unsafe fn into_ref(self) -> &'a T {
&*self.as_ptr()
}
pub unsafe fn into_mut(self) -> &'a mut T {
&mut *self.as_ptr()
}
pub fn into_maybe_uninit(self) -> &'a mut mem::MaybeUninit<T> {
unsafe { &mut*(self.as_ptr() as *mut mem::MaybeUninit<T>) }
}
pub fn into_box(self, val: T) -> Box<'a, T> {
Box::new(val, self)
}
pub unsafe fn read(&self) -> T {
ptr::read(self.as_ptr())
}
}
impl<'a, T> Uninit<'a, [T]> {
pub fn empty() -> Self {
Uninit::from_presumed_mutable_view(UninitView {
ptr: ptr::NonNull::<T>::dangling().cast(),
len: 0,
lifetime: PhantomData,
typed: PhantomData,
})
}
pub fn from_maybe_uninit_slice(mem: &'a mut [mem::MaybeUninit<T>]) -> Self {
let size = mem::size_of_val(mem);
let ptr = ptr::NonNull::from(mem);
let raw = unsafe {
Uninit::from_memory(ptr.cast(), size)
};
raw.cast_slice().unwrap()
}
pub const fn as_begin_ptr(&self) -> *mut T {
self.view.ptr.as_ptr() as *mut T
}
pub fn capacity(&self) -> usize {
self.view.capacity()
}
pub fn split_at(&mut self, at: usize) -> Option<Self> {
self.view.split_at(at)
.map(Self::from_presumed_mutable_view)
}
pub fn shrink_to_fit(&mut self) -> Uninit<'a, ()> {
Uninit::decast(self.split_at(self.capacity()).unwrap())
}
pub fn split_first(&mut self) -> Option<Uninit<'a, T>> {
let mut part = self.split_at(1)?;
mem::swap(self, &mut part);
Some(Uninit::decast(part).cast().unwrap())
}
pub fn split_last(&mut self) -> Option<Uninit<'a, T>> {
let split = self.capacity().wrapping_sub(1);
let part = self.split_at(split)?;
Some(Uninit::decast(part).cast().unwrap())
}
pub fn into_maybe_uninit_slice(self) -> &'a mut [mem::MaybeUninit<T>] {
unsafe {
slice::from_raw_parts_mut(
self.as_begin_ptr() as *mut mem::MaybeUninit<T>,
self.capacity())
}
}
}
impl<'a, T: ?Sized> Uninit<'a, T> {
pub fn fits(&self, layout: Layout) -> bool {
self.view.fits(layout)
}
pub fn as_memory(self) -> Uninit<'a, ()> {
Uninit::decast(self)
}
fn from_presumed_mutable_view(view: UninitView<'a, T>) -> Self {
Uninit {
view,
mutable: PhantomData,
}
}
pub fn borrow(&self) -> UninitView<'_, T> {
self.view
}
pub fn borrow_mut(&mut self) -> Uninit<'_, T> {
Uninit::from_presumed_mutable_view(self.view)
}
pub const fn size(&self) -> usize {
self.view.size()
}
}
impl UninitView<'_, ()> {
pub unsafe fn from_memory(ptr: ptr::NonNull<u8>, len: usize) -> Self {
UninitView {
ptr,
len,
lifetime: PhantomData,
typed: PhantomData,
}
}
pub fn split_layout(&mut self, layout: Layout) -> Option<Self> {
let align = self.ptr.as_ptr()
.align_offset(layout.align());
let aligned_len = self.len
.checked_sub(align)
.and_then(|len| len.checked_sub(layout.size()));
if aligned_len.is_none() {
return None;
}
let aligned = self.split_at_byte(align)?;
assert!(aligned.fits(layout));
Some(aligned)
}
}
impl<'a> UninitView<'a, ()> {
fn decast<T: ?Sized>(view: UninitView<'a, T>) -> Self {
UninitView {
ptr: view.ptr.cast(),
len: view.len,
lifetime: PhantomData,
typed: PhantomData,
}
}
pub fn split_cast<U>(&mut self) -> Option<UninitView<'a, U>> {
let split = self.split_layout(Layout::new::<U>())?;
let cast = split.cast::<U>().unwrap();
Some(cast)
}
pub fn split_slice<U>(&mut self) -> Option<UninitView<'a, [U]>> {
let layout = Layout::for_value::<[U]>(&[]);
let split = self.split_layout(layout)?;
let cast = split.cast_slice::<U>().unwrap();
Some(cast)
}
}
impl<T> UninitView<'_, T> {
pub fn invent_for_zst() -> Self {
assert_eq!(mem::size_of::<T>(), 0, "Invented ZST uninit invoked with non-ZST");
let dangling = ptr::NonNull::<T>::dangling();
let raw = unsafe { UninitView::from_memory(dangling.cast(), 0) };
raw.cast().unwrap()
}
}
impl<'a, T> UninitView<'a, T> {
pub fn split_at_byte(&mut self, at: usize) -> Option<UninitView<'a, ()>> {
if self.len < at || at < mem::size_of::<T>() {
return None;
}
let base = self.ptr.as_ptr();
let next_base = unsafe { ptr::NonNull::new_unchecked(base.add(at)) };
let next_len = self.len - at;
self.len = at;
let other = unsafe { UninitView::from_memory(next_base.cast(), next_len) };
Some(other)
}
pub fn from_maybe_uninit(mem: &'a mem::MaybeUninit<T>) -> Self {
let ptr = ptr::NonNull::new(mem.as_ptr() as *mut T).unwrap();
let raw = unsafe {
UninitView::from_memory(ptr.cast(), mem::size_of_val(mem))
};
raw.cast().unwrap()
}
pub fn cast<U>(self) -> Result<UninitView<'a, U>, Self> {
if !self.fits(Layout::new::<U>()) {
return Err(self);
}
Ok(UninitView {
ptr: self.ptr.cast(),
len: self.len,
lifetime: PhantomData,
typed: PhantomData,
})
}
pub fn cast_slice<U>(self) -> Result<UninitView<'a, [U]>, Self> {
let empty = Layout::for_value::<[U]>(&[]);
if !self.fits(empty) {
return Err(self)
}
Ok(UninitView {
ptr: self.ptr,
len: self.len,
lifetime: PhantomData,
typed: PhantomData,
})
}
pub fn split_to_fit(&mut self) -> UninitView<'a, ()> {
self.split_at_byte(mem::size_of::<T>()).unwrap()
}
pub const fn as_ptr(&self) -> *const T {
self.ptr.as_ptr() as *const T
}
pub fn as_non_null(&self) -> ptr::NonNull<T> {
self.ptr.cast()
}
pub unsafe fn as_ref(&self) -> &T {
self.into_ref()
}
pub unsafe fn into_ref(self) -> &'a T {
&*self.as_ptr()
}
pub fn into_maybe_uninit(self) -> &'a mem::MaybeUninit<T> {
unsafe { &*(self.as_ptr() as *const mem::MaybeUninit<T>) }
}
}
impl<'a, T> UninitView<'a, [T]> {
pub fn empty() -> Self {
UninitView {
ptr: ptr::NonNull::<T>::dangling().cast(),
len: 0,
lifetime: PhantomData,
typed: PhantomData,
}
}
pub fn from_maybe_uninit_slice(mem: &'a [mem::MaybeUninit<T>]) -> Self {
let ptr = ptr::NonNull::from(mem);
let raw = unsafe {
UninitView::from_memory(ptr.cast(), mem::size_of_val(mem))
};
raw.cast_slice().unwrap()
}
pub fn as_begin_ptr(&self) -> *const T {
self.ptr.as_ptr() as *const T
}
pub fn capacity(&self) -> usize {
self.size()
.checked_div(mem::size_of::<T>())
.unwrap_or_else(usize::max_value)
}
pub fn split_at(&mut self, at: usize) -> Option<Self> {
let bytes = match at.checked_mul(mem::size_of::<T>()) {
None => return None,
Some(byte) if byte > self.len => return None,
Some(byte) => byte,
};
let next_len = self.len - bytes;
self.len = bytes;
let base = self.ptr.as_ptr();
let next_base = unsafe { ptr::NonNull::new_unchecked(base.add(bytes)) };
let other = unsafe { UninitView::from_memory(next_base, next_len) };
Some(other.cast_slice().unwrap())
}
pub fn shrink_to_fit(&mut self) -> UninitView<'a, ()> {
UninitView::decast(self.split_at(self.capacity()).unwrap())
}
pub fn split_first(&mut self) -> Option<UninitView<'a, T>> {
let mut part = self.split_at(1)?;
mem::swap(self, &mut part);
Some(UninitView::decast(part).cast().unwrap())
}
pub fn split_last(&mut self) -> Option<UninitView<'a, T>> {
let split = self.capacity().wrapping_sub(1);
let part = self.split_at(split)?;
Some(UninitView::decast(part).cast().unwrap())
}
pub fn into_maybe_uninit_slice(self) -> &'a [mem::MaybeUninit<T>] {
unsafe {
slice::from_raw_parts(
self.as_begin_ptr() as *const mem::MaybeUninit<T>,
self.capacity())
}
}
}
impl<'a, T: ?Sized> UninitView<'a, T> {
pub fn fits(&self, layout: Layout) -> bool {
self.ptr.as_ptr().align_offset(layout.align()) == 0
&& layout.size() <= self.len
}
pub fn borrow(&self) -> UninitView<'_, T> {
*self
}
pub const fn size(&self) -> usize {
self.len
}
}
impl<'a, T> From<&'a mut mem::MaybeUninit<T>> for Uninit<'a, T> {
fn from(mem: &'a mut mem::MaybeUninit<T>) -> Self {
Uninit::<T>::from_maybe_uninit(mem)
}
}
impl<'a, T> From<&'a mut [mem::MaybeUninit<T>]> for Uninit<'a, [T]> {
fn from(mem: &'a mut [mem::MaybeUninit<T>]) -> Self {
Uninit::<[T]>::from_maybe_uninit_slice(mem)
}
}
impl<'a, T> From<&'a mem::MaybeUninit<T>> for UninitView<'a, T> {
fn from(mem: &'a mem::MaybeUninit<T>) -> Self {
UninitView::from_maybe_uninit(mem)
}
}
impl<'a, T> From<&'a [mem::MaybeUninit<T>]> for UninitView<'a, [T]> {
fn from(mem: &'a [mem::MaybeUninit<T>]) -> Self {
UninitView::<[T]>::from_maybe_uninit_slice(mem)
}
}
impl<T: ?Sized> fmt::Debug for Uninit<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("Uninit")
.field(&self.view.ptr)
.field(&self.view.len)
.finish()
}
}
impl<T: ?Sized> fmt::Debug for UninitView<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("UninitView")
.field(&self.ptr)
.field(&self.len)
.finish()
}
}
impl<'a, T> From<Uninit<'a, T>> for UninitView<'a, T> {
fn from(uninit: Uninit<'a, T>) -> Self {
uninit.view
}
}
impl<T> Default for Uninit<'_, [T]> {
fn default() -> Self {
Uninit::empty()
}
}
impl<T> Default for UninitView<'_, [T]> {
fn default() -> Self {
UninitView::empty()
}
}
impl<T: ?Sized> Clone for UninitView<'_, T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized> Copy for UninitView<'_, T> { }
#[cfg(test)]
mod tests {
use super::Uninit;
#[test]
fn lifetime_longer() {
fn _long<'a, T>(_: Uninit<'a, &'static T>) { }
}
#[test]
fn lifetime_shorter() {
fn _short<'a, T>(_: Uninit<'static, &'a T>) { }
}
#[test]
fn in_a_struct() {
enum _List<T> {
Nil,
Cons(T, Uninit<'static, T>),
}
}
}