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