1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
use crate::stack_req::StackReq;
use core::mem::MaybeUninit;
use core::ptr::NonNull;
use alloc::alloc::{handle_alloc_error, AllocError, Allocator, Global, Layout};
/// Buffer of uninitialized bytes to serve as workspace for dynamic arrays.
pub struct MemBuffer<A: Allocator = Global> {
alloc: A,
ptr: NonNull<u8>,
size: usize,
align: usize,
}
impl<A: Allocator> Drop for MemBuffer<A> {
fn drop(&mut self) {
// SAFETY: this was initialized with std::alloc::alloc
unsafe {
self.alloc.deallocate(
self.ptr,
Layout::from_size_align_unchecked(self.size, self.align),
)
}
}
}
fn to_layout(req: StackReq) -> Layout {
unsafe { Layout::from_size_align_unchecked(req.size_bytes(), req.align_bytes()) }
}
/// Allocate a memory buffer with sufficient storage for the given stack requirements, using the
/// provided allocator.
///
/// Calls [`std::alloc::handle_alloc_error`] in the case of failure.
///
/// # Example
/// ```
/// #![feature(allocator_api)]
///
/// use dynstack::{DynStack, StackReq, uninit_mem_in};
/// use std::alloc::Global;
///
/// let req = StackReq::new::<i32>(3);
/// let mut buf = uninit_mem_in(Global, req);
/// let stack = DynStack::new(&mut buf);
///
/// // use the stack
/// let (arr, _) = stack.make_with::<i32, _>(3, |i| i as i32);
/// ```
pub fn uninit_mem_in<A: Allocator>(alloc: A, req: StackReq) -> MemBuffer<A> {
try_uninit_mem_in(alloc, req).unwrap_or_else(|_| handle_alloc_error(to_layout(req)))
}
/// Allocate a memory buffer with sufficient storage for the given stack requirements, using the
/// global allocator.
///
/// Calls [`std::alloc::handle_alloc_error`] in the case of failure.
///
/// # Example
/// ```
/// #![feature(allocator_api)]
///
/// use dynstack::{DynStack, StackReq, uninit_mem};
///
/// let req = StackReq::new::<i32>(3);
/// let mut buf = uninit_mem(req);
/// let stack = DynStack::new(&mut buf);
///
/// // use the stack
/// let (arr, _) = stack.make_with::<i32, _>(3, |i| i as i32);
/// ```
pub fn uninit_mem(req: StackReq) -> MemBuffer {
uninit_mem_in(Global, req)
}
/// Allocate a memory buffer with sufficient storage for the given stack requirements, using the
/// provided allocator, or an `AllocError` in the case of failure.
///
/// # Example
/// ```
/// #![feature(allocator_api)]
///
/// use dynstack::{DynStack, StackReq, try_uninit_mem_in};
/// use std::alloc::Global;
///
/// let req = StackReq::new::<i32>(3);
/// let mut buf = try_uninit_mem_in(Global, req).unwrap();
/// let stack = DynStack::new(&mut buf);
///
/// // use the stack
/// let (arr, _) = stack.make_with::<i32, _>(3, |i| i as i32);
/// ```
pub fn try_uninit_mem_in<A: Allocator>(
alloc: A,
req: StackReq,
) -> Result<MemBuffer<A>, AllocError> {
unsafe {
let ptr = alloc.allocate(to_layout(req))?;
let size = ptr.len();
let ptr = NonNull::new_unchecked(ptr.as_mut_ptr());
Ok(MemBuffer {
alloc,
ptr,
size,
align: req.align_bytes(),
})
}
}
/// Allocate a memory buffer with sufficient storage for the given stack requirements, using the
/// global allocator, or an `AllocError` in the case of failure.
///
/// # Example
/// ```
/// #![feature(allocator_api)]
///
/// use dynstack::{DynStack, StackReq, try_uninit_mem};
///
/// let req = StackReq::new::<i32>(3);
/// let mut buf = try_uninit_mem(req).unwrap();
/// let stack = DynStack::new(&mut buf);
///
/// // use the stack
/// let (arr, _) = stack.make_with::<i32, _>(3, |i| i as i32);
/// ```
pub fn try_uninit_mem(req: StackReq) -> Result<MemBuffer, AllocError> {
try_uninit_mem_in(Global, req)
}
impl<A: Allocator> core::ops::Deref for MemBuffer<A> {
type Target = [MaybeUninit<u8>];
fn deref(&self) -> &Self::Target {
unsafe {
core::slice::from_raw_parts(self.ptr.as_ptr() as *const MaybeUninit<u8>, self.size)
}
}
}
impl<A: Allocator> core::ops::DerefMut for MemBuffer<A> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe {
core::slice::from_raw_parts_mut(self.ptr.as_ptr() as *mut MaybeUninit<u8>, self.size)
}
}
}