use crate::stack_req::StackReq;
use alloc::alloc::handle_alloc_error;
use core::alloc::Layout;
use core::mem::{ManuallyDrop, MaybeUninit};
use core::ptr::NonNull;
use crate::alloc::*;
extern crate alloc;
impl core::fmt::Display for AllocError {
fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
fmt.write_str("memory allocation failed")
}
}
#[cfg(any(feature = "std", feature = "core-error"))]
impl crate::Error for AllocError {}
use super::*;
#[inline]
fn to_layout(req: StackReq) -> Result<Layout, AllocError> {
req.layout().ok().ok_or(AllocError)
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl MemBuffer {
pub fn new(req: StackReq) -> Self {
Self::new_in(req, Global)
}
pub fn try_new(req: StackReq) -> Result<Self, AllocError> {
Self::try_new_in(req, Global)
}
#[inline]
pub unsafe fn from_raw_parts(ptr: *mut u8, len: usize, align: usize) -> Self {
Self {
ptr: NonNull::new_unchecked(ptr),
len,
align,
alloc: Global,
}
}
#[inline]
pub fn into_raw_parts(self) -> (*mut u8, usize, usize) {
let no_drop = ManuallyDrop::new(self);
(no_drop.ptr.as_ptr(), no_drop.len, no_drop.align)
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl PodBuffer {
pub fn new(req: StackReq) -> Self {
Self::new_in(req, Global)
}
pub fn try_new(req: StackReq) -> Result<Self, AllocError> {
Self::try_new_in(req, Global)
}
#[inline]
pub unsafe fn from_raw_parts(ptr: *mut u8, len: usize, align: usize) -> Self {
Self {
ptr: NonNull::new_unchecked(ptr),
len,
align,
alloc: Global,
}
}
#[inline]
pub fn into_raw_parts(self) -> (*mut u8, usize, usize) {
let no_drop = ManuallyDrop::new(self);
(no_drop.ptr.as_ptr(), no_drop.len, no_drop.align)
}
}
#[cfg(feature = "alloc")]
pub struct MemBuffer<A: Allocator = Global> {
ptr: NonNull<u8>,
len: usize,
align: usize,
alloc: A,
}
#[cfg(feature = "alloc")]
pub struct PodBuffer<A: Allocator = Global> {
ptr: NonNull<u8>,
len: usize,
align: usize,
alloc: A,
}
#[cfg(not(feature = "alloc"))]
pub struct MemBuffer<A: Allocator> {
ptr: NonNull<u8>,
len: usize,
align: usize,
alloc: A,
}
#[cfg(not(feature = "alloc"))]
pub struct PodBuffer<A: Allocator> {
ptr: NonNull<u8>,
len: usize,
align: usize,
alloc: A,
}
unsafe impl<A: Allocator + Sync> Sync for MemBuffer<A> {}
unsafe impl<A: Allocator + Send> Send for MemBuffer<A> {}
unsafe impl<A: Allocator + Sync> Sync for PodBuffer<A> {}
unsafe impl<A: Allocator + Send> Send for PodBuffer<A> {}
impl<A: Allocator> Drop for MemBuffer<A> {
#[inline]
fn drop(&mut self) {
unsafe { self.alloc.deallocate(self.ptr, Layout::from_size_align_unchecked(self.len, self.align)) }
}
}
impl<A: Allocator> Drop for PodBuffer<A> {
#[inline]
fn drop(&mut self) {
unsafe { self.alloc.deallocate(self.ptr, Layout::from_size_align_unchecked(self.len, self.align)) }
}
}
impl<A: Allocator> PodBuffer<A> {
pub fn new_in(req: StackReq, alloc: A) -> Self {
Self::try_new_in(req, alloc).unwrap_or_else(|_| handle_alloc_error(to_layout(req).unwrap()))
}
pub fn try_new_in(req: StackReq, alloc: A) -> Result<Self, AllocError> {
unsafe {
let ptr = &mut *(alloc.allocate_zeroed(to_layout(req)?).map_err(|_| AllocError)?.as_ptr() as *mut [MaybeUninit<u8>]);
#[cfg(debug_assertions)]
ptr.fill(MaybeUninit::new(0xCD));
let len = ptr.len();
let ptr = NonNull::new_unchecked(ptr.as_mut_ptr() as *mut u8);
Ok(PodBuffer {
alloc,
ptr,
len,
align: req.align_bytes(),
})
}
}
#[inline]
pub unsafe fn from_raw_parts_in(ptr: *mut u8, len: usize, align: usize, alloc: A) -> Self {
Self {
ptr: NonNull::new_unchecked(ptr),
len,
align,
alloc,
}
}
#[inline]
pub fn into_raw_parts_with_alloc(self) -> (*mut u8, usize, usize, A) {
let me = ManuallyDrop::new(self);
(me.ptr.as_ptr(), me.len, me.align, unsafe {
core::ptr::read(core::ptr::addr_of!(me.alloc))
})
}
}
impl<A: Allocator> MemBuffer<A> {
pub fn new_in(req: StackReq, alloc: A) -> Self {
Self::try_new_in(req, alloc).unwrap_or_else(|_| handle_alloc_error(to_layout(req).unwrap()))
}
pub fn try_new_in(req: StackReq, alloc: A) -> Result<Self, AllocError> {
unsafe {
let ptr = &mut *(alloc.allocate(to_layout(req)?).map_err(|_| AllocError)?.as_ptr() as *mut [MaybeUninit<u8>]);
let len = ptr.len();
let ptr = NonNull::new_unchecked(ptr.as_mut_ptr() as *mut u8);
Ok(MemBuffer {
alloc,
ptr,
len,
align: req.align_bytes(),
})
}
}
#[inline]
pub unsafe fn from_raw_parts_in(ptr: *mut u8, len: usize, align: usize, alloc: A) -> Self {
Self {
ptr: NonNull::new_unchecked(ptr),
len,
align,
alloc,
}
}
#[inline]
pub fn into_raw_parts_with_alloc(self) -> (*mut u8, usize, usize, A) {
let me = ManuallyDrop::new(self);
(me.ptr.as_ptr(), me.len, me.align, unsafe {
core::ptr::read(core::ptr::addr_of!(me.alloc))
})
}
}
impl<A: Allocator> core::ops::Deref for MemBuffer<A> {
type Target = [MaybeUninit<u8>];
#[inline]
fn deref(&self) -> &Self::Target {
unsafe { core::slice::from_raw_parts(self.ptr.as_ptr() as *const MaybeUninit<u8>, self.len) }
}
}
impl<A: Allocator> core::ops::DerefMut for MemBuffer<A> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { core::slice::from_raw_parts_mut(self.ptr.as_ptr() as *mut MaybeUninit<u8>, self.len) }
}
}
impl<A: Allocator> core::ops::Deref for PodBuffer<A> {
type Target = [u8];
#[inline]
fn deref(&self) -> &Self::Target {
unsafe { core::slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
}
}
impl<A: Allocator> core::ops::DerefMut for PodBuffer<A> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AllocError;