use core::{
alloc::{Allocator, Layout},
any::type_name,
cmp, fmt,
mem::{self, ManuallyDrop, MaybeUninit},
ptr::NonNull,
};
use crate::{AllocateError, HeaderOpaqueNodePtr};
pub trait StructureHandle<U>
where
U: ?Sized,
{
type Allocator: Allocator;
unsafe fn insert(self, node: HeaderOpaqueNodePtr<U>);
fn allocator(&self) -> &Self::Allocator;
unsafe fn deallocate(&self, node: HeaderOpaqueNodePtr<U>);
}
pub struct MaybeUninitNode<U, S>
where
U: ?Sized,
S: StructureHandle<U>,
{
structure: S,
node: HeaderOpaqueNodePtr<U>,
}
macro_rules! init_docs {
() => {
init_docs!(# U, " with the metadata the node was created with")
};
(T) => {
init_docs!(# T, "")
};
(# $t:ty, $validity:literal ) => {
concat!(
r"
# Safety
The value must:
- have been initialised
- be valid for `",
stringify!($t),
"`", $validity, r"
- not have been dropped
- not have been copied unless it is [`Copy`]
"
)
};
}
pub const unsafe fn new_maybe_uninit<U, S>(
structure: S,
node: HeaderOpaqueNodePtr<U>,
) -> MaybeUninitNode<U, S>
where
U: ?Sized,
S: StructureHandle<U>,
{
MaybeUninitNode { structure, node }
}
impl<U, S> MaybeUninitNode<U, S>
where
U: ?Sized,
S: StructureHandle<U>,
{
#[must_use]
#[inline]
pub const fn value_ptr(&self) -> NonNull<()> {
self.node.value_ptr()
}
#[must_use]
#[inline]
pub const fn as_ptr(&self) -> NonNull<U> {
NonNull::from_raw_parts(
self.value_ptr(),
unsafe { self.node.metadata() },
)
}
fn into_parts(self) -> (S, HeaderOpaqueNodePtr<U>) {
let node = self.node;
let structure = {
let mut me = ManuallyDrop::new(self);
unsafe { NonNull::from_mut(&mut me.structure).read() }
};
(structure, node)
}
#[inline]
#[doc = init_docs!()]
pub unsafe fn drop_in_place(&mut self) {
unsafe { self.as_ptr().drop_in_place() };
}
#[doc = init_docs!()]
pub unsafe fn insert(self) {
let (structure, node) = self.into_parts();
unsafe { structure.insert(node) };
}
#[cfg(feature = "alloc")]
#[doc = init_docs!()]
pub unsafe fn try_take_boxed_in<A>(self, allocator: A) -> Result<Box<U, A>, AllocateError<Self>>
where
A: Allocator,
{
let value_layout = unsafe { Layout::for_value_raw(self.as_ptr().as_ptr()) };
let ptr = match allocator.allocate(value_layout) {
Ok(value) => value,
Err(error) => {
return Err(AllocateError::new_alloc(error, value_layout).with_value(self))
}
};
let metadata = unsafe { self.node.metadata() };
unsafe {
ptr.cast::<u8>()
.copy_from_nonoverlapping(self.value_ptr().cast(), value_layout.size());
}
drop(self);
let ptr = NonNull::from_raw_parts(ptr.cast::<()>(), metadata);
Ok(
unsafe { crate::alloc::Box::from_raw_in(ptr.as_ptr(), allocator) },
)
}
#[cfg(feature = "alloc")]
#[doc = init_docs!()]
pub unsafe fn try_take_boxed(
self,
) -> Result<crate::alloc::Box<U, S::Allocator>, AllocateError<Self>>
where
S::Allocator: Clone,
{
let allocator = self.structure.allocator().clone();
unsafe { self.try_take_boxed_in(allocator) }
}
#[cfg(feature = "alloc")]
#[must_use]
#[doc = init_docs!()]
pub unsafe fn take_boxed_in<A>(self, allocator: A) -> crate::alloc::Box<U, A>
where
A: Allocator,
{
match unsafe { Self::try_take_boxed_in(self, allocator) } {
Ok(value) => value,
Err(error) => {
let (mut node, error) = error.into_parts();
unsafe { node.drop_in_place() };
error.handle()
}
}
}
#[cfg(feature = "alloc")]
#[must_use]
#[doc = init_docs!()]
pub unsafe fn take_boxed(self) -> crate::alloc::Box<U, S::Allocator>
where
S::Allocator: Clone,
{
let allocator = self.structure.allocator().clone();
unsafe { self.take_boxed_in(allocator) }
}
}
impl<U, S> Drop for MaybeUninitNode<U, S>
where
U: ?Sized,
S: StructureHandle<U>,
{
fn drop(&mut self) {
unsafe { self.structure.deallocate(self.node) };
}
}
impl<T, S> MaybeUninitNode<T, S>
where
S: StructureHandle<T>,
{
#[must_use]
#[inline]
#[doc = init_docs!(T)]
pub unsafe fn take(self) -> T {
unsafe { self.as_ptr().read() }
}
}
impl<T, S> MaybeUninitNode<[T], S>
where
S: StructureHandle<[T]>,
{
pub fn copy_from_slice(&mut self, src: &[T])
where
T: Copy,
{
let dest = self.as_mut();
let len = cmp::min(dest.len(), src.len());
MaybeUninit::copy_from_slice(&mut dest[..len], &src[..len]);
}
pub fn clone_from_slice(&mut self, src: &[T])
where
T: Clone,
{
struct DropGuard<'a, T, S>
where
S: StructureHandle<[T]>,
{
node: &'a mut MaybeUninitNode<[T], S>,
len: usize,
}
impl<T, S> Drop for DropGuard<'_, T, S>
where
S: StructureHandle<[T]>,
{
fn drop(&mut self) {
self.node.as_mut()[..self.len].iter_mut().for_each(|value| {
unsafe { value.assume_init_drop() }
});
}
}
let mut guard = DropGuard { node: self, len: 0 };
for (dst, value) in guard.node.as_mut().iter_mut().zip(src) {
dst.write(value.clone());
guard.len += 1;
}
mem::forget(guard);
}
}
impl<S> MaybeUninitNode<str, S>
where
S: StructureHandle<str>,
{
#[must_use]
pub const fn as_bytes(&self) -> &[MaybeUninit<u8>] {
let (ptr, length) = self.as_ptr().to_raw_parts();
let ptr = NonNull::from_raw_parts(ptr, length);
unsafe { ptr.as_uninit_slice() }
}
pub fn as_bytes_mut(&mut self) -> &mut [MaybeUninit<u8>] {
let (ptr, length) = self.as_ptr().to_raw_parts();
let ptr = NonNull::from_raw_parts(ptr, length);
unsafe { ptr.as_uninit_slice_mut() }
}
pub fn copy_from_str(&mut self, src: &str) {
let dest = self.as_bytes_mut();
let len = cmp::min(dest.len(), src.len());
MaybeUninit::copy_from_slice(&mut self.as_bytes_mut()[..len], &src.as_bytes()[..len]);
}
}
unsafe impl<U, S> Send for MaybeUninitNode<U, S>
where
U: ?Sized + Send,
S: StructureHandle<U> + Send,
{
}
unsafe impl<U, S> Sync for MaybeUninitNode<U, S>
where
U: ?Sized + Sync,
S: StructureHandle<U> + Sync,
{
}
impl<T, S> AsRef<MaybeUninit<T>> for MaybeUninitNode<T, S>
where
S: StructureHandle<T>,
{
#[must_use]
#[inline]
fn as_ref(&self) -> &MaybeUninit<T> {
unsafe { self.as_ptr().as_uninit_ref() }
}
}
impl<T, S> AsRef<[MaybeUninit<T>]> for MaybeUninitNode<[T], S>
where
S: StructureHandle<[T]>,
{
#[must_use]
#[inline]
fn as_ref(&self) -> &[MaybeUninit<T>] {
unsafe { self.as_ptr().as_uninit_slice() }
}
}
impl<T, S> AsMut<MaybeUninit<T>> for MaybeUninitNode<T, S>
where
S: StructureHandle<T>,
{
#[must_use]
#[inline]
fn as_mut(&mut self) -> &mut MaybeUninit<T> {
unsafe { self.as_ptr().as_uninit_mut() }
}
}
impl<T, S> AsMut<[MaybeUninit<T>]> for MaybeUninitNode<[T], S>
where
S: StructureHandle<[T]>,
{
#[must_use]
#[inline]
fn as_mut(&mut self) -> &mut [MaybeUninit<T>] {
unsafe { self.as_ptr().as_uninit_slice_mut() }
}
}
impl<U, S> fmt::Debug for MaybeUninitNode<U, S>
where
U: ?Sized,
S: StructureHandle<U>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("MaybeUninitNode")
.field(&type_name::<U>())
.finish()
}
}
impl<U, S> fmt::Pointer for MaybeUninitNode<U, S>
where
U: ?Sized,
S: StructureHandle<U>,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Pointer::fmt(&self.node, f)
}
}