Skip to main content

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}