dyn_stack/mem.rs
1use crate::stack_req::StackReq;
2use alloc::alloc::handle_alloc_error;
3use core::alloc::Layout;
4use core::mem::ManuallyDrop;
5use core::mem::MaybeUninit;
6use core::ptr::NonNull;
7
8use crate::alloc::*;
9extern crate alloc;
10
11impl core::fmt::Display for AllocError {
12 fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
13 fmt.write_str("memory allocation failed")
14 }
15}
16
17#[cfg(any(feature = "std", feature = "core-error"))]
18impl crate::Error for AllocError {}
19
20use super::*;
21
22#[inline]
23fn to_layout(req: StackReq) -> Result<Layout, AllocError> {
24 req.layout().ok().ok_or(AllocError)
25}
26
27#[cfg(feature = "alloc")]
28#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
29impl MemBuffer {
30 /// Allocate a memory buffer with sufficient storage for the given stack requirements, using the
31 /// global allocator.
32 ///
33 /// Calls [`alloc::alloc::handle_alloc_error`] in the case of failure.
34 ///
35 /// # Example
36 /// ```
37 /// use dyn_stack::{MemStack, StackReq, MemBuffer};
38 ///
39 /// let req = StackReq::new::<i32>(3);
40 /// let mut buf = MemBuffer::new(req);
41 /// let stack = MemStack::new(&mut buf);
42 ///
43 /// // use the stack
44 /// let (arr, _) = stack.make_with::<i32>(3, |i| i as i32);
45 /// ```
46 pub fn new(req: StackReq) -> Self {
47 Self::new_in(req, Global)
48 }
49
50 /// Allocate a memory buffer with sufficient storage for the given stack requirements, using the
51 /// global allocator, or an error if the allocation did not succeed.
52 ///
53 /// # Example
54 /// ```
55 /// use dyn_stack::{MemStack, StackReq, MemBuffer};
56 ///
57 /// let req = StackReq::new::<i32>(3);
58 /// let mut buf = MemBuffer::new(req);
59 /// let stack = MemStack::new(&mut buf);
60 ///
61 /// // use the stack
62 /// let (arr, _) = stack.make_with::<i32>(3, |i| i as i32);
63 /// ```
64 pub fn try_new(req: StackReq) -> Result<Self, AllocError> {
65 Self::try_new_in(req, Global)
66 }
67
68 /// Creates a `MemBuffer` from its raw components.
69 ///
70 /// # Safety
71 ///
72 /// The arguments to this function must have been acquired from a call to
73 /// [`MemBuffer::into_raw_parts`]
74 #[inline]
75 pub unsafe fn from_raw_parts(ptr: *mut u8, len: usize, align: usize) -> Self {
76 Self {
77 ptr: NonNull::new_unchecked(ptr),
78 len,
79 align,
80 alloc: Global,
81 }
82 }
83
84 /// Decomposes a `MemBuffer` into its raw components in this order: ptr, length and
85 /// alignment.
86 #[inline]
87 pub fn into_raw_parts(self) -> (*mut u8, usize, usize) {
88 let no_drop = ManuallyDrop::new(self);
89 (no_drop.ptr.as_ptr(), no_drop.len, no_drop.align)
90 }
91}
92
93#[cfg(feature = "alloc")]
94#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
95impl PodBuffer {
96 /// Allocate a memory buffer with sufficient storage for the given stack requirements, using the
97 /// global allocator.
98 ///
99 /// Calls [`alloc::alloc::handle_alloc_error`] in the case of failure.
100 ///
101 /// # Example
102 /// ```
103 /// use dyn_stack::{PodStack, StackReq, PodBuffer};
104 ///
105 /// let req = StackReq::new::<i32>(3);
106 /// let mut buf = PodBuffer::new(req);
107 /// let stack = PodStack::new(&mut buf);
108 ///
109 /// // use the stack
110 /// let (arr, _) = stack.make_with::<i32>(3, |i| i as i32);
111 /// ```
112 pub fn new(req: StackReq) -> Self {
113 Self::new_in(req, Global)
114 }
115
116 /// Allocate a memory buffer with sufficient storage for the given stack requirements, using the
117 /// global allocator, or an error if the allocation did not succeed.
118 ///
119 /// # Example
120 /// ```
121 /// use dyn_stack::{PodStack, StackReq, PodBuffer};
122 ///
123 /// let req = StackReq::new::<i32>(3);
124 /// let mut buf = PodBuffer::new(req);
125 /// let stack = PodStack::new(&mut buf);
126 ///
127 /// // use the stack
128 /// let (arr, _) = stack.make_with::<i32>(3, |i| i as i32);
129 /// ```
130 pub fn try_new(req: StackReq) -> Result<Self, AllocError> {
131 Self::try_new_in(req, Global)
132 }
133
134 /// Creates a `PodBuffer` from its raw components.
135 ///
136 /// # Safety
137 ///
138 /// The arguments to this function must have been acquired from a call to
139 /// [`PodBuffer::into_raw_parts`]
140 #[inline]
141 pub unsafe fn from_raw_parts(ptr: *mut u8, len: usize, align: usize) -> Self {
142 Self {
143 ptr: NonNull::new_unchecked(ptr),
144 len,
145 align,
146 alloc: Global,
147 }
148 }
149
150 /// Decomposes a `PodBuffer` into its raw components in this order: ptr, length and
151 /// alignment.
152 #[inline]
153 pub fn into_raw_parts(self) -> (*mut u8, usize, usize) {
154 let no_drop = ManuallyDrop::new(self);
155 (no_drop.ptr.as_ptr(), no_drop.len, no_drop.align)
156 }
157}
158
159#[cfg(feature = "alloc")]
160/// Buffer of uninitialized bytes to serve as workspace for dynamic arrays.
161pub struct MemBuffer<A: Allocator = Global> {
162 ptr: NonNull<u8>,
163 len: usize,
164 align: usize,
165 alloc: A,
166}
167
168#[cfg(feature = "alloc")]
169/// Buffer of initialized bytes to serve as workspace for dynamic arrays.
170pub struct PodBuffer<A: Allocator = Global> {
171 ptr: NonNull<u8>,
172 len: usize,
173 align: usize,
174 alloc: A,
175}
176
177#[cfg(not(feature = "alloc"))]
178/// Buffer of uninitialized bytes to serve as workspace for dynamic arrays.
179pub struct MemBuffer<A: Allocator> {
180 ptr: NonNull<u8>,
181 len: usize,
182 align: usize,
183 alloc: A,
184}
185
186#[cfg(not(feature = "alloc"))]
187/// Buffer of initialized bytes to serve as workspace for dynamic arrays.
188pub struct PodBuffer<A: Allocator> {
189 ptr: NonNull<u8>,
190 len: usize,
191 align: usize,
192 alloc: A,
193}
194
195unsafe impl<A: Allocator + Sync> Sync for MemBuffer<A> {}
196unsafe impl<A: Allocator + Send> Send for MemBuffer<A> {}
197
198unsafe impl<A: Allocator + Sync> Sync for PodBuffer<A> {}
199unsafe impl<A: Allocator + Send> Send for PodBuffer<A> {}
200
201impl<A: Allocator> Drop for MemBuffer<A> {
202 #[inline]
203 fn drop(&mut self) {
204 // SAFETY: this was initialized with std::alloc::alloc
205 unsafe {
206 self.alloc.deallocate(
207 self.ptr,
208 Layout::from_size_align_unchecked(self.len, self.align),
209 )
210 }
211 }
212}
213
214impl<A: Allocator> Drop for PodBuffer<A> {
215 #[inline]
216 fn drop(&mut self) {
217 // SAFETY: this was initialized with std::alloc::alloc
218 unsafe {
219 self.alloc.deallocate(
220 self.ptr,
221 Layout::from_size_align_unchecked(self.len, self.align),
222 )
223 }
224 }
225}
226
227impl<A: Allocator> PodBuffer<A> {
228 /// Allocate a memory buffer with sufficient storage for the given stack requirements, using the
229 /// provided allocator.
230 ///
231 /// Calls [`alloc::alloc::handle_alloc_error`] in the case of failure.
232 ///
233 /// # Example
234 /// ```
235 /// use dyn_stack::{PodStack, StackReq, PodBuffer};
236 /// use dyn_stack::alloc::Global;
237 ///
238 /// let req = StackReq::new::<i32>(3);
239 /// let mut buf = PodBuffer::new_in(req, Global);
240 /// let stack = PodStack::new(&mut buf);
241 ///
242 /// // use the stack
243 /// let (arr, _) = stack.make_with::<i32>(3, |i| i as i32);
244 /// ```
245 pub fn new_in(req: StackReq, alloc: A) -> Self {
246 Self::try_new_in(req, alloc).unwrap_or_else(|_| handle_alloc_error(to_layout(req).unwrap()))
247 }
248
249 /// Allocate a memory buffer with sufficient storage for the given stack requirements, using the
250 /// provided allocator, or an `AllocError` in the case of failure.
251 ///
252 /// # Example
253 /// ```
254 /// use dyn_stack::{PodStack, StackReq, PodBuffer};
255 /// use dyn_stack::alloc::Global;
256 ///
257 /// let req = StackReq::new::<i32>(3);
258 /// let mut buf = PodBuffer::new_in(req, Global);
259 /// let stack = PodStack::new(&mut buf);
260 ///
261 /// // use the stack
262 /// let (arr, _) = stack.make_with::<i32>(3, |i| i as i32);
263 /// ```
264 pub fn try_new_in(req: StackReq, alloc: A) -> Result<Self, AllocError> {
265 unsafe {
266 let ptr = &mut *(alloc
267 .allocate_zeroed(to_layout(req)?)
268 .map_err(|_| AllocError)?
269 .as_ptr() as *mut [MaybeUninit<u8>]);
270 #[cfg(debug_assertions)]
271 ptr.fill(MaybeUninit::new(0xCD));
272
273 let len = ptr.len();
274 let ptr = NonNull::new_unchecked(ptr.as_mut_ptr() as *mut u8);
275 Ok(PodBuffer {
276 alloc,
277 ptr,
278 len,
279 align: req.align_bytes(),
280 })
281 }
282 }
283
284 /// Creates a `PodBuffer` from its raw components.
285 ///
286 /// # Safety
287 ///
288 /// The arguments to this function must have been acquired from a call to
289 /// [`PodBuffer::into_raw_parts`]
290 #[inline]
291 pub unsafe fn from_raw_parts_in(ptr: *mut u8, len: usize, align: usize, alloc: A) -> Self {
292 Self {
293 ptr: NonNull::new_unchecked(ptr),
294 len,
295 align,
296 alloc,
297 }
298 }
299
300 /// Decomposes a `PodBuffer` into its raw components in this order: ptr, length and
301 /// alignment.
302 #[inline]
303 pub fn into_raw_parts_with_alloc(self) -> (*mut u8, usize, usize, A) {
304 let me = ManuallyDrop::new(self);
305 (me.ptr.as_ptr(), me.len, me.align, unsafe {
306 core::ptr::read(core::ptr::addr_of!(me.alloc))
307 })
308 }
309}
310
311impl<A: Allocator> MemBuffer<A> {
312 /// Allocate a memory buffer with sufficient storage for the given stack requirements, using the
313 /// provided allocator.
314 ///
315 /// Calls [`alloc::alloc::handle_alloc_error`] in the case of failure.
316 ///
317 /// # Example
318 /// ```
319 /// use dyn_stack::{MemStack, StackReq, MemBuffer};
320 /// use dyn_stack::alloc::Global;
321 ///
322 /// let req = StackReq::new::<i32>(3);
323 /// let mut buf = MemBuffer::new_in(req, Global);
324 /// let stack = MemStack::new(&mut buf);
325 ///
326 /// // use the stack
327 /// let (arr, _) = stack.make_with::<i32>(3, |i| i as i32);
328 /// ```
329 pub fn new_in(req: StackReq, alloc: A) -> Self {
330 Self::try_new_in(req, alloc).unwrap_or_else(|_| handle_alloc_error(to_layout(req).unwrap()))
331 }
332
333 /// Allocate a memory buffer with sufficient storage for the given stack requirements, using the
334 /// provided allocator, or an `AllocError` in the case of failure.
335 ///
336 /// # Example
337 /// ```
338 /// use dyn_stack::{MemStack, StackReq, MemBuffer};
339 /// use dyn_stack::alloc::Global;
340 ///
341 /// let req = StackReq::new::<i32>(3);
342 /// let mut buf = MemBuffer::new_in(req, Global);
343 /// let stack = MemStack::new(&mut buf);
344 ///
345 /// // use the stack
346 /// let (arr, _) = stack.make_with::<i32>(3, |i| i as i32);
347 /// ```
348 pub fn try_new_in(req: StackReq, alloc: A) -> Result<Self, AllocError> {
349 unsafe {
350 let ptr = &mut *(alloc
351 .allocate(to_layout(req)?)
352 .map_err(|_| AllocError)?
353 .as_ptr() as *mut [MaybeUninit<u8>]);
354 let len = ptr.len();
355 let ptr = NonNull::new_unchecked(ptr.as_mut_ptr() as *mut u8);
356 Ok(MemBuffer {
357 alloc,
358 ptr,
359 len,
360 align: req.align_bytes(),
361 })
362 }
363 }
364
365 /// Creates a `MemBuffer` from its raw components.
366 ///
367 /// # Safety
368 ///
369 /// The arguments to this function must have been acquired from a call to
370 /// [`MemBuffer::into_raw_parts`]
371 #[inline]
372 pub unsafe fn from_raw_parts_in(ptr: *mut u8, len: usize, align: usize, alloc: A) -> Self {
373 Self {
374 ptr: NonNull::new_unchecked(ptr),
375 len,
376 align,
377 alloc,
378 }
379 }
380
381 /// Decomposes a `MemBuffer` into its raw components in this order: ptr, length and
382 /// alignment.
383 #[inline]
384 pub fn into_raw_parts_with_alloc(self) -> (*mut u8, usize, usize, A) {
385 let me = ManuallyDrop::new(self);
386 (me.ptr.as_ptr(), me.len, me.align, unsafe {
387 core::ptr::read(core::ptr::addr_of!(me.alloc))
388 })
389 }
390}
391
392impl<A: Allocator> core::ops::Deref for MemBuffer<A> {
393 type Target = [MaybeUninit<u8>];
394
395 #[inline]
396 fn deref(&self) -> &Self::Target {
397 unsafe {
398 core::slice::from_raw_parts(self.ptr.as_ptr() as *const MaybeUninit<u8>, self.len)
399 }
400 }
401}
402
403impl<A: Allocator> core::ops::DerefMut for MemBuffer<A> {
404 #[inline]
405 fn deref_mut(&mut self) -> &mut Self::Target {
406 unsafe {
407 core::slice::from_raw_parts_mut(self.ptr.as_ptr() as *mut MaybeUninit<u8>, self.len)
408 }
409 }
410}
411
412impl<A: Allocator> core::ops::Deref for PodBuffer<A> {
413 type Target = [u8];
414
415 #[inline]
416 fn deref(&self) -> &Self::Target {
417 unsafe { core::slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
418 }
419}
420
421impl<A: Allocator> core::ops::DerefMut for PodBuffer<A> {
422 #[inline]
423 fn deref_mut(&mut self) -> &mut Self::Target {
424 unsafe { core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }
425 }
426}
427
428/// Error during memory allocation.
429#[derive(Debug, Clone, Copy, PartialEq, Eq)]
430pub struct AllocError;