use core::fmt;
use core::ptr;
use core::slice;
use super::{
ConcatenateSlice, Error, ErrorKind, IntoMutSliceLikePtr, SliceLike,
};
use core::marker::PhantomData;
use core::mem::forget;
use core::ops::{Deref, DerefMut};
use core::ptr::NonNull;
pub struct Allocation<'marker, T>
where
T: ?Sized,
{
pub(crate) data: NonNull<T>,
pub(crate) _phantom: PhantomData<&'marker ()>,
}
impl<'marker, T> Allocation<'marker, T>
where
T: Sized,
{
pub fn unwrap(self) -> T {
unsafe {
let value = ptr::read(self.data.as_ptr());
forget(self);
value
}
}
}
impl<'marker, T> Allocation<'marker, T>
where
T: ?Sized,
{
#[inline]
pub fn into_slice_like_allocation<U>(self) -> Allocation<'marker, U>
where
T: IntoMutSliceLikePtr<U>,
U: SliceLike + ?Sized,
{
let data = unsafe {
NonNull::new_unchecked(T::into_mut_slice_like_ptr(
self.data.as_ptr(),
))
};
forget(self);
Allocation {
data,
_phantom: PhantomData,
}
}
pub fn concat<U, V>(
self,
other: Allocation<'marker, V>,
) -> Result<
Allocation<'marker, U>,
Error<(Allocation<'marker, T>, Allocation<'marker, V>)>,
>
where
T: IntoMutSliceLikePtr<U>,
U: ConcatenateSlice + ?Sized,
V: IntoMutSliceLikePtr<U> + ?Sized,
{
unsafe {
let data0 = (*T::into_mut_slice_like_ptr(self.data.as_ptr()))
.as_element_slice();
let data1 = (*V::into_mut_slice_like_ptr(other.data.as_ptr()))
.as_element_slice();
let data0_len = data0.len();
let data1_len = data1.len();
assert!(data0_len <= ::core::isize::MAX as usize);
assert!(data1_len <= ::core::isize::MAX as usize);
let data0_start = data0.as_ptr();
let data0_end = data0_start.offset(data0_len as isize);
let data1_start = data1.as_ptr();
if data0_end != data1_start {
return Err(Error::new(
if data0_start < data1_start {
ErrorKind::NotAdjacent
} else {
ErrorKind::OutOfOrder
},
(self, other),
));
}
Ok(self.concat_unchecked(other))
}
}
#[inline]
pub unsafe fn concat_unchecked<U, V>(
self,
other: Allocation<'marker, V>,
) -> Allocation<'marker, U>
where
T: IntoMutSliceLikePtr<U>,
U: ConcatenateSlice + ?Sized,
V: IntoMutSliceLikePtr<U> + ?Sized,
{
let data0 = (*T::into_mut_slice_like_ptr(self.data.as_ptr()))
.as_element_slice_mut();
let data1 = (*V::into_mut_slice_like_ptr(other.data.as_ptr()))
.as_element_slice_mut();
forget(self);
forget(other);
Allocation {
data: NonNull::new(<U as SliceLike>::from_element_slice_mut(
slice::from_raw_parts_mut(
data0.as_mut_ptr(),
data0.len() + data1.len(),
),
)).unwrap(),
_phantom: PhantomData,
}
}
}
impl<'marker, T> Deref for Allocation<'marker, T>
where
T: ?Sized,
{
type Target = T;
#[inline]
fn deref(&self) -> &T {
unsafe { self.data.as_ref() }
}
}
impl<'marker, T> DerefMut for Allocation<'marker, T>
where
T: ?Sized,
{
#[inline]
fn deref_mut(&mut self) -> &mut T {
unsafe { self.data.as_mut() }
}
}
impl<'marker, T> Drop for Allocation<'marker, T>
where
T: ?Sized,
{
#[inline]
fn drop(&mut self) {
unsafe { ptr::drop_in_place(self.data.as_ptr()) };
}
}
impl<'marker, T> fmt::Debug for Allocation<'marker, T>
where
T: ?Sized + fmt::Debug,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
unsafe {
write!(f, "Allocation {{ data: {:?} }}", self.data.as_ref())
}
}
}