bump_scope/bump.rs
1use core::{
2 alloc::Layout,
3 ffi::CStr,
4 fmt::{self, Debug},
5 mem::{ManuallyDrop, MaybeUninit},
6 panic::{RefUnwindSafe, UnwindSafe},
7 ptr::NonNull,
8};
9
10#[cfg(feature = "nightly-clone-to-uninit")]
11use core::clone::CloneToUninit;
12
13use crate::{
14 BaseAllocator, BumpBox, BumpClaimGuard, BumpScope, BumpScopeGuard, Checkpoint, ErrorBehavior,
15 alloc::{AllocError, Allocator},
16 allocator_impl,
17 chunk::ChunkSize,
18 maybe_default_allocator,
19 owned_slice::OwnedSlice,
20 polyfill::{transmute_mut, transmute_ref, transmute_value},
21 raw_bump::RawBump,
22 settings::{BumpAllocatorSettings, BumpSettings, False, MinimumAlignment, SupportedMinimumAlignment},
23 stats::{AnyStats, Stats},
24 traits::{
25 self, BumpAllocator, BumpAllocatorCore, BumpAllocatorScope, BumpAllocatorTyped, BumpAllocatorTypedScope,
26 MutBumpAllocatorTypedScope,
27 },
28};
29
30#[cfg(feature = "panic-on-alloc")]
31use crate::panic_on_error;
32
33macro_rules! make_type {
34 ($($allocator_parameter:tt)*) => {
35 /// The bump allocator.
36 ///
37 /// # Generic parameters
38 /// - **`A`** — the base allocator, defaults to `Global` when the `alloc` feature is enabled
39 /// - **`S`** — the bump allocator settings, see [`settings`](crate::settings)
40 ///
41 /// # Overview
42 /// All of the mentioned methods that do allocations panic if the base allocator returned an error.
43 /// For every such panicking method, there is a corresponding `try_`-prefixed version that returns a `Result` instead.
44 ///
45 /// #### Create a `Bump` ...
46 /// - with a default size hint: <code>[new]\([_in][new_in])</code> / <code>[default]</code>
47 /// - provide a size hint: <code>[with_size]\([_in][with_size_in])</code>
48 /// - provide a minimum capacity: <code>[with_capacity]\([_in][with_capacity_in])</code>
49 /// - const, without allocating a chunk: <code>[unallocated]</code>
50 ///
51 /// [new]: Bump::new
52 /// [new_in]: Bump::new_in
53 /// [default]: Bump::default
54 /// [with_size]: Bump::with_size
55 /// [with_size_in]: Bump::with_size_in
56 /// [with_capacity]: Bump::with_capacity
57 /// [with_capacity_in]: Bump::with_capacity_in
58 /// [unallocated]: Bump::unallocated
59 ///
60 /// #### Allocate ...
61 /// - sized values: [`alloc`], [`alloc_with`], [`alloc_default`], [`alloc_zeroed`]
62 /// - strings: [`alloc_str`], <code>[alloc_fmt](BumpAllocatorTypedScope::alloc_fmt)([_mut](MutBumpAllocatorTypedScope::alloc_fmt_mut))</code>
63 /// - c strings: [`alloc_cstr`], [`alloc_cstr_from_str`], <code>[alloc_cstr_fmt](BumpAllocatorTypedScope::alloc_cstr_fmt)([_mut](MutBumpAllocatorTypedScope::alloc_cstr_fmt_mut))</code>
64 /// - slices: <code>alloc_slice_{[copy](BumpAllocatorTypedScope::alloc_slice_copy), [clone](BumpAllocatorTypedScope::alloc_slice_clone), [move](BumpAllocatorTypedScope::alloc_slice_move), [fill](BumpAllocatorTypedScope::alloc_slice_fill), [fill_with](BumpAllocatorTypedScope::alloc_slice_fill_with)}</code>,
65 /// [`alloc_zeroed_slice`]
66 /// - slices from an iterator: [`alloc_iter`], [`alloc_iter_exact`], [`alloc_iter_mut`], [`alloc_iter_mut_rev`]
67 /// - uninitialized values: [`alloc_uninit`], [`alloc_uninit_slice`], [`alloc_uninit_slice_for`]
68 ///
69 /// which can then be conveniently initialized by the [`init*` methods of `BumpBox`](crate::BumpBox#bumpbox-has-a-lot-of-methods).
70 /// - results: [`alloc_try_with`], [`alloc_try_with_mut`]
71 /// - via clone *(nightly only)*: [`alloc_clone`]
72 ///
73 /// #### Free memory using ...
74 /// - scopes: [`scoped`], [`scoped_aligned`], [`scope_guard`]
75 /// - checkpoints: [`checkpoint`], [`reset_to`]
76 /// - reset: [`reset`], [`reset_to_start`]
77 /// - dealloc: [`dealloc`]
78 ///
79 /// #### Configure allocator settings ...
80 /// - [`with_settings`], [`borrow_with_settings`], [`borrow_mut_with_settings`]
81 ///
82 /// ## Collections
83 /// A `Bump` (and [`BumpScope`]) can be used to allocate collections of this crate...
84 /// ```
85 /// use bump_scope::{Bump, BumpString};
86 /// let bump: Bump = Bump::new();
87 ///
88 /// let mut string = BumpString::new_in(&bump);
89 /// string.push_str("Hello,");
90 /// string.push_str(" world!");
91 /// ```
92 ///
93 /// ... and collections from crates that use `allocator_api2`'s `Allocator` like [hashbrown](https://docs.rs/hashbrown)'s [`HashMap`](https://docs.rs/hashbrown/latest/hashbrown/struct.HashMap.html):
94 ///
95 /// *This requires the `allocator-api2-02` feature OR the `nightly-allocator-api` feature along with hashbrown's `nightly` feature.*
96 // NOTE: This code is tested in `crates/test-hashbrown/lib.rs`.
97 // It's not tested here because using hashbrown requires us to either have both the crate features for a nightly allocator api in bump-scope and hashbrown or neither.
98 // This could be solved by making bump-scope's "nightly-allocator-api" depend on "hashbrown/nightly" but that currently breaks tools like cargo-hack and cargo-minimal-versions.
99 /// ```
100 /// # /*
101 /// use bump_scope::Bump;
102 /// use hashbrown::HashMap;
103 ///
104 /// let bump: Bump = Bump::new();
105 /// let mut map = HashMap::new_in(&bump);
106 /// map.insert("tau", 6.283);
107 /// # */
108 /// # ()
109 /// ```
110 ///
111 /// On nightly and with the feature `nightly-allocator-api` you can also allocate collections from `std` that have an allocator parameter:
112 #[cfg_attr(feature = "nightly-allocator-api", doc = "```")]
113 #[cfg_attr(not(feature = "nightly-allocator-api"), doc = "```no_run")]
114 /// # /*
115 /// # those features are already been enabled by a `doc(test(attr`
116 /// # but we still want it here for demonstration
117 /// #![feature(allocator_api, btreemap_alloc)]
118 /// # */
119 /// # #[cfg(feature = "nightly-allocator-api")] fn main() {
120 /// use bump_scope::Bump;
121 /// use std::collections::{VecDeque, BTreeMap, LinkedList};
122 ///
123 /// let bump: Bump = Bump::new();
124 /// let vec = Vec::new_in(&bump);
125 /// let queue = VecDeque::new_in(&bump);
126 /// let map = BTreeMap::new_in(&bump);
127 /// let list = LinkedList::new_in(&bump);
128 /// # let _: Vec<i32, _> = vec;
129 /// # let _: VecDeque<i32, _> = queue;
130 /// # let _: BTreeMap<i32, i32, _> = map;
131 /// # let _: LinkedList<i32, _> = list;
132 /// # }
133 /// # #[cfg(not(feature = "nightly-allocator-api"))] fn main() {}
134 /// ```
135 ///
136 /// [`alloc`]: BumpAllocatorTypedScope::alloc
137 /// [`alloc_with`]: BumpAllocatorTypedScope::alloc_with
138 /// [`alloc_default`]: BumpAllocatorTypedScope::alloc_default
139 /// [`alloc_zeroed`]: crate::zerocopy_08::BumpAllocatorTypedScopeExt::alloc_zeroed
140 ///
141 /// [`alloc_str`]: BumpAllocatorTypedScope::alloc_str
142 ///
143 /// [`alloc_cstr`]: BumpAllocatorTypedScope::alloc_cstr
144 /// [`alloc_cstr_from_str`]: BumpAllocatorTypedScope::alloc_cstr_from_str
145 ///
146 /// [`alloc_zeroed_slice`]: crate::zerocopy_08::BumpAllocatorTypedScopeExt::alloc_zeroed_slice
147 ///
148 /// [`alloc_iter`]: BumpAllocatorTypedScope::alloc_iter
149 /// [`alloc_iter_exact`]: BumpAllocatorTypedScope::alloc_iter_exact
150 /// [`alloc_iter_mut`]: MutBumpAllocatorTypedScope::alloc_iter_mut
151 /// [`alloc_iter_mut_rev`]: MutBumpAllocatorTypedScope::alloc_iter_mut_rev
152 ///
153 /// [`alloc_uninit`]: BumpAllocatorTypedScope::alloc_uninit
154 /// [`alloc_uninit_slice`]: BumpAllocatorTypedScope::alloc_uninit_slice
155 /// [`alloc_uninit_slice_for`]: BumpAllocatorTypedScope::alloc_uninit_slice_for
156 ///
157 /// [`alloc_try_with`]: Bump::alloc_try_with
158 /// [`alloc_try_with_mut`]: Bump::alloc_try_with_mut
159 ///
160 /// [`alloc_clone`]: BumpAllocatorTypedScope::alloc_clone
161 ///
162 /// [`scoped`]: crate::traits::BumpAllocator::scoped
163 /// [`scoped_aligned`]: crate::traits::BumpAllocator::scoped_aligned
164 /// [`scope_guard`]: crate::traits::BumpAllocator::scope_guard
165 ///
166 /// [`checkpoint`]: BumpAllocatorCore::checkpoint
167 /// [`reset_to`]: BumpAllocatorCore::reset_to
168 ///
169 /// [`reset`]: Bump::reset
170 /// [`reset_to_start`]: Bump::reset_to_start
171 /// [`dealloc`]: BumpAllocatorTyped::dealloc
172 ///
173 /// [`aligned`]: BumpAllocatorScope::aligned
174 ///
175 /// [`with_settings`]: Bump::with_settings
176 /// [`borrow_with_settings`]: Bump::borrow_with_settings
177 /// [`borrow_mut_with_settings`]: Bump::borrow_with_settings
178 ///
179 /// # Gotcha
180 ///
181 /// Having live allocations and entering bump scopes at the same time requires a `BumpScope`.
182 /// This is due to the way lifetimes work, since `Bump` returns allocations with the lifetime
183 /// of its own borrow instead of a separate lifetime like `BumpScope` does.
184 ///
185 /// So you can't do this:
186 /// ```compile_fail,E0502
187 /// # use bump_scope::Bump;
188 /// let mut bump: Bump = Bump::new();
189 ///
190 /// let one = bump.alloc(1);
191 ///
192 /// bump.scoped(|bump| {
193 /// // whatever
194 /// # _ = bump;
195 /// });
196 /// # _ = one;
197 /// ```
198 /// But you can make the code work by converting the `Bump` it to a [`BumpScope`] first using [`as_mut_scope`]:
199 /// ```
200 /// # use bump_scope::Bump;
201 /// let mut bump: Bump = Bump::new();
202 /// let bump = bump.as_mut_scope();
203 ///
204 /// let one = bump.alloc(1);
205 ///
206 /// bump.scoped(|bump| {
207 /// // whatever
208 /// # _ = bump;
209 /// });
210 /// # _ = one;
211 /// ```
212 ///
213 /// [`as_mut_scope`]: Bump::as_mut_scope
214 #[repr(transparent)]
215 pub struct Bump<$($allocator_parameter)*, S = BumpSettings>
216 where
217 A: Allocator,
218 S: BumpAllocatorSettings,
219 {
220 pub(crate) raw: RawBump<A, S>,
221 }
222 };
223}
224
225maybe_default_allocator!(make_type);
226
227// Sending Bumps when nothing is allocated is fine.
228// When something is allocated Bump is borrowed and sending is not possible.
229unsafe impl<A, S> Send for Bump<A, S>
230where
231 A: Allocator,
232 S: BumpAllocatorSettings,
233{
234}
235
236impl<A, S> UnwindSafe for Bump<A, S>
237where
238 A: Allocator + UnwindSafe,
239 S: BumpAllocatorSettings,
240{
241}
242
243impl<A, S> RefUnwindSafe for Bump<A, S>
244where
245 A: Allocator + RefUnwindSafe,
246 S: BumpAllocatorSettings,
247{
248}
249
250impl<A, S> Drop for Bump<A, S>
251where
252 A: Allocator,
253 S: BumpAllocatorSettings,
254{
255 fn drop(&mut self) {
256 unsafe { self.raw.manually_drop() }
257 }
258}
259
260impl<A, S> Debug for Bump<A, S>
261where
262 A: Allocator,
263 S: BumpAllocatorSettings,
264{
265 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266 AnyStats::from(self.stats()).debug_format("Bump", f)
267 }
268}
269
270#[cfg(feature = "panic-on-alloc")]
271impl<A, S> Default for Bump<A, S>
272where
273 A: Allocator + Default,
274 S: BumpAllocatorSettings,
275{
276 /// With [`GUARANTEED_ALLOCATED`] this does the same as [`new`], otherwise it does the same as [`unallocated`].
277 ///
278 /// [`GUARANTEED_ALLOCATED`]: crate::settings
279 /// [`new`]: Bump::new
280 /// [`unallocated`]: Bump::unallocated
281 #[inline(always)]
282 fn default() -> Self {
283 if S::GUARANTEED_ALLOCATED {
284 Self::new_in(Default::default())
285 } else {
286 use core::{cell::Cell, marker::PhantomData};
287
288 use crate::{chunk::ChunkHeader, raw_bump::RawChunk};
289
290 Self {
291 raw: RawBump {
292 chunk: Cell::new(RawChunk {
293 header: ChunkHeader::unallocated::<S>().cast(),
294 marker: PhantomData,
295 }),
296 },
297 }
298 }
299 }
300}
301
302#[cfg(not(feature = "panic-on-alloc"))]
303impl<A, S> Default for Bump<A, S>
304where
305 A: Allocator + Default,
306 S: BumpAllocatorSettings<GuaranteedAllocated = False>,
307{
308 /// Does the same as [`unallocated`].
309 ///
310 /// [`unallocated`]: Bump::unallocated
311 #[inline(always)]
312 fn default() -> Self {
313 Self::unallocated()
314 }
315}
316
317impl<A, S> Bump<A, S>
318where
319 A: Allocator,
320 S: BumpAllocatorSettings<GuaranteedAllocated = False>,
321{
322 /// Constructs a new `Bump` without allocating a chunk.
323 ///
324 /// This requires the `GUARANTEED_ALLOCATED` setting to be `false`, see [`settings`].
325 ///
326 /// # Examples
327 ///
328 /// ```
329 /// use bump_scope::{
330 /// alloc::Global,
331 /// Bump,
332 /// settings::{BumpSettings, BumpAllocatorSettings}
333 /// };
334 ///
335 /// type Settings = <BumpSettings as BumpAllocatorSettings>::WithGuaranteedAllocated<false>;
336 ///
337 /// let bump: Bump<Global, Settings> = Bump::unallocated();
338 /// # _ = bump;
339 /// ```
340 ///
341 /// [`settings`]: crate::settings
342 #[must_use]
343 pub const fn unallocated() -> Self {
344 Self { raw: RawBump::new() }
345 }
346}
347
348/// Methods for a `Bump` with a default base allocator.
349impl<A, S> Bump<A, S>
350where
351 A: Allocator + Default,
352 S: BumpAllocatorSettings,
353{
354 /// Constructs a new `Bump` with a default size hint for the first chunk.
355 ///
356 /// This is equivalent to <code>[with_size][]([MINIMUM_CHUNK_SIZE])</code>.
357 ///
358 /// # Panics
359 /// Panics if the allocation fails.
360 ///
361 /// # Examples
362 /// ```
363 /// use bump_scope::Bump;
364 ///
365 /// let bump: Bump = Bump::new();
366 /// # _ = bump;
367 /// ```
368 ///
369 /// [with_size]: Bump::with_size
370 /// [MINIMUM_CHUNK_SIZE]: crate::settings
371 #[must_use]
372 #[inline(always)]
373 #[cfg(feature = "panic-on-alloc")]
374 pub fn new() -> Self {
375 Self::with_size(S::MINIMUM_CHUNK_SIZE)
376 }
377
378 /// Constructs a new `Bump` with a default size hint for the first chunk.
379 ///
380 /// This is equivalent to <code>[try_with_size][]([MINIMUM_CHUNK_SIZE])</code>.
381 ///
382 /// # Errors
383 /// Errors if the allocation fails.
384 ///
385 /// # Examples
386 /// ```
387 /// use bump_scope::Bump;
388 ///
389 /// let bump: Bump = Bump::try_new()?;
390 /// # _ = bump;
391 /// # Ok::<(), bump_scope::alloc::AllocError>(())
392 /// ```
393 ///
394 /// [try_with_size]: Bump::try_with_size
395 /// [MINIMUM_CHUNK_SIZE]: crate::settings
396 #[inline(always)]
397 pub fn try_new() -> Result<Self, AllocError> {
398 Self::try_with_size(S::MINIMUM_CHUNK_SIZE)
399 }
400
401 /// Constructs a new `Bump` with a size hint for the first chunk.
402 ///
403 /// If you want to ensure a specific capacity, use [`with_capacity`](Self::with_capacity) instead.
404 ///
405 /// An effort is made to ensure the size requested from the base allocator is friendly to an allocator that uses size classes and stores metadata alongside allocations.
406 /// To achieve this, the requested size is rounded up to either the next power of two or the next multiple of `0x1000`, whichever is smaller.
407 /// After that, the size of `[usize; 2]` is subtracted.
408 ///
409 /// If the base allocator returns a memory block that is larger than requested, then the chunk will use the extra space.
410 ///
411 /// **Disclaimer:** The way in which the chunk layout is calculated might change.
412 /// Such a change is not considered semver breaking.
413 ///
414 /// # Panics
415 /// Panics if the allocation fails.
416 ///
417 /// # Examples
418 /// ```
419 /// use bump_scope::Bump;
420 ///
421 /// // `Bump` with a roughly 1 Mebibyte sized chunk
422 /// let bump_1mib: Bump = Bump::with_size(1024 * 1024);
423 /// # _ = bump_1mib;
424 /// ```
425 #[must_use]
426 #[inline(always)]
427 #[cfg(feature = "panic-on-alloc")]
428 pub fn with_size(size: usize) -> Self {
429 panic_on_error(Self::generic_with_size(size))
430 }
431
432 /// Constructs a new `Bump` with a size hint for the first chunk.
433 ///
434 /// If you want to ensure a specific capacity, use [`try_with_capacity`](Self::try_with_capacity) instead.
435 ///
436 /// An effort is made to ensure the size requested from the base allocator is friendly to an allocator that uses size classes and stores metadata alongside allocations.
437 /// To achieve this, the requested size is rounded up to either the next power of two or the next multiple of `0x1000`, whichever is smaller.
438 /// After that, the size of `[usize; 2]` is subtracted.
439 ///
440 /// If the base allocator returns a memory block that is larger than requested, then the chunk will use the extra space.
441 ///
442 /// **Disclaimer:** The way in which the chunk layout is calculated might change.
443 /// Such a change is not considered semver breaking.
444 ///
445 /// # Errors
446 /// Errors if the allocation fails.
447 ///
448 /// # Examples
449 /// ```
450 /// use bump_scope::Bump;
451 ///
452 /// // `Bump` with a roughly 1 Mebibyte sized chunk
453 /// let bump_1mib: Bump = Bump::try_with_size(1024 * 1024)?;
454 /// # _ = bump_1mib;
455 /// # Ok::<(), bump_scope::alloc::AllocError>(())
456 /// ```
457 #[inline(always)]
458 pub fn try_with_size(size: usize) -> Result<Self, AllocError> {
459 Self::generic_with_size(size)
460 }
461
462 #[inline]
463 pub(crate) fn generic_with_size<E: ErrorBehavior>(size: usize) -> Result<Self, E> {
464 Self::generic_with_size_in(size, Default::default())
465 }
466
467 /// Constructs a new `Bump` with a chunk that has at least enough space for `layout`.
468 ///
469 /// To construct a `Bump` with a size hint use <code>[with_size](Bump::with_size)</code> instead.
470 ///
471 /// # Panics
472 /// Panics if the allocation fails.
473 ///
474 /// # Examples
475 /// ```
476 /// use bump_scope::Bump;
477 /// use core::alloc::Layout;
478 ///
479 /// let layout = Layout::array::<u8>(1234).unwrap();
480 /// let bump: Bump = Bump::with_capacity(layout);
481 /// assert!(bump.stats().capacity() >= layout.size());
482 /// ```
483 #[must_use]
484 #[inline(always)]
485 #[cfg(feature = "panic-on-alloc")]
486 pub fn with_capacity(layout: Layout) -> Self {
487 panic_on_error(Self::generic_with_capacity(layout))
488 }
489
490 /// Constructs a new `Bump` with a chunk that has at least enough space for `layout`.
491 ///
492 /// To construct a `Bump` with a size hint use <code>[try_with_size](Bump::try_with_size)</code> instead.
493 ///
494 /// # Errors
495 /// Errors if the allocation fails.
496 ///
497 /// # Examples
498 /// ```
499 /// use bump_scope::Bump;
500 /// use core::alloc::Layout;
501 ///
502 /// let layout = Layout::array::<u8>(1234).unwrap();
503 /// let bump: Bump = Bump::try_with_capacity(layout)?;
504 /// assert!(bump.stats().capacity() >= layout.size());
505 /// # Ok::<(), bump_scope::alloc::AllocError>(())
506 /// ```
507 #[inline(always)]
508 pub fn try_with_capacity(layout: Layout) -> Result<Self, AllocError> {
509 Self::generic_with_capacity(layout)
510 }
511
512 #[inline]
513 pub(crate) fn generic_with_capacity<E: ErrorBehavior>(layout: Layout) -> Result<Self, E> {
514 Self::generic_with_capacity_in(layout, Default::default())
515 }
516}
517
518/// Methods that are always available.
519impl<A, S> Bump<A, S>
520where
521 A: Allocator,
522 S: BumpAllocatorSettings,
523{
524 /// Constructs a new `Bump` with a default size hint for the first chunk.
525 ///
526 /// This is equivalent to <code>[with_size_in][]([MINIMUM_CHUNK_SIZE], allocator)</code>.
527 ///
528 /// # Panics
529 /// Panics if the allocation fails.
530 ///
531 /// # Examples
532 /// ```
533 /// use bump_scope::Bump;
534 /// use bump_scope::alloc::Global;
535 ///
536 /// let bump: Bump = Bump::new_in(Global);
537 /// # _ = bump;
538 /// ```
539 ///
540 /// [with_size_in]: Bump::with_size_in
541 /// [MINIMUM_CHUNK_SIZE]: crate::settings
542 #[must_use]
543 #[inline(always)]
544 #[cfg(feature = "panic-on-alloc")]
545 pub fn new_in(allocator: A) -> Self {
546 Self::with_size_in(S::MINIMUM_CHUNK_SIZE, allocator)
547 }
548
549 /// Constructs a new `Bump` with a default size hint for the first chunk.
550 ///
551 /// This is equivalent to <code>[try_with_size_in][]([MINIMUM_CHUNK_SIZE], allocator)</code>.
552 ///
553 /// # Errors
554 /// Errors if the allocation fails.
555 ///
556 /// # Examples
557 /// ```
558 /// use bump_scope::Bump;
559 /// use bump_scope::alloc::Global;
560 ///
561 /// let bump: Bump = Bump::try_new_in(Global)?;
562 /// # _ = bump;
563 /// # Ok::<(), bump_scope::alloc::AllocError>(())
564 /// ```
565 ///
566 /// [try_with_size_in]: Bump::try_with_size_in
567 /// [MINIMUM_CHUNK_SIZE]: crate::settings
568 #[inline(always)]
569 pub fn try_new_in(allocator: A) -> Result<Self, AllocError> {
570 Self::try_with_size_in(S::MINIMUM_CHUNK_SIZE, allocator)
571 }
572
573 /// Constructs a new `Bump` with a size hint for the first chunk.
574 ///
575 /// If you want to ensure a specific capacity, use [`with_capacity_in`](Self::with_capacity_in) instead.
576 ///
577 /// An effort is made to ensure the size requested from the base allocator is friendly to an allocator that uses size classes and stores metadata alongside allocations.
578 /// To achieve this, the requested size is rounded up to either the next power of two or the next multiple of `0x1000`, whichever is smaller.
579 /// After that, the size of `[usize; 2]` is subtracted.
580 ///
581 /// If the base allocator returns a memory block that is larger than requested, then the chunk will use the extra space.
582 ///
583 /// **Disclaimer:** The way in which the chunk layout is calculated might change.
584 /// Such a change is not considered semver breaking.
585 ///
586 /// # Panics
587 /// Panics if the allocation fails.
588 ///
589 /// # Examples
590 /// ```
591 /// use bump_scope::Bump;
592 /// use bump_scope::alloc::Global;
593 ///
594 /// // `Bump` with a roughly 1 Mebibyte sized chunk
595 /// let bump_1mib: Bump = Bump::with_size_in(1024 * 1024, Global);
596 /// # _ = bump_1mib;
597 /// ```
598 #[must_use]
599 #[inline(always)]
600 #[cfg(feature = "panic-on-alloc")]
601 pub fn with_size_in(size: usize, allocator: A) -> Self {
602 panic_on_error(Self::generic_with_size_in(size, allocator))
603 }
604
605 /// Constructs a new `Bump` with a size hint for the first chunk.
606 ///
607 /// If you want to ensure a specific capacity, use [`try_with_capacity`](Self::try_with_capacity) instead.
608 ///
609 /// An effort is made to ensure the size requested from the base allocator is friendly to an allocator that uses size classes and stores metadata alongside allocations.
610 /// To achieve this, the requested size is rounded up to either the next power of two or the next multiple of `0x1000`, whichever is smaller.
611 /// After that, the size of `[usize; 2]` is subtracted.
612 ///
613 /// If the base allocator returns a memory block that is larger than requested, then the chunk will use the extra space.
614 ///
615 /// **Disclaimer:** The way in which the chunk layout is calculated might change.
616 /// Such a change is not considered semver breaking.
617 ///
618 /// # Errors
619 /// Errors if the allocation fails.
620 ///
621 /// # Examples
622 /// ```
623 /// use bump_scope::Bump;
624 /// use bump_scope::alloc::Global;
625 ///
626 /// // `Bump` with a roughly 1 Mebibyte sized chunk
627 /// let bump_1mib: Bump = Bump::try_with_size_in(1024 * 1024, Global)?;
628 /// # _ = bump_1mib;
629 /// # Ok::<(), bump_scope::alloc::AllocError>(())
630 /// ```
631 #[inline(always)]
632 pub fn try_with_size_in(size: usize, allocator: A) -> Result<Self, AllocError> {
633 Self::generic_with_size_in(size, allocator)
634 }
635
636 #[inline]
637 pub(crate) fn generic_with_size_in<E: ErrorBehavior>(size: usize, allocator: A) -> Result<Self, E> {
638 Ok(Self {
639 raw: RawBump::with_size(
640 ChunkSize::<A, S>::from_hint(size).ok_or_else(E::capacity_overflow)?,
641 allocator,
642 )?,
643 })
644 }
645
646 /// Constructs a new `Bump` with at least enough space for `layout`.
647 ///
648 /// To construct a `Bump` with a size hint use <code>[with_size_in](Bump::with_size_in)</code> instead.
649 ///
650 /// # Panics
651 /// Panics if the allocation fails.
652 ///
653 /// # Examples
654 /// ```
655 /// use bump_scope::Bump;
656 /// use bump_scope::alloc::Global;
657 /// use core::alloc::Layout;
658 ///
659 /// let layout = Layout::array::<u8>(1234).unwrap();
660 /// let bump: Bump = Bump::with_capacity_in(layout, Global);
661 /// assert!(bump.stats().capacity() >= layout.size());
662 /// # Ok::<(), bump_scope::alloc::AllocError>(())
663 /// ```
664 #[must_use]
665 #[inline(always)]
666 #[cfg(feature = "panic-on-alloc")]
667 pub fn with_capacity_in(layout: Layout, allocator: A) -> Self {
668 panic_on_error(Self::generic_with_capacity_in(layout, allocator))
669 }
670
671 /// Constructs a new `Bump` with at least enough space for `layout`.
672 ///
673 /// To construct a `Bump` with a size hint use <code>[try_with_size_in](Bump::try_with_size_in)</code> instead.
674 ///
675 /// # Errors
676 /// Errors if the allocation fails.
677 ///
678 /// # Examples
679 /// ```
680 /// use bump_scope::Bump;
681 /// use bump_scope::alloc::Global;
682 /// use core::alloc::Layout;
683 ///
684 /// let layout = Layout::array::<u8>(1234).unwrap();
685 /// let bump: Bump = Bump::try_with_capacity_in(layout, Global)?;
686 /// assert!(bump.stats().capacity() >= layout.size());
687 /// # Ok::<(), bump_scope::alloc::AllocError>(())
688 /// ```
689 #[inline(always)]
690 pub fn try_with_capacity_in(layout: Layout, allocator: A) -> Result<Self, AllocError> {
691 Self::generic_with_capacity_in(layout, allocator)
692 }
693
694 #[inline]
695 pub(crate) fn generic_with_capacity_in<E: ErrorBehavior>(layout: Layout, allocator: A) -> Result<Self, E> {
696 Ok(Self {
697 raw: RawBump::with_size(
698 ChunkSize::<A, S>::from_capacity(layout).ok_or_else(E::capacity_overflow)?,
699 allocator,
700 )?,
701 })
702 }
703
704 /// Resets this bump allocator and deallocates all but the largest chunk.
705 ///
706 /// This deallocates all allocations at once by resetting
707 /// the bump pointer to the start of the retained chunk.
708 ///
709 /// For a version of this function that doesn't deallocate chunks, see [`reset_to_start`].
710 ///
711 /// [`reset_to_start`]: Self::reset_to_start
712 ///
713 /// # Examples
714 ///
715 /// Basic usage:
716 ///
717 /// ```
718 /// # use bump_scope::Bump;
719 /// let mut scratch_allocator: Bump = Bump::new();
720 /// let items = [1, 2, 3];
721 ///
722 /// for item in items {
723 /// // the scratch allocator is empty
724 /// assert_eq!(scratch_allocator.stats().allocated(), 0);
725 ///
726 /// // allocate on scratch allocator...
727 /// let _ = scratch_allocator.alloc_fmt(format_args!("hello {item}"));
728 ///
729 /// // reset the scratch allocator for the next iteration
730 /// scratch_allocator.reset();
731 /// }
732 /// ```
733 ///
734 /// Detailed behavior:
735 ///
736 /// ```
737 /// # use bump_scope::Bump;
738 /// let mut bump: Bump = Bump::with_size(512);
739 ///
740 /// // won't fit in the first chunk, will be allocated in another chunk
741 /// bump.alloc_uninit_slice::<u8>(600);
742 ///
743 /// let chunks = bump.stats().small_to_big().collect::<Vec<_>>();
744 /// assert_eq!(chunks.len(), 2);
745 /// assert!(chunks[0].size() < chunks[1].size());
746 /// assert_eq!(chunks[0].allocated(), 0);
747 /// assert_eq!(chunks[1].allocated(), 600);
748 /// let last_chunk_size = chunks[1].size();
749 ///
750 /// bump.reset();
751 ///
752 /// let chunks = bump.stats().small_to_big().collect::<Vec<_>>();
753 /// assert_eq!(chunks.len(), 1);
754 /// assert_eq!(chunks[0].size(), last_chunk_size);
755 /// assert_eq!(chunks[0].allocated(), 0);
756 /// ```
757 #[inline(always)]
758 pub fn reset(&mut self) {
759 self.raw.reset();
760 }
761
762 /// Resets this bump allocator.
763 ///
764 /// This deallocates all allocations at once by resetting
765 /// the bump pointer to the start of the first chunk.
766 ///
767 /// For a version of this function that also deallocates chunks, see [`reset`].
768 ///
769 /// [`reset`]: Self::reset
770 ///
771 /// # Examples
772 ///
773 /// Basic usage:
774 ///
775 /// ```
776 /// # use bump_scope::Bump;
777 /// let mut scratch_allocator: Bump = Bump::new();
778 /// let items = [1, 2, 3];
779 ///
780 /// for item in items {
781 /// // the scratch allocator is empty
782 /// assert_eq!(scratch_allocator.stats().allocated(), 0);
783 ///
784 /// // allocate on scratch allocator...
785 /// let _ = scratch_allocator.alloc_fmt(format_args!("hello {item}"));
786 ///
787 /// // reset the scratch allocator for the next iteration
788 /// scratch_allocator.reset_to_start();
789 /// }
790 /// ```
791 ///
792 /// Detailed behavior:
793 ///
794 /// ```
795 /// # use bump_scope::Bump;
796 /// let mut bump: Bump = Bump::with_size(512);
797 ///
798 /// // won't fit in the first chunk, will be allocated in another chunk
799 /// bump.alloc_uninit_slice::<u8>(600);
800 ///
801 /// let chunks = bump.stats().small_to_big().collect::<Vec<_>>();
802 /// assert_eq!(chunks.len(), 2);
803 /// assert!(chunks[0].size() < chunks[1].size());
804 /// assert_eq!(chunks[0].allocated(), 0);
805 /// assert_eq!(chunks[1].allocated(), 600);
806 ///
807 /// bump.reset_to_start();
808 ///
809 /// // we still have two chunks...
810 /// assert_eq!(bump.stats().count(), 2);
811 ///
812 /// // ... but everything is deallocated
813 /// assert_eq!(bump.stats().allocated(), 0);
814 ///
815 /// // we are back at the first chunk
816 /// assert!(bump.stats().current_chunk().unwrap().prev().is_none());
817 /// ```
818 #[inline(always)]
819 pub fn reset_to_start(&mut self) {
820 self.raw.reset_to_start();
821 }
822
823 /// Returns a type which provides statistics about the memory usage of the bump allocator.
824 #[must_use]
825 #[inline(always)]
826 pub fn stats(&self) -> Stats<'_, A, S> {
827 self.as_scope().stats()
828 }
829
830 /// Returns this `&Bump` as a `&BumpScope`.
831 #[must_use]
832 #[inline(always)]
833 pub fn as_scope(&self) -> &BumpScope<'_, A, S> {
834 unsafe { transmute_ref(self) }
835 }
836
837 /// Returns this `&mut Bump` as a `&mut BumpScope`.
838 #[must_use]
839 #[inline(always)]
840 pub fn as_mut_scope(&mut self) -> &mut BumpScope<'_, A, S> {
841 unsafe { transmute_mut(self) }
842 }
843
844 /// Converts this `Bump` into a `Bump` with new settings.
845 ///
846 /// This function will fail to compile if:
847 /// - `NewS::UP != S::UP`
848 ///
849 /// # Panics
850 /// Panics if `!NewS::CLAIMABLE` and the bump allocator is currently [claimed].
851 ///
852 /// Panics if `NewS::GUARANTEED_ALLOCATED` and no chunk has been allocated.
853 ///
854 /// [claimed]: crate::traits::BumpAllocatorScope::claim
855 #[inline]
856 pub fn with_settings<NewS>(self) -> Bump<A, NewS>
857 where
858 A: BaseAllocator<NewS::GuaranteedAllocated>,
859 NewS: BumpAllocatorSettings,
860 {
861 self.raw.ensure_satisfies_settings::<NewS>();
862 unsafe { transmute_value(self) }
863 }
864
865 /// Borrows this `Bump` with new settings.
866 ///
867 /// This function will fail to compile if:
868 /// - `NewS::MIN_ALIGN != S::MIN_ALIGN`
869 /// - `NewS::UP != S::UP`
870 /// - `NewS::CLAIMABLE != S::CLAIMABLE`
871 /// - `NewS::GUARANTEED_ALLOCATED > S::GUARANTEED_ALLOCATED`
872 #[inline]
873 pub fn borrow_with_settings<NewS>(&self) -> &Bump<A, NewS>
874 where
875 A: BaseAllocator<NewS::GuaranteedAllocated>,
876 NewS: BumpAllocatorSettings,
877 {
878 self.raw.ensure_satisfies_settings_for_borrow::<NewS>();
879 unsafe { transmute_ref(self) }
880 }
881
882 /// Borrows this `Bump` mutably with new settings.
883 ///
884 /// This function will fail to compile if:
885 /// - `NewS::MIN_ALIGN < S::MIN_ALIGN`
886 /// - `NewS::UP != S::UP`
887 /// - `NewS::GUARANTEED_ALLOCATED != S::GUARANTEED_ALLOCATED`
888 /// - `NewS::CLAIMABLE != S::CLAIMABLE`
889 #[inline]
890 pub fn borrow_mut_with_settings<NewS>(&mut self) -> &mut Bump<A, NewS>
891 where
892 A: BaseAllocator<NewS::GuaranteedAllocated>,
893 NewS: BumpAllocatorSettings,
894 {
895 self.raw.ensure_satisfies_settings_for_borrow_mut::<NewS>();
896 unsafe { transmute_mut(self) }
897 }
898
899 /// Converts this `Bump` into a raw pointer.
900 ///
901 /// ```
902 /// # use bump_scope::Bump;
903 /// #
904 /// let bump: Bump = Bump::new();
905 /// bump.alloc_str("Hello, ");
906 ///
907 /// let ptr = bump.into_raw();
908 /// let bump: Bump = unsafe { Bump::from_raw(ptr) };
909 ///
910 /// bump.alloc_str("World!");
911 /// # assert_eq!(bump.stats().allocated(), 13);
912 /// ```
913 #[inline]
914 #[must_use]
915 pub fn into_raw(self) -> NonNull<()> {
916 ManuallyDrop::new(self).raw.clone().into_raw()
917 }
918
919 /// Converts the raw pointer that was created with [`into_raw`](Bump::into_raw) back into a `Bump`.
920 ///
921 /// # Safety
922 /// - `ptr` must come from a call to `Self::into_raw`.
923 /// - This function must only be called once with this `ptr`.
924 /// - The settings must match the original ones.
925 #[inline]
926 #[must_use]
927 pub unsafe fn from_raw(ptr: NonNull<()>) -> Self {
928 Self {
929 raw: unsafe { RawBump::from_raw(ptr) },
930 }
931 }
932}
933
934impl<'b, A, S> From<&'b Bump<A, S>> for &'b BumpScope<'b, A, S>
935where
936 A: BaseAllocator<S::GuaranteedAllocated>,
937 S: BumpAllocatorSettings,
938{
939 #[inline(always)]
940 fn from(value: &'b Bump<A, S>) -> Self {
941 value.as_scope()
942 }
943}
944
945impl<'b, A, S> From<&'b mut Bump<A, S>> for &'b mut BumpScope<'b, A, S>
946where
947 A: BaseAllocator<S::GuaranteedAllocated>,
948 S: BumpAllocatorSettings,
949{
950 #[inline(always)]
951 fn from(value: &'b mut Bump<A, S>) -> Self {
952 value.as_mut_scope()
953 }
954}
955
956/// Methods that forward to traits.
957// Documentation is in the forwarded to methods.
958#[allow(clippy::missing_errors_doc, clippy::missing_safety_doc)]
959impl<A, S> Bump<A, S>
960where
961 A: BaseAllocator<S::GuaranteedAllocated>,
962 S: BumpAllocatorSettings,
963{
964 traits::forward_methods! {
965 self: self
966 access: {self.as_scope()}
967 access_mut: {self.as_mut_scope()}
968 lifetime: '_
969 }
970}
971
972/// Additional `alloc` methods that are not available in traits.
973impl<A, S> Bump<A, S>
974where
975 A: BaseAllocator<S::GuaranteedAllocated>,
976 S: BumpAllocatorSettings,
977{
978 /// Allocates the result of `f` in the bump allocator, then moves `E` out of it and deallocates the space it took up.
979 ///
980 /// This can be more performant than allocating `T` after the fact, as `Result<T, E>` may be constructed in the bump allocators memory instead of on the stack and then copied over.
981 ///
982 /// There is also [`alloc_try_with_mut`](Self::alloc_try_with_mut), optimized for a mutable reference.
983 ///
984 /// # Panics
985 /// Panics if the allocation fails.
986 ///
987 /// # Examples
988 #[cfg_attr(feature = "nightly-tests", doc = "```")]
989 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
990 /// # #![feature(offset_of_enum)]
991 /// # use core::mem::offset_of;
992 /// # use bump_scope::Bump;
993 /// # let bump: Bump = Bump::new();
994 /// let result = bump.alloc_try_with(|| -> Result<i32, i32> { Ok(123) });
995 /// assert_eq!(result.unwrap(), 123);
996 /// assert_eq!(bump.stats().allocated(), offset_of!(Result<i32, i32>, Ok.0) + size_of::<i32>());
997 /// ```
998 #[cfg_attr(feature = "nightly-tests", doc = "```")]
999 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
1000 /// # use bump_scope::Bump;
1001 /// # let bump: Bump = Bump::new();
1002 /// let result = bump.alloc_try_with(|| -> Result<i32, i32> { Err(123) });
1003 /// assert_eq!(result.unwrap_err(), 123);
1004 /// assert_eq!(bump.stats().allocated(), 0);
1005 /// ```
1006 #[inline(always)]
1007 #[cfg(feature = "panic-on-alloc")]
1008 #[expect(clippy::missing_errors_doc)]
1009 pub fn alloc_try_with<T, E>(&self, f: impl FnOnce() -> Result<T, E>) -> Result<BumpBox<'_, T>, E> {
1010 self.as_scope().alloc_try_with(f)
1011 }
1012
1013 /// Allocates the result of `f` in the bump allocator, then moves `E` out of it and deallocates the space it took up.
1014 ///
1015 /// This can be more performant than allocating `T` after the fact, as `Result<T, E>` may be constructed in the bump allocators memory instead of on the stack and then copied over.
1016 ///
1017 /// There is also [`try_alloc_try_with_mut`](Self::try_alloc_try_with_mut), optimized for a mutable reference.
1018 ///
1019 /// # Errors
1020 /// Errors if the allocation fails.
1021 ///
1022 /// # Examples
1023 #[cfg_attr(feature = "nightly-tests", doc = "```")]
1024 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
1025 /// # #![feature(offset_of_enum)]
1026 /// # use core::mem::offset_of;
1027 /// # use bump_scope::Bump;
1028 /// # let bump: Bump = Bump::new();
1029 /// let result = bump.try_alloc_try_with(|| -> Result<i32, i32> { Ok(123) })?;
1030 /// assert_eq!(result.unwrap(), 123);
1031 /// assert_eq!(bump.stats().allocated(), offset_of!(Result<i32, i32>, Ok.0) + size_of::<i32>());
1032 /// # Ok::<(), bump_scope::alloc::AllocError>(())
1033 /// ```
1034 #[cfg_attr(feature = "nightly-tests", doc = "```")]
1035 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
1036 /// # use bump_scope::Bump;
1037 /// # let bump: Bump = Bump::new();
1038 /// let result = bump.try_alloc_try_with(|| -> Result<i32, i32> { Err(123) })?;
1039 /// assert_eq!(result.unwrap_err(), 123);
1040 /// assert_eq!(bump.stats().allocated(), 0);
1041 /// # Ok::<(), bump_scope::alloc::AllocError>(())
1042 /// ```
1043 #[inline(always)]
1044 pub fn try_alloc_try_with<T, E>(
1045 &self,
1046 f: impl FnOnce() -> Result<T, E>,
1047 ) -> Result<Result<BumpBox<'_, T>, E>, AllocError> {
1048 self.as_scope().try_alloc_try_with(f)
1049 }
1050
1051 /// Allocates the result of `f` in the bump allocator, then moves `E` out of it and deallocates the space it took up.
1052 ///
1053 /// This can be more performant than allocating `T` after the fact, as `Result<T, E>` may be constructed in the bump allocators memory instead of on the stack and then copied over.
1054 ///
1055 /// This is just like [`alloc_try_with`](Self::alloc_try_with), but optimized for a mutable reference.
1056 ///
1057 /// # Panics
1058 /// Panics if the allocation fails.
1059 ///
1060 /// # Examples
1061 #[cfg_attr(feature = "nightly-tests", doc = "```")]
1062 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
1063 /// # #![feature(offset_of_enum)]
1064 /// # use core::mem::offset_of;
1065 /// # use bump_scope::Bump;
1066 /// # let mut bump: Bump = Bump::new();
1067 /// let result = bump.alloc_try_with_mut(|| -> Result<i32, i32> { Ok(123) });
1068 /// assert_eq!(result.unwrap(), 123);
1069 /// assert_eq!(bump.stats().allocated(), offset_of!(Result<i32, i32>, Ok.0) + size_of::<i32>());
1070 /// ```
1071 #[cfg_attr(feature = "nightly-tests", doc = "```")]
1072 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
1073 /// # use bump_scope::Bump;
1074 /// # let mut bump: Bump = Bump::new();
1075 /// let result = bump.alloc_try_with_mut(|| -> Result<i32, i32> { Err(123) });
1076 /// assert_eq!(result.unwrap_err(), 123);
1077 /// assert_eq!(bump.stats().allocated(), 0);
1078 /// ```
1079 #[inline(always)]
1080 #[cfg(feature = "panic-on-alloc")]
1081 #[expect(clippy::missing_errors_doc)]
1082 pub fn alloc_try_with_mut<T, E>(&mut self, f: impl FnOnce() -> Result<T, E>) -> Result<BumpBox<'_, T>, E> {
1083 self.as_mut_scope().alloc_try_with_mut(f)
1084 }
1085
1086 /// Allocates the result of `f` in the bump allocator, then moves `E` out of it and deallocates the space it took up.
1087 ///
1088 /// This can be more performant than allocating `T` after the fact, as `Result<T, E>` may be constructed in the bump allocators memory instead of on the stack and then copied over.
1089 ///
1090 /// This is just like [`try_alloc_try_with`](Self::try_alloc_try_with), but optimized for a mutable reference.
1091 ///
1092 /// # Errors
1093 /// Errors if the allocation fails.
1094 ///
1095 /// # Examples
1096 #[cfg_attr(feature = "nightly-tests", doc = "```")]
1097 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
1098 /// # #![feature(offset_of_enum)]
1099 /// # use core::mem::offset_of;
1100 /// # use bump_scope::Bump;
1101 /// # let mut bump: Bump = Bump::new();
1102 /// let result = bump.try_alloc_try_with_mut(|| -> Result<i32, i32> { Ok(123) })?;
1103 /// assert_eq!(result.unwrap(), 123);
1104 /// assert_eq!(bump.stats().allocated(), offset_of!(Result<i32, i32>, Ok.0) + size_of::<i32>());
1105 /// # Ok::<(), bump_scope::alloc::AllocError>(())
1106 /// ```
1107 #[cfg_attr(feature = "nightly-tests", doc = "```")]
1108 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
1109 /// # use bump_scope::Bump;
1110 /// # let mut bump: Bump = Bump::new();
1111 /// let result = bump.try_alloc_try_with_mut(|| -> Result<i32, i32> { Err(123) })?;
1112 /// assert_eq!(result.unwrap_err(), 123);
1113 /// assert_eq!(bump.stats().allocated(), 0);
1114 /// # Ok::<(), bump_scope::alloc::AllocError>(())
1115 /// ```
1116 #[inline(always)]
1117 pub fn try_alloc_try_with_mut<T, E>(
1118 &mut self,
1119 f: impl FnOnce() -> Result<T, E>,
1120 ) -> Result<Result<BumpBox<'_, T>, E>, AllocError> {
1121 self.as_mut_scope().try_alloc_try_with_mut(f)
1122 }
1123}
1124
1125unsafe impl<A, S> Allocator for Bump<A, S>
1126where
1127 A: BaseAllocator<S::GuaranteedAllocated>,
1128 S: BumpAllocatorSettings,
1129{
1130 #[inline(always)]
1131 fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
1132 allocator_impl::allocate(&self.raw, layout)
1133 }
1134
1135 #[inline(always)]
1136 unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
1137 unsafe { allocator_impl::deallocate(&self.raw, ptr, layout) };
1138 }
1139
1140 #[inline(always)]
1141 unsafe fn grow(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
1142 unsafe { allocator_impl::grow(&self.raw, ptr, old_layout, new_layout) }
1143 }
1144
1145 #[inline(always)]
1146 unsafe fn grow_zeroed(
1147 &self,
1148 ptr: NonNull<u8>,
1149 old_layout: Layout,
1150 new_layout: Layout,
1151 ) -> Result<NonNull<[u8]>, AllocError> {
1152 unsafe { allocator_impl::grow_zeroed(&self.raw, ptr, old_layout, new_layout) }
1153 }
1154
1155 #[inline(always)]
1156 unsafe fn shrink(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
1157 unsafe { allocator_impl::shrink(&self.raw, ptr, old_layout, new_layout) }
1158 }
1159}