rune_alloc/alloc/
global.rs

1use core::alloc::Layout;
2
3use crate::alloc::{AllocError, Allocator};
4use crate::ptr::{invalid_mut, NonNull};
5
6#[cfg(feature = "alloc")]
7use ::rust_alloc::alloc::{alloc, alloc_zeroed, dealloc};
8
9/// Creates a `NonNull` that is dangling, but well-aligned for this Layout.
10///
11/// Note that the pointer value may potentially represent a valid pointer, which
12/// means this must not be used as a "not yet initialized" sentinel value. Types
13/// that lazily allocate must track initialization by some other means.
14pub(crate) const fn dangling<T>(layout: &Layout) -> NonNull<T> {
15    unsafe { NonNull::new_unchecked(invalid_mut::<T>(layout.align())) }
16}
17
18/// The default global allocator for Rune.
19///
20/// This supports enforcing thread-local memory limits through the [`limit`]
21/// module.
22///
23/// [`limit`]: crate::limit
24#[derive(Default, Debug, Clone, Copy)]
25pub struct Global;
26
27impl Global {
28    /// Release the specified memory from being accounted for.
29    pub(crate) fn release(&self, layout: Layout) {
30        crate::limit::release(layout.size());
31    }
32
33    /// Acquire the specified memory.
34    pub(crate) fn take(&self, layout: Layout) -> Result<(), AllocError> {
35        if !crate::limit::take(layout.size()) {
36            return Err(AllocError { layout });
37        }
38
39        Ok(())
40    }
41
42    #[inline]
43    fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> {
44        self.take(layout)?;
45
46        match layout.size() {
47            0 => Ok(NonNull::slice_from_raw_parts(dangling(&layout), 0)),
48            // SAFETY: `layout` is non-zero in size,
49            size => unsafe {
50                let raw_ptr = if zeroed {
51                    alloc_zeroed(layout)
52                } else {
53                    alloc(layout)
54                };
55
56                let Some(ptr) = NonNull::new(raw_ptr) else {
57                    return Err(AllocError { layout });
58                };
59
60                Ok(NonNull::slice_from_raw_parts(ptr, size))
61            },
62        }
63    }
64}
65
66unsafe impl Allocator for Global {
67    #[inline]
68    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
69        self.alloc_impl(layout, false)
70    }
71
72    #[inline]
73    fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
74        self.alloc_impl(layout, true)
75    }
76
77    unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
78        if layout.size() != 0 {
79            // SAFETY: `layout` is non-zero in size,
80            // other conditions must be upheld by the caller
81            dealloc(ptr.as_ptr(), layout);
82            self.release(layout);
83        }
84    }
85}