1use core::{alloc::Layout, ops::Range, ptr::NonNull};
2
3use crate::{
4 BaseAllocator, Bump, BumpScope, Checkpoint, MinimumAlignment, SupportedMinimumAlignment, WithoutDealloc, WithoutShrink,
5 alloc::{AllocError, Allocator},
6 layout::CustomLayout,
7 stats::AnyStats,
8 traits::{assert_dyn_compatible, assert_implements},
9};
10
11pub trait Sealed {}
12
13impl<B: Sealed + ?Sized> Sealed for &B {}
14impl<B: Sealed + ?Sized> Sealed for &mut B {}
15impl<B: Sealed> Sealed for WithoutDealloc<B> {}
16impl<B: Sealed> Sealed for WithoutShrink<B> {}
17
18impl<A, const MIN_ALIGN: usize, const UP: bool, const GUARANTEED_ALLOCATED: bool, const DEALLOCATES: bool> Sealed
19 for Bump<A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES>
20where
21 MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
22 A: BaseAllocator<GUARANTEED_ALLOCATED>,
23{
24}
25
26impl<A, const MIN_ALIGN: usize, const UP: bool, const GUARANTEED_ALLOCATED: bool, const DEALLOCATES: bool> Sealed
27 for BumpScope<'_, A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES>
28where
29 MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
30 A: BaseAllocator<GUARANTEED_ALLOCATED>,
31{
32}
33
34pub unsafe trait BumpAllocator: Allocator + Sealed {
64 fn any_stats(&self) -> AnyStats<'_>;
66
67 fn checkpoint(&self) -> Checkpoint;
73
74 unsafe fn reset_to(&self, checkpoint: Checkpoint);
109
110 fn prepare_allocation(&self, layout: Layout) -> Result<Range<NonNull<u8>>, AllocError>;
119
120 unsafe fn allocate_prepared(&self, layout: Layout, range: Range<NonNull<u8>>) -> NonNull<u8>;
131
132 unsafe fn allocate_prepared_rev(&self, layout: Layout, range: Range<NonNull<u8>>) -> NonNull<u8>;
144}
145
146assert_dyn_compatible!(BumpAllocator);
147
148assert_implements! {
149 [BumpAllocator + ?Sized]
150
151 Bump
152 &Bump
153 &mut Bump
154
155 BumpScope
156 &BumpScope
157 &mut BumpScope
158
159 dyn BumpAllocator
160 &dyn BumpAllocator
161 &mut dyn BumpAllocator
162
163 dyn BumpAllocatorScope
164 &dyn BumpAllocatorScope
165 &mut dyn BumpAllocatorScope
166
167 dyn MutBumpAllocator
168 &dyn MutBumpAllocator
169 &mut dyn MutBumpAllocator
170
171 dyn MutBumpAllocatorScope
172 &dyn MutBumpAllocatorScope
173 &mut dyn MutBumpAllocatorScope
174}
175
176unsafe impl<B: BumpAllocator + ?Sized> BumpAllocator for &B {
177 #[inline(always)]
178 fn any_stats(&self) -> AnyStats<'_> {
179 B::any_stats(self)
180 }
181
182 #[inline(always)]
183 fn checkpoint(&self) -> Checkpoint {
184 B::checkpoint(self)
185 }
186
187 #[inline(always)]
188 unsafe fn reset_to(&self, checkpoint: Checkpoint) {
189 unsafe { B::reset_to(self, checkpoint) };
190 }
191
192 #[inline(always)]
193 fn prepare_allocation(&self, layout: Layout) -> Result<Range<NonNull<u8>>, AllocError> {
194 B::prepare_allocation(self, layout)
195 }
196
197 #[inline(always)]
198 unsafe fn allocate_prepared(&self, layout: Layout, range: Range<NonNull<u8>>) -> NonNull<u8> {
199 unsafe { B::allocate_prepared(self, layout, range) }
200 }
201
202 #[inline(always)]
203 unsafe fn allocate_prepared_rev(&self, layout: Layout, range: Range<NonNull<u8>>) -> NonNull<u8> {
204 unsafe { B::allocate_prepared_rev(self, layout, range) }
205 }
206}
207
208unsafe impl<B: BumpAllocator + ?Sized> BumpAllocator for &mut B {
209 #[inline(always)]
210 fn any_stats(&self) -> AnyStats<'_> {
211 B::any_stats(self)
212 }
213
214 #[inline(always)]
215 fn checkpoint(&self) -> Checkpoint {
216 B::checkpoint(self)
217 }
218
219 #[inline(always)]
220 unsafe fn reset_to(&self, checkpoint: Checkpoint) {
221 unsafe { B::reset_to(self, checkpoint) };
222 }
223
224 #[inline(always)]
225 fn prepare_allocation(&self, layout: Layout) -> Result<Range<NonNull<u8>>, AllocError> {
226 B::prepare_allocation(self, layout)
227 }
228
229 #[inline(always)]
230 unsafe fn allocate_prepared(&self, layout: Layout, range: Range<NonNull<u8>>) -> NonNull<u8> {
231 unsafe { B::allocate_prepared(self, layout, range) }
232 }
233
234 #[inline(always)]
235 unsafe fn allocate_prepared_rev(&self, layout: Layout, range: Range<NonNull<u8>>) -> NonNull<u8> {
236 unsafe { B::allocate_prepared_rev(self, layout, range) }
237 }
238}
239
240unsafe impl<B: BumpAllocator> BumpAllocator for WithoutDealloc<B> {
241 #[inline(always)]
242 fn any_stats(&self) -> AnyStats<'_> {
243 B::any_stats(&self.0)
244 }
245
246 #[inline(always)]
247 fn checkpoint(&self) -> Checkpoint {
248 B::checkpoint(&self.0)
249 }
250
251 #[inline(always)]
252 unsafe fn reset_to(&self, checkpoint: Checkpoint) {
253 unsafe { B::reset_to(&self.0, checkpoint) };
254 }
255
256 #[inline(always)]
257 fn prepare_allocation(&self, layout: Layout) -> Result<Range<NonNull<u8>>, AllocError> {
258 B::prepare_allocation(&self.0, layout)
259 }
260
261 #[inline(always)]
262 unsafe fn allocate_prepared(&self, layout: Layout, range: Range<NonNull<u8>>) -> NonNull<u8> {
263 unsafe { B::allocate_prepared(&self.0, layout, range) }
264 }
265
266 #[inline(always)]
267 unsafe fn allocate_prepared_rev(&self, layout: Layout, range: Range<NonNull<u8>>) -> NonNull<u8> {
268 unsafe { B::allocate_prepared_rev(&self.0, layout, range) }
269 }
270}
271
272unsafe impl<B: BumpAllocator> BumpAllocator for WithoutShrink<B> {
273 #[inline(always)]
274 fn any_stats(&self) -> AnyStats<'_> {
275 B::any_stats(&self.0)
276 }
277
278 #[inline(always)]
279 fn checkpoint(&self) -> Checkpoint {
280 B::checkpoint(&self.0)
281 }
282
283 #[inline(always)]
284 unsafe fn reset_to(&self, checkpoint: Checkpoint) {
285 unsafe { B::reset_to(&self.0, checkpoint) };
286 }
287
288 #[inline(always)]
289 fn prepare_allocation(&self, layout: Layout) -> Result<Range<NonNull<u8>>, AllocError> {
290 B::prepare_allocation(&self.0, layout)
291 }
292
293 #[inline(always)]
294 unsafe fn allocate_prepared(&self, layout: Layout, range: Range<NonNull<u8>>) -> NonNull<u8> {
295 unsafe { B::allocate_prepared(&self.0, layout, range) }
296 }
297
298 #[inline(always)]
299 unsafe fn allocate_prepared_rev(&self, layout: Layout, range: Range<NonNull<u8>>) -> NonNull<u8> {
300 unsafe { B::allocate_prepared_rev(&self.0, layout, range) }
301 }
302}
303
304unsafe impl<A, const MIN_ALIGN: usize, const UP: bool, const GUARANTEED_ALLOCATED: bool, const DEALLOCATES: bool>
305 BumpAllocator for Bump<A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES>
306where
307 MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
308 A: BaseAllocator<GUARANTEED_ALLOCATED>,
309{
310 #[inline(always)]
311 fn any_stats(&self) -> AnyStats<'_> {
312 self.as_scope().any_stats()
313 }
314
315 #[inline(always)]
316 fn checkpoint(&self) -> Checkpoint {
317 self.as_scope().checkpoint()
318 }
319
320 #[inline(always)]
321 unsafe fn reset_to(&self, checkpoint: Checkpoint) {
322 unsafe { self.as_scope().reset_to(checkpoint) };
323 }
324
325 #[inline(always)]
326 fn prepare_allocation(&self, layout: Layout) -> Result<Range<NonNull<u8>>, AllocError> {
327 self.as_scope().prepare_allocation(layout)
328 }
329
330 #[inline(always)]
331 unsafe fn allocate_prepared(&self, layout: Layout, range: Range<NonNull<u8>>) -> NonNull<u8> {
332 unsafe { self.as_scope().allocate_prepared(layout, range) }
333 }
334
335 #[inline(always)]
336 unsafe fn allocate_prepared_rev(&self, layout: Layout, range: Range<NonNull<u8>>) -> NonNull<u8> {
337 unsafe { self.as_scope().allocate_prepared_rev(layout, range) }
338 }
339}
340
341unsafe impl<A, const MIN_ALIGN: usize, const UP: bool, const GUARANTEED_ALLOCATED: bool, const DEALLOCATES: bool>
342 BumpAllocator for BumpScope<'_, A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES>
343where
344 MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
345 A: BaseAllocator<GUARANTEED_ALLOCATED>,
346{
347 #[inline(always)]
348 fn any_stats(&self) -> AnyStats<'_> {
349 self.stats().into()
350 }
351
352 #[inline]
353 fn checkpoint(&self) -> Checkpoint {
354 Self::checkpoint(self)
355 }
356
357 #[inline]
358 unsafe fn reset_to(&self, checkpoint: Checkpoint) {
359 unsafe { Self::reset_to(self, checkpoint) }
360 }
361
362 #[inline(always)]
363 fn prepare_allocation(&self, layout: Layout) -> Result<Range<NonNull<u8>>, AllocError> {
364 #[cold]
365 #[inline(never)]
366 unsafe fn prepare_allocation_in_another_chunk<
367 A,
368 const MIN_ALIGN: usize,
369 const UP: bool,
370 const GUARANTEED_ALLOCATED: bool,
371 const DEALLOCATES: bool,
372 >(
373 this: &BumpScope<'_, A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES>,
374 layout: Layout,
375 ) -> Result<Range<NonNull<u8>>, AllocError>
376 where
377 MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
378 A: BaseAllocator<GUARANTEED_ALLOCATED>,
379 {
380 unsafe {
381 this.in_another_chunk(CustomLayout(layout), |chunk, layout| {
382 chunk.prepare_allocation_range(MinimumAlignment::<MIN_ALIGN>, layout)
383 })
384 }
385 }
386
387 match self
388 .chunk
389 .get()
390 .prepare_allocation_range(MinimumAlignment::<MIN_ALIGN>, CustomLayout(layout))
391 {
392 Some(ptr) => Ok(ptr),
393 None => unsafe { prepare_allocation_in_another_chunk(self, layout) },
394 }
395 }
396
397 #[inline(always)]
398 unsafe fn allocate_prepared(&self, layout: Layout, range: Range<NonNull<u8>>) -> NonNull<u8> {
399 debug_assert_eq!(range.start.addr().get() % layout.align(), 0);
400 debug_assert_eq!(range.end.addr().get() % layout.align(), 0);
401 debug_assert_eq!(layout.size() % layout.align(), 0);
402
403 unsafe {
404 if UP {
405 let end = range.start.add(layout.size());
406 self.set_pos(end.addr());
407 range.start
408 } else {
409 let src = range.start;
410 let dst_end = range.end;
411 let dst = dst_end.sub(layout.size());
412 src.copy_to(dst, layout.size());
413 self.set_pos(dst.addr());
414 dst
415 }
416 }
417 }
418
419 #[inline(always)]
420 unsafe fn allocate_prepared_rev(&self, layout: Layout, range: Range<NonNull<u8>>) -> NonNull<u8> {
421 debug_assert_eq!(range.start.addr().get() % layout.align(), 0);
422 debug_assert_eq!(range.end.addr().get() % layout.align(), 0);
423 debug_assert_eq!(layout.size() % layout.align(), 0);
424
425 unsafe {
426 if UP {
427 let dst = range.start;
428 let dst_end = dst.add(layout.size());
429
430 let src_end = range.end;
431 let src = src_end.sub(layout.size());
432
433 src.copy_to(dst, layout.size());
434
435 self.set_pos(dst_end.addr());
436
437 dst
438 } else {
439 let dst_end = range.end;
440 let dst = dst_end.sub(layout.size());
441 self.set_pos(dst.addr());
442 dst
443 }
444 }
445 }
446}