ngx/
allocator.rs

1//! The allocator module.
2//!
3//! The module provides custom memory allocator support traits and utilities based on the unstable
4//! [feature(allocator_api)].
5//!
6//! Currently implemented as a reexport of parts of the [allocator_api2].
7//!
8//! [feature(allocator_api)]: https://github.com/rust-lang/rust/issues/32838
9
10use ::core::alloc::Layout;
11use ::core::mem;
12use ::core::ptr::{self, NonNull};
13
14pub use allocator_api2::alloc::{AllocError, Allocator, Global};
15
16#[cfg(feature = "alloc")]
17pub use allocator_api2::{boxed, collections, vec};
18
19/// Explicitly duplicate an object using the specified Allocator.
20pub trait TryCloneIn: Sized {
21    /// Target type, generic over an allocator.
22    type Target<A: Allocator + Clone>;
23
24    /// Attempts to copy the value using `alloc` as an underlying Allocator.
25    fn try_clone_in<A: Allocator + Clone>(&self, alloc: A) -> Result<Self::Target<A>, AllocError>;
26}
27
28/// Moves `value` to the memory backed by `alloc` and returns a pointer.
29///
30/// This should be similar to `Box::into_raw(Box::try_new_in(value, alloc)?)`, except without
31/// `alloc` requirement and intermediate steps.
32///
33/// # Note
34///
35/// The resulting pointer has no owner. The caller is responsible for destroying `T` and releasing
36/// the memory.
37pub fn allocate<T, A>(value: T, alloc: &A) -> Result<NonNull<T>, AllocError>
38where
39    A: Allocator,
40{
41    let layout = Layout::for_value(&value);
42    let ptr: NonNull<T> = alloc.allocate(layout)?.cast();
43
44    // SAFETY: the allocator succeeded and gave us a correctly aligned pointer to an uninitialized
45    // data
46    unsafe { ptr.cast::<mem::MaybeUninit<T>>().as_mut().write(value) };
47
48    Ok(ptr)
49}
50///
51/// Creates a [NonNull] that is dangling, but well-aligned for this [Layout].
52///
53/// See also [::core::alloc::Layout::dangling()]
54#[inline(always)]
55pub(crate) const fn dangling_for_layout(layout: &Layout) -> NonNull<u8> {
56    unsafe {
57        let ptr = ptr::null_mut::<u8>().byte_add(layout.align());
58        NonNull::new_unchecked(ptr)
59    }
60}
61
62#[cfg(feature = "alloc")]
63mod impls {
64    use allocator_api2::boxed::Box;
65
66    use super::*;
67
68    impl<T, OA> TryCloneIn for Box<T, OA>
69    where
70        T: TryCloneIn,
71        OA: Allocator,
72    {
73        type Target<A: Allocator + Clone> = Box<<T as TryCloneIn>::Target<A>, A>;
74
75        fn try_clone_in<A: Allocator + Clone>(
76            &self,
77            alloc: A,
78        ) -> Result<Self::Target<A>, AllocError> {
79            let x = self.as_ref().try_clone_in(alloc.clone())?;
80            Box::try_new_in(x, alloc)
81        }
82    }
83}