bump_scope/alloc/
global.rs1#![expect(clippy::unused_self)]
3
4use alloc_crate::alloc::{alloc, alloc_zeroed, dealloc, realloc};
5use core::{
6    alloc::Layout,
7    hint,
8    ptr::{self, NonNull},
9};
10
11use crate::polyfill;
12
13use super::{AllocError, Allocator};
14
15#[derive(Copy, Clone, Default, Debug)]
21pub struct Global;
23
24impl Global {
25    #[inline]
26    #[cfg_attr(miri, track_caller)] fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> {
28        match layout.size() {
29            0 => Ok(NonNull::slice_from_raw_parts(polyfill::layout::dangling(layout), 0)),
30            size => unsafe {
32                let raw_ptr = if zeroed { alloc_zeroed(layout) } else { alloc(layout) };
33                let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
34                Ok(NonNull::slice_from_raw_parts(ptr, size))
35            },
36        }
37    }
38
39    #[inline]
41    #[cfg_attr(miri, track_caller)] unsafe fn grow_impl(
43        &self,
44        ptr: NonNull<u8>,
45        old_layout: Layout,
46        new_layout: Layout,
47        zeroed: bool,
48    ) -> Result<NonNull<[u8]>, AllocError> {
49        debug_assert!(
50            new_layout.size() >= old_layout.size(),
51            "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
52        );
53
54        match old_layout.size() {
55            0 => self.alloc_impl(new_layout, zeroed),
56
57            old_size if old_layout.align() == new_layout.align() => unsafe {
60                let new_size = new_layout.size();
61
62                hint::assert_unchecked(new_size >= old_layout.size());
64
65                let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size);
66                let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
67                if zeroed {
68                    raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
69                }
70                Ok(NonNull::slice_from_raw_parts(ptr, new_size))
71            },
72
73            old_size => unsafe {
79                let new_ptr = self.alloc_impl(new_layout, zeroed)?;
80                ptr::copy_nonoverlapping(ptr.as_ptr(), polyfill::non_null::as_mut_ptr(new_ptr), old_size);
81                self.deallocate(ptr, old_layout);
82                Ok(new_ptr)
83            },
84        }
85    }
86}
87
88unsafe impl Allocator for Global {
89    #[inline]
90    #[cfg_attr(miri, track_caller)] fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
92        self.alloc_impl(layout, false)
93    }
94
95    #[inline]
96    #[cfg_attr(miri, track_caller)] fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
98        self.alloc_impl(layout, true)
99    }
100
101    #[inline]
102    #[cfg_attr(miri, track_caller)] unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
104        if layout.size() != 0 {
105            unsafe { dealloc(ptr.as_ptr(), layout) }
114        }
115    }
116
117    #[inline]
118    #[cfg_attr(miri, track_caller)] unsafe fn grow(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
120        unsafe { self.grow_impl(ptr, old_layout, new_layout, false) }
122    }
123
124    #[inline]
125    #[cfg_attr(miri, track_caller)] unsafe fn grow_zeroed(
127        &self,
128        ptr: NonNull<u8>,
129        old_layout: Layout,
130        new_layout: Layout,
131    ) -> Result<NonNull<[u8]>, AllocError> {
132        unsafe { self.grow_impl(ptr, old_layout, new_layout, true) }
134    }
135
136    #[inline]
137    #[cfg_attr(miri, track_caller)] unsafe fn shrink(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
139        debug_assert!(
140            new_layout.size() <= old_layout.size(),
141            "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
142        );
143
144        match new_layout.size() {
145            0 => unsafe {
147                self.deallocate(ptr, old_layout);
148                Ok(NonNull::slice_from_raw_parts(polyfill::layout::dangling(new_layout), 0))
149            },
150
151            new_size if old_layout.align() == new_layout.align() => unsafe {
153                hint::assert_unchecked(new_size <= old_layout.size());
155
156                let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size);
157                let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
158                Ok(NonNull::slice_from_raw_parts(ptr, new_size))
159            },
160
161            new_size => unsafe {
167                let new_ptr = self.allocate(new_layout)?;
168                ptr::copy_nonoverlapping(ptr.as_ptr(), polyfill::non_null::as_mut_ptr(new_ptr), new_size);
169                self.deallocate(ptr, old_layout);
170                Ok(new_ptr)
171            },
172        }
173    }
174}