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