osom_lib_alloc/traits.rs
1//! Defines allocator traits.
2
3use core::{alloc::Layout, fmt::Debug, ptr::NonNull};
4
5use osom_lib_reprc::{macros::reprc, traits::ReprC};
6
7/// Represents a generic allocation error. Most likely represents out-of-memory state.
8#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Default)]
9#[reprc]
10pub struct AllocationError;
11
12/// Represents an Allocator.
13///
14/// # Safety
15///
16/// This trait is inherently unsafe, since it depends on well managed
17/// raw pointers. For example it is possible to call [`Allocator::deallocate`]
18/// twice on the same pointer, which is an Undefined Behaviour.
19pub unsafe trait Allocator: Debug + Default + Clone + ReprC + Send + Sync {
20 /// A specific Allocator error. Implementor can add additional
21 /// information to the error, not only generic "allocation failed".
22 type SpecificAllocationError: Into<AllocationError> + Debug + ReprC;
23
24 /// Allocates new piece of memory. This is the only safe
25 /// function here. The returned `ptr` is guaranteed to satisfy
26 /// `layout` requirements (although the implementation is free
27 /// to overallocate and strengthen alignment).
28 ///
29 /// # Errors
30 ///
31 /// An error typically means out-of-memory error. But the implemtation
32 /// is allowed to provide additional info.
33 fn allocate(&self, layout: Layout) -> Result<NonNull<u8>, Self::SpecificAllocationError>;
34
35 /// Deallocates memory.
36 ///
37 /// # Safety
38 ///
39 /// Passed `ptr` has to be created with previous call to [`Allocator::allocate`]
40 /// or [`Allocator::resize`]. Layouts have to match. Using the passed `ptr`
41 /// after the call to this function is an Undefined Behaviour.
42 unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout);
43
44 /// Resizes given `ptr` to the new layout.
45 ///
46 /// # Errors
47 ///
48 /// An error typically means out-of-memory error. But the implemtation
49 /// is allowed to provide additional info.
50 ///
51 /// # Safety
52 ///
53 /// `ptr` has to be a valid pointer created with previous call to
54 /// [`Allocator::allocate`] or [`Allocator::resize`]. `old_layout`
55 /// has to match the pointers layout. Using the passed ptr after
56 /// the call to this function is an Undefined Behaviour. Use the
57 /// return value instead.
58 unsafe fn resize(
59 &self,
60 ptr: NonNull<u8>,
61 old_layout: Layout,
62 new_layout: Layout,
63 ) -> Result<NonNull<u8>, Self::SpecificAllocationError> {
64 unsafe {
65 let new_ptr = self.allocate(new_layout)?;
66 new_ptr.copy_from_nonoverlapping(ptr, new_layout.size());
67 self.deallocate(ptr, old_layout);
68 Ok(new_ptr)
69 }
70 }
71}