iceoryx2_bb_elementary_traits/allocator.rs
1// Copyright (c) 2023 Contributors to the Eclipse Foundation
2//
3// See the NOTICE file(s) distributed with this work for additional
4// information regarding copyright ownership.
5//
6// This program and the accompanying materials are made available under the
7// terms of the Apache Software License 2.0 which is available at
8// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
9// which is available at https://opensource.org/licenses/MIT.
10//
11// SPDX-License-Identifier: Apache-2.0 OR MIT
12
13//! Contains the traits [`BaseAllocator`] which contains the most basic functionality an allocator
14//! requires and [`Allocator`] with more advanced allocation features.
15
16pub use core::{alloc::Layout, ptr::NonNull};
17
18/// Failures caused by [`BaseAllocator::allocate()`] or [`BaseAllocator::allocate_zeroed()`].
19#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
20pub enum AllocationError {
21 SizeIsZero,
22 SizeTooLarge,
23 AlignmentFailure,
24 OutOfMemory,
25 InternalError,
26}
27
28impl core::fmt::Display for AllocationError {
29 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
30 write!(f, "AllocationError::{self:?}")
31 }
32}
33
34impl core::error::Error for AllocationError {}
35
36/// Failures caused by [`Allocator::grow()`] or [`Allocator::grow_zeroed()`].
37#[derive(Debug, PartialEq, Eq, Copy, Clone)]
38pub enum AllocationGrowError {
39 GrowWouldShrink,
40 SizeIsZero,
41 OutOfMemory,
42 AlignmentFailure,
43 InternalError,
44}
45
46impl core::fmt::Display for AllocationGrowError {
47 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
48 write!(f, "AllocationGrowError::{self:?}")
49 }
50}
51
52impl core::error::Error for AllocationGrowError {}
53
54/// Failures caused by [`Allocator::shrink()`].
55#[derive(Debug, PartialEq, Eq, Copy, Clone)]
56pub enum AllocationShrinkError {
57 ShrinkWouldGrow,
58 SizeIsZero,
59 AlignmentFailure,
60 InternalError,
61}
62
63impl core::fmt::Display for AllocationShrinkError {
64 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
65 write!(f, "AllocationShrinkError::{self:?}")
66 }
67}
68
69impl core::error::Error for AllocationShrinkError {}
70
71/// The most minimalistic requirement for an allocator
72pub trait BaseAllocator {
73 /// Allocates a memory chunk with the properties provided in layout and either
74 /// returns a slice or an allocation error on failure.
75 fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocationError>;
76
77 /// Allocates a memory chunk with the properties provided in layout and zeroes the memory
78 /// On success it returns a slice or an allocation error on failure.
79 fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocationError> {
80 let memory = self.allocate(layout)?;
81 unsafe {
82 core::ptr::write_bytes(
83 memory.as_ref().as_ptr() as *mut u8,
84 0,
85 memory.as_ref().len(),
86 )
87 };
88 Ok(memory)
89 }
90
91 /// Releases an previously allocated chunk of memory.
92 ///
93 /// # Safety
94 ///
95 /// * `ptr` must be allocated previously with [`BaseAllocator::allocate()`] or
96 /// [`BaseAllocator::allocate_zeroed()`]
97 /// * `layout` must have the same value as in the allocation or, when the memory was
98 /// resized, the same value as it was resized to
99 ///
100 unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout);
101}
102
103/// Allocator with grow and shrink features.
104pub trait Allocator: BaseAllocator {
105 /// Increases the size of an previously allocated chunk of memory or allocates a new chunk
106 /// with the provided properties.
107 /// It returns a failure when the size decreases.
108 ///
109 /// # Safety
110 ///
111 /// * `ptr` must be allocated previously with [`BaseAllocator::allocate()`] or
112 /// [`BaseAllocator::allocate_zeroed()`]
113 /// * `old_layout` must have the same value as in the allocation or, when the memory was
114 /// resized, the same value as it was resized to
115 ///
116 unsafe fn grow(
117 &self,
118 ptr: NonNull<u8>,
119 old_layout: Layout,
120 new_layout: Layout,
121 ) -> Result<NonNull<[u8]>, AllocationGrowError>;
122
123 /// Increases the size of an previously allocated chunk of memory or allocates a new chunk
124 /// with the provided properties. If the chunk can be resized only the difference in size
125 /// will be zeroed.
126 /// It returns a failure when the size decreases.
127 ///
128 /// # Safety
129 ///
130 /// * `ptr` must be allocated previously with [`BaseAllocator::allocate()`] or
131 /// [`BaseAllocator::allocate_zeroed()`]
132 /// * `old_layout` must have the same value as in the allocation or, when the memory was
133 /// resized, the same value as it was resized to
134 ///
135 unsafe fn grow_zeroed(
136 &self,
137 ptr: NonNull<u8>,
138 old_layout: Layout,
139 new_layout: Layout,
140 ) -> Result<NonNull<[u8]>, AllocationGrowError> {
141 let memory = self.grow(ptr, old_layout, new_layout)?;
142 core::ptr::write_bytes(
143 memory.as_ref().as_ptr().add(old_layout.size()) as *mut u8,
144 0,
145 memory.as_ref().len() - old_layout.size(),
146 );
147 Ok(memory)
148 }
149
150 /// Decreases the size of an previously allocated chunk of memory. If the size increases it
151 /// fails.
152 ///
153 /// # Safety
154 ///
155 /// * `ptr` must be allocated previously with [`BaseAllocator::allocate()`] or
156 /// [`BaseAllocator::allocate_zeroed()`]
157 /// * `old_layout` must have the same value as in the allocation or, when the memory was
158 /// resized, the same value as it was resized to
159 ///
160 unsafe fn shrink(
161 &self,
162 ptr: NonNull<u8>,
163 old_layout: Layout,
164 new_layout: Layout,
165 ) -> Result<NonNull<[u8]>, AllocationShrinkError>;
166}