flex_array/alloc/
std_alloc.rs

1pub use alloc_def::Global;
2
3#[cfg(feature = "alloc_unstable")]
4mod alloc_def {
5    /// Re-export the std Global implementation of allocator APIs.
6    pub use std::alloc::Global;
7}
8
9#[cfg(not(feature = "alloc_unstable"))]
10mod alloc_def {
11    use core::ptr;
12    use core::ptr::NonNull;
13    use std::alloc;
14    use std::alloc::Layout;
15
16    use crate::alloc::AllocError;
17    use crate::alloc::AltAllocator;
18
19    /// This is basically a wrapper around the std global allocator APIs.
20    ///
21    /// See:
22    /// <https://doc.rust-lang.org/std/alloc/struct.Global.html>
23    ///
24    /// It has the same name as `Global` since the allocator APIs are
25    /// not stabilized yet. When stabilized this will be just removed.
26    /// Rust's `Global` will be exported for backwards compatibility.
27    #[derive(Debug, Copy, Clone)]
28    pub struct Global;
29
30    unsafe impl AltAllocator for Global {
31        fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
32            // std::alloc::alloc() requires that the layout size be non-zero,
33            // but the allocator API does not require this.
34            if layout.size() == 0 {
35                return Err(AllocError);
36            };
37            let ptr = unsafe { alloc::alloc(layout) };
38            let Some(ptr) = NonNull::new(ptr) else {
39                return Err(AllocError);
40            };
41            return Ok(NonNull::slice_from_raw_parts(ptr, layout.size()));
42        }
43
44        fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
45            if layout.size() == 0 {
46                return Err(AllocError);
47            };
48            let ptr = unsafe { alloc::alloc_zeroed(layout) };
49            let Some(ptr) = NonNull::new(ptr) else {
50                return Err(AllocError);
51            };
52            return Ok(NonNull::slice_from_raw_parts(ptr, layout.size()));
53        }
54
55        unsafe fn deallocate(&self, ptr: ptr::NonNull<u8>, layout: Layout) {
56            unsafe { alloc::dealloc(ptr.as_ptr(), layout) };
57        }
58
59        unsafe fn grow(
60            &self,
61            old_ptr: NonNull<u8>,
62            old_layout: Layout,
63            new_layout: Layout,
64        ) -> Result<NonNull<[u8]>, AllocError> {
65            if new_layout.size() == 0 {
66                return Err(AllocError);
67            }
68
69            let new = unsafe { alloc::realloc(old_ptr.as_ptr(), old_layout, new_layout.size()) };
70            let Some(new) = NonNull::new(new) else {
71                return Err(AllocError);
72            };
73            return Ok(NonNull::slice_from_raw_parts(new, new_layout.size()));
74        }
75
76        unsafe fn grow_zeroed(
77            &self,
78            old_ptr: NonNull<u8>,
79            old_layout: Layout,
80            new_layout: Layout,
81        ) -> Result<NonNull<[u8]>, AllocError> {
82            let old_sz = old_layout.size();
83            let new_sz = new_layout.size();
84
85            // In this case just allocate new zeroed memory.
86            // that way any optimizations for `alloc::alloc_zeroed()`
87            // are used.
88            if old_sz == 0 {
89                return self.allocate_zeroed(new_layout);
90            }
91
92            // Do nothing in this case.
93            // This also means that if it's not true
94            // new_sz is greater than zero.
95            if new_sz <= old_sz {
96                return Ok(NonNull::slice_from_raw_parts(old_ptr, old_layout.size()));
97            }
98
99            let new = unsafe { alloc::realloc(old_ptr.as_ptr(), old_layout, new_layout.size()) };
100            let Some(new) = NonNull::new(new) else {
101                return Err(AllocError);
102            };
103
104            // Move to end of the old data.
105            let start = unsafe { new.add(old_sz) };
106            unsafe {
107                start.write_bytes(0, new_sz - old_sz);
108            };
109
110            return Ok(NonNull::slice_from_raw_parts(new, new_layout.size()));
111        }
112
113        unsafe fn shrink(
114            &self,
115            old_ptr: NonNull<u8>,
116            old_layout: Layout,
117            new_layout: Layout,
118        ) -> Result<NonNull<[u8]>, AllocError> {
119            if new_layout.size() == 0 {
120                return Err(AllocError);
121            }
122            let new = unsafe { alloc::realloc(old_ptr.as_ptr(), old_layout, new_layout.size()) };
123            let Some(new) = NonNull::new(new) else {
124                return Err(AllocError);
125            };
126            return Ok(NonNull::slice_from_raw_parts(new, new_layout.size()));
127        }
128    }
129}