1use core::{alloc::Layout, ops::Range, ptr::NonNull};
2
3use crate::{
4 BaseAllocator, Bump, BumpScope, Checkpoint, WithoutDealloc, WithoutShrink,
5 alloc::{AllocError, Allocator},
6 layout::CustomLayout,
7 raw_bump::RawChunk,
8 settings::BumpAllocatorSettings,
9 stats::AnyStats,
10 traits::{assert_dyn_compatible, assert_implements},
11};
12
13pub trait Sealed {}
14
15impl<B: Sealed + ?Sized> Sealed for &B {}
16impl<B: Sealed + ?Sized> Sealed for &mut B {}
17impl<B: Sealed> Sealed for WithoutDealloc<B> {}
18impl<B: Sealed> Sealed for WithoutShrink<B> {}
19
20impl<A, S> Sealed for Bump<A, S>
21where
22 A: BaseAllocator<S::GuaranteedAllocated>,
23 S: BumpAllocatorSettings,
24{
25}
26
27impl<A, S> Sealed for BumpScope<'_, A, S>
28where
29 A: BaseAllocator<S::GuaranteedAllocated>,
30 S: BumpAllocatorSettings,
31{
32}
33
34pub unsafe trait BumpAllocatorCore: Allocator + Sealed {
65 #[must_use]
67 fn any_stats(&self) -> AnyStats<'_>;
68
69 #[must_use]
75 fn checkpoint(&self) -> Checkpoint;
76
77 unsafe fn reset_to(&self, checkpoint: Checkpoint);
109
110 #[must_use]
114 fn is_claimed(&self) -> bool;
115
116 fn prepare_allocation(&self, layout: Layout) -> Result<Range<NonNull<u8>>, AllocError>;
125
126 unsafe fn allocate_prepared(&self, layout: Layout, range: Range<NonNull<u8>>) -> NonNull<u8>;
139
140 fn prepare_allocation_rev(&self, layout: Layout) -> Result<Range<NonNull<u8>>, AllocError>;
149
150 unsafe fn allocate_prepared_rev(&self, layout: Layout, range: Range<NonNull<u8>>) -> NonNull<u8>;
163}
164
165assert_dyn_compatible!(BumpAllocatorCore);
166
167assert_implements! {
168 [BumpAllocatorCore + ?Sized]
169
170 Bump
171 &Bump
172 &mut Bump
173
174 BumpScope
175 &BumpScope
176 &mut BumpScope
177
178 dyn BumpAllocatorCore
179 &dyn BumpAllocatorCore
180 &mut dyn BumpAllocatorCore
181
182 dyn BumpAllocatorCoreScope
183 &dyn BumpAllocatorCoreScope
184 &mut dyn BumpAllocatorCoreScope
185
186 dyn MutBumpAllocatorCore
187 &dyn MutBumpAllocatorCore
188 &mut dyn MutBumpAllocatorCore
189
190 dyn MutBumpAllocatorCoreScope
191 &dyn MutBumpAllocatorCoreScope
192 &mut dyn MutBumpAllocatorCoreScope
193}
194
195macro_rules! impl_for_ref {
196 ($($ty:ty)*) => {
197 $(
198 unsafe impl<B: BumpAllocatorCore + ?Sized> BumpAllocatorCore for $ty {
199 #[inline(always)]
200 fn any_stats(&self) -> AnyStats<'_> {
201 B::any_stats(self)
202 }
203
204 #[inline(always)]
205 fn checkpoint(&self) -> Checkpoint {
206 B::checkpoint(self)
207 }
208
209 #[inline(always)]
210 unsafe fn reset_to(&self, checkpoint: Checkpoint) {
211 unsafe { B::reset_to(self, checkpoint) };
212 }
213
214 #[inline(always)]
215 fn is_claimed(&self) -> bool {
216 B::is_claimed(self)
217 }
218
219 #[inline(always)]
220 fn prepare_allocation(&self, layout: Layout) -> Result<Range<NonNull<u8>>, AllocError> {
221 B::prepare_allocation(self, layout)
222 }
223
224 #[inline(always)]
225 unsafe fn allocate_prepared(&self, layout: Layout, range: Range<NonNull<u8>>) -> NonNull<u8> {
226 unsafe { B::allocate_prepared(self, layout, range) }
227 }
228
229 #[inline(always)]
230 fn prepare_allocation_rev(&self, layout: Layout) -> Result<Range<NonNull<u8>>, AllocError> {
231 B::prepare_allocation_rev(self, layout)
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 )*
240 };
241}
242
243impl_for_ref! {
244 &B
245 &mut B
246}
247
248unsafe impl<B: BumpAllocatorCore> BumpAllocatorCore for WithoutDealloc<B> {
249 #[inline(always)]
250 fn any_stats(&self) -> AnyStats<'_> {
251 B::any_stats(&self.0)
252 }
253
254 #[inline(always)]
255 fn checkpoint(&self) -> Checkpoint {
256 B::checkpoint(&self.0)
257 }
258
259 #[inline(always)]
260 unsafe fn reset_to(&self, checkpoint: Checkpoint) {
261 unsafe { B::reset_to(&self.0, checkpoint) };
262 }
263
264 #[inline(always)]
265 fn is_claimed(&self) -> bool {
266 B::is_claimed(&self.0)
267 }
268
269 #[inline(always)]
270 fn prepare_allocation(&self, layout: Layout) -> Result<Range<NonNull<u8>>, AllocError> {
271 B::prepare_allocation(&self.0, layout)
272 }
273
274 #[inline(always)]
275 unsafe fn allocate_prepared(&self, layout: Layout, range: Range<NonNull<u8>>) -> NonNull<u8> {
276 unsafe { B::allocate_prepared(&self.0, layout, range) }
277 }
278
279 #[inline(always)]
280 fn prepare_allocation_rev(&self, layout: Layout) -> Result<Range<NonNull<u8>>, AllocError> {
281 B::prepare_allocation_rev(&self.0, layout)
282 }
283
284 #[inline(always)]
285 unsafe fn allocate_prepared_rev(&self, layout: Layout, range: Range<NonNull<u8>>) -> NonNull<u8> {
286 unsafe { B::allocate_prepared_rev(&self.0, layout, range) }
287 }
288}
289
290unsafe impl<B: BumpAllocatorCore> BumpAllocatorCore for WithoutShrink<B> {
291 #[inline(always)]
292 fn any_stats(&self) -> AnyStats<'_> {
293 B::any_stats(&self.0)
294 }
295
296 #[inline(always)]
297 fn checkpoint(&self) -> Checkpoint {
298 B::checkpoint(&self.0)
299 }
300
301 #[inline(always)]
302 unsafe fn reset_to(&self, checkpoint: Checkpoint) {
303 unsafe { B::reset_to(&self.0, checkpoint) };
304 }
305
306 #[inline(always)]
307 fn is_claimed(&self) -> bool {
308 B::is_claimed(&self.0)
309 }
310
311 #[inline(always)]
312 fn prepare_allocation(&self, layout: Layout) -> Result<Range<NonNull<u8>>, AllocError> {
313 B::prepare_allocation(&self.0, layout)
314 }
315
316 #[inline(always)]
317 unsafe fn allocate_prepared(&self, layout: Layout, range: Range<NonNull<u8>>) -> NonNull<u8> {
318 unsafe { B::allocate_prepared(&self.0, layout, range) }
319 }
320
321 #[inline(always)]
322 fn prepare_allocation_rev(&self, layout: Layout) -> Result<Range<NonNull<u8>>, AllocError> {
323 B::prepare_allocation_rev(&self.0, layout)
324 }
325
326 #[inline(always)]
327 unsafe fn allocate_prepared_rev(&self, layout: Layout, range: Range<NonNull<u8>>) -> NonNull<u8> {
328 unsafe { B::allocate_prepared_rev(&self.0, layout, range) }
329 }
330}
331
332unsafe impl<A, S> BumpAllocatorCore for Bump<A, S>
333where
334 A: BaseAllocator<S::GuaranteedAllocated>,
335 S: BumpAllocatorSettings,
336{
337 #[inline(always)]
338 fn any_stats(&self) -> AnyStats<'_> {
339 self.as_scope().any_stats()
340 }
341
342 #[inline(always)]
343 fn checkpoint(&self) -> Checkpoint {
344 self.as_scope().checkpoint()
345 }
346
347 #[inline(always)]
348 unsafe fn reset_to(&self, checkpoint: Checkpoint) {
349 unsafe { self.as_scope().reset_to(checkpoint) };
350 }
351
352 #[inline(always)]
353 fn is_claimed(&self) -> bool {
354 self.as_scope().is_claimed()
355 }
356
357 #[inline(always)]
358 fn prepare_allocation(&self, layout: Layout) -> Result<Range<NonNull<u8>>, AllocError> {
359 self.as_scope().prepare_allocation(layout)
360 }
361
362 #[inline(always)]
363 unsafe fn allocate_prepared(&self, layout: Layout, range: Range<NonNull<u8>>) -> NonNull<u8> {
364 unsafe { self.as_scope().allocate_prepared(layout, range) }
365 }
366
367 #[inline(always)]
368 fn prepare_allocation_rev(&self, layout: Layout) -> Result<Range<NonNull<u8>>, AllocError> {
369 self.as_scope().prepare_allocation_rev(layout)
370 }
371
372 #[inline(always)]
373 unsafe fn allocate_prepared_rev(&self, layout: Layout, range: Range<NonNull<u8>>) -> NonNull<u8> {
374 unsafe { self.as_scope().allocate_prepared_rev(layout, range) }
375 }
376}
377
378unsafe impl<A, S> BumpAllocatorCore for BumpScope<'_, A, S>
379where
380 A: BaseAllocator<S::GuaranteedAllocated>,
381 S: BumpAllocatorSettings,
382{
383 #[inline(always)]
384 fn any_stats(&self) -> AnyStats<'_> {
385 self.stats().into()
386 }
387
388 #[inline(always)]
389 fn checkpoint(&self) -> Checkpoint {
390 self.raw.checkpoint()
391 }
392
393 #[inline]
394 unsafe fn reset_to(&self, checkpoint: Checkpoint) {
395 unsafe { self.raw.reset_to(checkpoint) }
396 }
397
398 #[inline(always)]
399 fn is_claimed(&self) -> bool {
400 self.raw.is_claimed()
401 }
402
403 #[inline(always)]
404 fn prepare_allocation(&self, layout: Layout) -> Result<Range<NonNull<u8>>, AllocError> {
405 #[cold]
406 #[inline(never)]
407 unsafe fn prepare_allocation_in_another_chunk<A, S>(
408 this: &BumpScope<'_, A, S>,
409 layout: Layout,
410 ) -> Result<Range<NonNull<u8>>, AllocError>
411 where
412 A: BaseAllocator<S::GuaranteedAllocated>,
413 S: BumpAllocatorSettings,
414 {
415 unsafe {
416 this.raw
417 .in_another_chunk(CustomLayout(layout), RawChunk::prepare_allocation_range)
418 }
419 }
420
421 match self.raw.chunk.get().prepare_allocation_range(CustomLayout(layout)) {
422 Some(ptr) => Ok(ptr),
423 None => unsafe { prepare_allocation_in_another_chunk(self, layout) },
424 }
425 }
426
427 #[inline(always)]
428 unsafe fn allocate_prepared(&self, layout: Layout, range: Range<NonNull<u8>>) -> NonNull<u8> {
429 debug_assert_eq!(range.start.addr().get() % layout.align(), 0);
430 debug_assert_eq!(range.end.addr().get() % layout.align(), 0);
431 debug_assert_eq!(layout.size() % layout.align(), 0);
432
433 unsafe {
434 let chunk = self.raw.chunk.get().as_non_dummy_unchecked();
436
437 if S::UP {
438 let end = range.start.add(layout.size());
439 chunk.set_pos_addr_and_align(end.addr().get());
440 range.start
441 } else {
442 let src = range.start;
443 let dst_end = range.end;
444 let dst = dst_end.sub(layout.size());
445 src.copy_to(dst, layout.size());
446 chunk.set_pos_addr_and_align(dst.addr().get());
447 dst
448 }
449 }
450 }
451
452 #[inline(always)]
453 fn prepare_allocation_rev(&self, layout: Layout) -> Result<Range<NonNull<u8>>, AllocError> {
454 self.prepare_allocation(layout)
456 }
457
458 #[inline(always)]
459 unsafe fn allocate_prepared_rev(&self, layout: Layout, range: Range<NonNull<u8>>) -> NonNull<u8> {
460 debug_assert_eq!(range.start.addr().get() % layout.align(), 0);
461 debug_assert_eq!(range.end.addr().get() % layout.align(), 0);
462 debug_assert_eq!(layout.size() % layout.align(), 0);
463
464 unsafe {
465 let chunk = self.raw.chunk.get().as_non_dummy_unchecked();
467
468 if S::UP {
469 let dst = range.start;
470 let dst_end = dst.add(layout.size());
471
472 let src_end = range.end;
473 let src = src_end.sub(layout.size());
474
475 src.copy_to(dst, layout.size());
476
477 chunk.set_pos_addr_and_align(dst_end.addr().get());
478
479 dst
480 } else {
481 let dst_end = range.end;
482 let dst = dst_end.sub(layout.size());
483 chunk.set_pos_addr_and_align(dst.addr().get());
484 dst
485 }
486 }
487 }
488}