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}