1use super::{
4 AllocError,
5 granularity::{Granularity, ResourceClass},
6 host::HostMemory,
7 linear::Linear,
8 tlsf::Tlsf,
9 virtual_block::{PlacementStrategy, VirtualAllocationInfo, VirtualBlockStats},
10};
11
12#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
20pub enum AllocationAlgorithm {
21 #[default]
22 Tlsf,
23 Linear,
24}
25
26#[derive(Clone, Copy)]
27pub(super) enum Placement {
28 Tlsf(usize, u64),
29 Linear { offset: u64, serial: u64 },
30}
31
32#[expect(
35 clippy::large_enum_variant,
36 reason = "inline metadata preserves fallible block acquisition"
37)]
38pub(super) enum Metadata<'callbacks> {
39 Tlsf(Tlsf<'callbacks>),
40 Linear(Linear<'callbacks>),
41}
42
43impl<'callbacks> Metadata<'callbacks> {
44 pub fn free_bytes(&self) -> u64 {
46 match self {
47 Self::Tlsf(metadata) => metadata.free_bytes(),
48 Self::Linear(metadata) => metadata.free_bytes(),
49 }
50 }
51
52 pub fn is_empty(&self) -> bool {
53 match self {
54 Self::Tlsf(metadata) => metadata.is_empty(),
55 Self::Linear(metadata) => metadata.is_empty(),
56 }
57 }
58
59 pub fn new_native(
60 size: u64,
61 algorithm: AllocationAlgorithm,
62 allow_ring: bool,
63 granularity: Granularity,
64 host: HostMemory<'callbacks>,
65 ) -> Result<Self, AllocError> {
66 let mut metadata = Self::new_with_host(size, algorithm, allow_ring, host)?;
67 match &mut metadata {
68 Self::Tlsf(metadata) => metadata.granularity = granularity,
69 Self::Linear(metadata) => metadata.granularity = granularity,
70 }
71 Ok(metadata)
72 }
73
74 pub fn new(
75 size: u64,
76 algorithm: AllocationAlgorithm,
77 allow_ring: bool,
78 ) -> Result<Self, AllocError> {
79 match algorithm {
80 AllocationAlgorithm::Tlsf => Tlsf::new(size).map(Self::Tlsf),
81 AllocationAlgorithm::Linear => Linear::new(size, allow_ring).map(Self::Linear),
82 }
83 }
84
85 pub fn host_memory(&self) -> HostMemory<'callbacks> {
86 match self {
87 Self::Tlsf(metadata) => metadata.host_memory(),
88 Self::Linear(metadata) => metadata.host_memory(),
89 }
90 }
91
92 pub fn new_with_host(
93 size: u64,
94 algorithm: AllocationAlgorithm,
95 allow_ring: bool,
96 host: HostMemory<'callbacks>,
97 ) -> Result<Self, AllocError> {
98 match algorithm {
99 AllocationAlgorithm::Tlsf => Tlsf::new_with_host(size, host).map(Self::Tlsf),
100 AllocationAlgorithm::Linear => {
101 Linear::new_with_host(size, allow_ring, host).map(Self::Linear)
102 }
103 }
104 }
105
106 pub fn allocate(
107 &mut self,
108 size: u64,
109 alignment: u64,
110 strategy: PlacementStrategy,
111 upper: bool,
112 ) -> Result<Placement, AllocError> {
113 match self {
114 Self::Tlsf(metadata) => {
115 if upper {
116 return Err(AllocError::UnsupportedCapability(
117 "upper address requires linear placement",
118 ));
119 }
120 metadata
121 .allocate(size, alignment, strategy)
122 .map(|(index, serial)| Placement::Tlsf(index, serial))
123 }
124 Self::Linear(metadata) => metadata.allocate(size, alignment, upper),
125 }
126 }
127
128 pub fn allocate_resource(
129 &mut self,
130 size: u64,
131 alignment: u64,
132 strategy: PlacementStrategy,
133 upper: bool,
134 class: ResourceClass,
135 ) -> Result<Placement, AllocError> {
136 match self {
137 Self::Tlsf(metadata) => {
138 if upper {
139 return Err(AllocError::UnsupportedCapability(
140 "upper address requires linear placement",
141 ));
142 }
143 metadata
144 .allocate_resource(size, alignment, strategy, class)
145 .map(|(index, serial)| Placement::Tlsf(index, serial))
146 }
147 Self::Linear(metadata) => metadata.allocate_resource(size, alignment, upper, class),
148 }
149 }
150
151 pub fn info(&self, placement: Placement) -> Result<VirtualAllocationInfo, AllocError> {
152 match (self, placement) {
153 (Self::Tlsf(metadata), Placement::Tlsf(index, serial)) => metadata.info(index, serial),
154 (Self::Linear(metadata), Placement::Linear { offset, serial }) => {
155 metadata.info(offset, serial)
156 }
157 _ => Err(AllocError::UnknownAllocation),
158 }
159 }
160
161 pub fn free(&mut self, placement: Placement) -> Result<(), AllocError> {
162 match (self, placement) {
163 (Self::Tlsf(metadata), Placement::Tlsf(index, serial)) => metadata.free(index, serial),
164 (Self::Linear(metadata), Placement::Linear { offset, serial }) => {
165 metadata.free(offset, serial)
166 }
167 _ => Err(AllocError::UnknownAllocation),
168 }
169 }
170
171 pub fn clear(&mut self) {
172 match self {
173 Self::Tlsf(metadata) => metadata.clear(),
174 Self::Linear(metadata) => metadata.clear(),
175 }
176 }
177
178 pub fn set_user_data(&mut self, placement: Placement, data: usize) -> Result<(), AllocError> {
179 match (self, placement) {
180 (Self::Tlsf(metadata), Placement::Tlsf(index, serial)) => {
181 metadata.set_user_data(index, serial, data)
182 }
183 (Self::Linear(metadata), Placement::Linear { offset, serial }) => {
184 metadata.set_user_data(offset, serial, data)
185 }
186 _ => Err(AllocError::UnknownAllocation),
187 }
188 }
189
190 pub fn for_each_allocation(&self, visit: impl FnMut(u64, u64, usize)) {
191 match self {
192 Self::Tlsf(metadata) => metadata.for_each_allocation(visit),
193 Self::Linear(metadata) => metadata.for_each_allocation(visit),
194 }
195 }
196
197 pub fn for_each_free(&self, visit: impl FnMut(u64, u64)) {
198 match self {
199 Self::Tlsf(metadata) => metadata.for_each_free(visit),
200 Self::Linear(metadata) => metadata.for_each_free(visit),
201 }
202 }
203
204 pub fn statistics(&self) -> VirtualBlockStats {
205 match self {
206 Self::Tlsf(metadata) => metadata.statistics(),
207 Self::Linear(metadata) => metadata.statistics(),
208 }
209 }
210}
211
212#[cfg(test)]
213#[path = "../../../test/rs/mem/test_granularity.rs"]
214mod tests;