flex_array/alloc/alt_alloc.rs
1use core::alloc::Layout;
2use core::ptr::NonNull;
3
4use super::AllocError;
5
6/// The rust allocator API is not stable yet. Therefore, this trait
7/// can be used to implement/wrap a custom allocator in a no_std environment.
8/// It mirrors the unstable allocator API at the moment.
9///
10/// This mirrors the safety requirements of the allocator API:
11/// <https://doc.rust-lang.org/std/alloc/trait.Allocator.html>
12///
13///
14/// If the allocator api is ever marked as stable this trait probably can
15/// be removed.
16pub unsafe trait AltAllocator {
17 /// Allocates a chunk of memory with the given layout.
18 ///
19 /// On success it returns a pointer to the allocated memory.
20 ///
21 /// If the allocation fails or has some kinda of error it will return
22 /// an `AllocError`.
23 fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>;
24
25 /// Allocates just like `allocate` but also zeroes the memory.
26 fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
27 let ret = self.allocate(layout)?;
28 let ptr = ret.cast::<u8>();
29 unsafe { ptr.write_bytes(0, ret.len()) };
30 return Ok(ret);
31 }
32
33 /// Deallocates the chunk of memory pointed at by`ptr`
34 ///
35 /// This memory must have only been allocated by this allocator.
36 /// The layout must match the layout provided when the chunk was
37 /// allocated.
38 unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout);
39
40 /// Grows the memory pointed at by `old_ptr` to the new layout.
41 ///
42 /// The new layout must be larger than the old layout.
43 ///
44 /// If this fails the old ptr must still will be valid. If it succeeds
45 /// the old ptr is not longer valid, and the ptr returned must be used
46 /// instead.
47 unsafe fn grow(
48 &self,
49 old_ptr: NonNull<u8>,
50 old_layout: Layout,
51 new_layout: Layout,
52 ) -> Result<NonNull<[u8]>, AllocError> {
53 let new = self.allocate(new_layout)?;
54 let ptr = new.cast::<u8>();
55
56 // Copy the old data to the new location
57 unsafe { ptr.copy_from_nonoverlapping(old_ptr, old_layout.size()) };
58 // free the old memory
59 unsafe { self.deallocate(old_ptr, old_layout) };
60 return Ok(new);
61 }
62
63 /// Behaves just like `grow` but the new memory will be zeroed.
64 unsafe fn grow_zeroed(
65 &self,
66 old_ptr: NonNull<u8>,
67 old_layout: Layout,
68 new_layout: Layout,
69 ) -> Result<NonNull<[u8]>, AllocError> {
70 let new = self.allocate_zeroed(new_layout)?;
71 let ptr = new.cast::<u8>();
72
73 // Copy the old data to the new location
74 unsafe { ptr.copy_from_nonoverlapping(old_ptr, old_layout.size()) };
75 // free the old memory
76 unsafe { self.deallocate(old_ptr, old_layout) };
77 return Ok(new);
78 }
79
80 /// Shrinks the memory pointed at by `old_ptr` to the new layout.
81 /// The new layout must be smaller than the old layout.
82 ///
83 /// If this fails the old ptr will still be valid. If it succeeds
84 /// the old ptr is not longer valid, and the ptr returned must be used
85 /// instead.
86 unsafe fn shrink(
87 &self,
88 old_ptr: NonNull<u8>,
89 old_layout: Layout,
90 new_layout: Layout,
91 ) -> Result<NonNull<[u8]>, AllocError> {
92 let new = self.allocate(new_layout)?;
93 let ptr = new.cast::<u8>();
94
95 // Copy the old data to the new location
96 unsafe { ptr.copy_from_nonoverlapping(old_ptr, new_layout.size()) };
97 // free the old memory
98 unsafe { self.deallocate(old_ptr, old_layout) };
99 return Ok(new);
100 }
101}