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