use core::{fmt, mem, ptr, slice};
use core::alloc::Layout;
use core::marker::PhantomData;
#[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> {
ptr: ptr::NonNull<T>,
len: usize,
lifetime: PhantomData<&'a mut T>,
}
#[must_use = "This is a pointer-like type that has no effect on its own."]
pub struct UninitView<'a, T: ?Sized>(
Uninit<'a, T>,
);
impl Uninit<'_, ()> {
pub unsafe fn from_memory(ptr: ptr::NonNull<()>, len: usize) -> Self {
Uninit {
ptr,
len,
lifetime: PhantomData,
}
}
pub fn split_layout(&mut self, layout: Layout) -> Option<Self> {
let align = self.ptr.cast::<u8>().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> Uninit<'a, ()> {
fn decast<T: ?Sized>(uninit: Uninit<'a, T>) -> Self {
Uninit {
ptr: uninit.ptr.cast(),
len: uninit.len,
lifetime: 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> {
fn fits(&self, layout: Layout) -> bool {
self.ptr.as_ptr().align_offset(layout.align()) == 0
&& layout.size() <= self.len
}
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 { Uninit::from_memory(dangling.cast(), 0) };
raw.cast().unwrap()
}
}
impl<'a, T> Uninit<'a, T> {
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, ()>> {
if self.len < at || at < mem::size_of::<T>() {
return None;
}
let base = self.ptr.cast::<u8>().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 { Uninit::from_memory(next_base.cast(), next_len) };
Some(other)
}
pub fn cast<U>(self) -> Result<Uninit<'a, U>, Self> {
if !self.fits(Layout::new::<U>()) {
return Err(self);
}
Ok(Uninit {
ptr: self.ptr.cast(),
len: self.len,
lifetime: PhantomData,
})
}
pub fn cast_slice<U>(self) -> Result<Uninit<'a, [U]>, Self> {
let empty = Layout::for_value::<[U]>(&[]);
if !self.fits(empty) {
return Err(self)
}
let slice = unsafe {
slice::from_raw_parts_mut(self.ptr.cast().as_ptr(), 0)
};
Ok(Uninit {
ptr: slice.into(),
len: self.len,
lifetime: PhantomData,
})
}
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
}
}
}
impl<'a, T> Uninit<'a, [T]> {
pub fn empty() -> Self {
Uninit {
ptr: <&'a mut [T]>::default().into(),
len: 0,
lifetime: PhantomData,
}
}
pub const fn as_begin_ptr(&self) -> *mut T {
self.ptr.as_ptr() as *mut 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 next_base = unsafe { self.as_begin_ptr().add(at) };
let slice = unsafe { slice::from_raw_parts_mut(next_base, 0) };
Some(Uninit {
ptr: slice.into(),
len: next_len,
lifetime: self.lifetime,
})
}
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())
}
}
impl<'a, T: ?Sized> Uninit<'a, T> {
pub fn as_memory(self) -> Uninit<'a, ()> {
Uninit::decast(self)
}
pub fn borrow(&self) -> UninitView<'_, T> {
UninitView(Uninit {
ptr: self.ptr,
len: self.len,
lifetime: PhantomData,
})
}
pub fn borrow_mut(&mut self) -> Uninit<'_, T> {
Uninit {
ptr: self.ptr,
len: self.len,
lifetime: PhantomData,
}
}
pub const fn size(&self) -> usize {
self.len
}
pub const fn as_ptr(&self) -> *mut T {
self.ptr.as_ptr()
}
pub const fn as_non_null(&self) -> ptr::NonNull<T> {
self.ptr
}
pub unsafe fn as_ref(&self) -> &T {
self.ptr.as_ref()
}
pub unsafe fn as_mut(&mut self) -> &mut T {
self.ptr.as_mut()
}
pub unsafe fn into_ref(self) -> &'a T {
&*self.as_ptr()
}
pub unsafe fn into_mut(self) -> &'a mut T {
&mut *self.as_ptr()
}
}
impl UninitView<'_, ()> {
pub fn split_layout(&mut self, layout: Layout) -> Option<Self> {
self.0.split_layout(layout).map(UninitView)
}
}
impl<'a> UninitView<'a, ()> {
pub fn split_cast<U>(&mut self) -> Option<UninitView<'a, U>> {
self.0.split_cast().map(UninitView)
}
pub fn split_slice<U>(&mut self) -> Option<UninitView<'a, [U]>> {
self.0.split_slice().map(UninitView)
}
}
impl<T> UninitView<'_, T> {
pub fn invent_for_zst() -> Self {
UninitView(Uninit::invent_for_zst())
}
}
impl<'a, T> UninitView<'a, T> {
pub fn split_at_byte(&mut self, at: usize) -> Option<UninitView<'a, ()>> {
self.0.split_at_byte(at).map(UninitView)
}
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 {
Uninit::from_memory(ptr.cast(), mem::size_of_val(mem))
};
UninitView(raw).cast().unwrap()
}
pub fn cast<U>(self) -> Result<UninitView<'a, U>, Self> {
self.0.cast::<U>()
.map_err(UninitView)
.map(UninitView)
}
pub fn cast_slice<U>(self) -> Result<UninitView<'a, [U]>, Self> {
self.0.cast_slice::<U>()
.map_err(UninitView)
.map(UninitView)
}
pub fn split_to_fit(&mut self) -> UninitView<'a, ()> {
UninitView(self.0.split_to_fit())
}
}
impl<'a, T> UninitView<'a, [T]> {
pub fn empty() -> Self {
UninitView(Uninit::empty())
}
pub fn as_begin_ptr(&self) -> *const T {
self.0.as_begin_ptr() as *const T
}
pub fn capacity(&self) -> usize {
self.0.capacity()
}
pub fn split_at(&mut self, at: usize) -> Option<Self> {
self.0.split_at(at).map(UninitView)
}
pub fn split_first(&mut self) -> Option<UninitView<'a, T>> {
self.0.split_first().map(UninitView)
}
pub fn split_last(&mut self) -> Option<UninitView<'a, T>> {
self.0.split_last().map(UninitView)
}
}
impl<'a, T: ?Sized> UninitView<'a, T> {
pub fn borrow(&self) -> UninitView<'_, T> {
self.0.borrow()
}
pub const fn size(&self) -> usize {
self.0.size()
}
pub const fn as_ptr(&self) -> *const T {
self.0.as_ptr() as *const T
}
pub fn as_non_null(&self) -> ptr::NonNull<T> {
self.0.as_non_null()
}
pub unsafe fn as_ref(&self) -> &T {
self.0.as_ref()
}
pub unsafe fn into_ref(self) -> &'a T {
&*self.as_ptr()
}
}
impl<'a, T> From<&'a mut mem::MaybeUninit<T>> for Uninit<'a, T> {
fn from(mem: &'a mut mem::MaybeUninit<T>) -> Self {
Uninit::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::from_maybe_uninit(mem)
}
}
impl<T: ?Sized> fmt::Debug for Uninit<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("Uninit")
.field(&self.ptr)
.field(&self.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.0.ptr)
.field(&self.0.len)
.finish()
}
}
impl<T> Default for Uninit<'_, [T]> {
fn default() -> Self {
Uninit::empty()
}
}
impl<T> Default for UninitView<'_, [T]> {
fn default() -> Self {
UninitView::empty()
}
}