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::traits::ReprC;
6
7/// Represents a trait for types that can provide a message.
8pub trait WithMessage {
9    fn message(&self) -> &str;
10}
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 + ReprC {
20    /// A specific Allocator error. Implementor can add additional
21    /// information to the error, not only generic "allocation failed".
22    type SpecificAllocationError: Debug + ReprC + WithMessage;
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 implementation
32    /// is allowed to provide additional info.
33    fn allocate(&mut 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(&mut 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 implementation
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        &mut 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            let new_size = core::cmp::min(new_layout.size(), old_layout.size());
67            new_ptr.copy_from_nonoverlapping(ptr, new_size);
68            self.deallocate(ptr, old_layout);
69            Ok(new_ptr)
70        }
71    }
72}