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][]([MINIMUM_CHUNK_SIZE])</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 ///
367 /// [with_size]: Bump::with_size
368 /// [MINIMUM_CHUNK_SIZE]: crate::settings
369 #[must_use]
370 #[inline(always)]
371 #[cfg(feature = "panic-on-alloc")]
372 pub fn new() -> Self {
373 Self::with_size(S::MINIMUM_CHUNK_SIZE)
374 }
375
376 /// Constructs a new `Bump` with a default size hint for the first chunk.
377 ///
378 /// This is equivalent to <code>[try_with_size][]([MINIMUM_CHUNK_SIZE])</code>.
379 ///
380 /// # Errors
381 /// Errors if the allocation fails.
382 ///
383 /// # Examples
384 /// ```
385 /// use bump_scope::Bump;
386 ///
387 /// let bump: Bump = Bump::try_new()?;
388 /// # _ = bump;
389 /// # Ok::<(), bump_scope::alloc::AllocError>(())
390 /// ```
391 ///
392 /// [try_with_size]: Bump::try_with_size
393 /// [MINIMUM_CHUNK_SIZE]: crate::settings
394 #[inline(always)]
395 pub fn try_new() -> Result<Self, AllocError> {
396 Self::try_with_size(S::MINIMUM_CHUNK_SIZE)
397 }
398
399 /// Constructs a new `Bump` with a size hint for the first chunk.
400 ///
401 /// If you want to ensure a specific capacity, use [`with_capacity`](Self::with_capacity) instead.
402 ///
403 /// 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.
404 /// 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.
405 /// After that, the size of `[usize; 2]` is subtracted.
406 ///
407 /// If the base allocator returns a memory block that is larger than requested, then the chunk will use the extra space.
408 ///
409 /// **Disclaimer:** The way in which the chunk layout is calculated might change.
410 /// Such a change is not considered semver breaking.
411 ///
412 /// # Panics
413 /// Panics if the allocation fails.
414 ///
415 /// # Examples
416 /// ```
417 /// use bump_scope::Bump;
418 ///
419 /// // `Bump` with a roughly 1 Mebibyte sized chunk
420 /// let bump_1mib: Bump = Bump::with_size(1024 * 1024);
421 /// # _ = bump_1mib;
422 /// ```
423 #[must_use]
424 #[inline(always)]
425 #[cfg(feature = "panic-on-alloc")]
426 pub fn with_size(size: usize) -> Self {
427 panic_on_error(Self::generic_with_size(size))
428 }
429
430 /// Constructs a new `Bump` with a size hint for the first chunk.
431 ///
432 /// If you want to ensure a specific capacity, use [`try_with_capacity`](Self::try_with_capacity) instead.
433 ///
434 /// 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.
435 /// 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.
436 /// After that, the size of `[usize; 2]` is subtracted.
437 ///
438 /// If the base allocator returns a memory block that is larger than requested, then the chunk will use the extra space.
439 ///
440 /// **Disclaimer:** The way in which the chunk layout is calculated might change.
441 /// Such a change is not considered semver breaking.
442 ///
443 /// # Errors
444 /// Errors if the allocation fails.
445 ///
446 /// # Examples
447 /// ```
448 /// use bump_scope::Bump;
449 ///
450 /// // `Bump` with a roughly 1 Mebibyte sized chunk
451 /// let bump_1mib: Bump = Bump::try_with_size(1024 * 1024)?;
452 /// # _ = bump_1mib;
453 /// # Ok::<(), bump_scope::alloc::AllocError>(())
454 /// ```
455 #[inline(always)]
456 pub fn try_with_size(size: usize) -> Result<Self, AllocError> {
457 Self::generic_with_size(size)
458 }
459
460 #[inline]
461 pub(crate) fn generic_with_size<E: ErrorBehavior>(size: usize) -> Result<Self, E> {
462 Self::generic_with_size_in(size, Default::default())
463 }
464
465 /// Constructs a new `Bump` with a chunk that has at least enough space for `layout`.
466 ///
467 /// To construct a `Bump` with a size hint use <code>[with_size](Bump::with_size)</code> instead.
468 ///
469 /// # Panics
470 /// Panics if the allocation fails.
471 ///
472 /// # Examples
473 /// ```
474 /// use bump_scope::Bump;
475 /// use core::alloc::Layout;
476 ///
477 /// let layout = Layout::array::<u8>(1234).unwrap();
478 /// let bump: Bump = Bump::with_capacity(layout);
479 /// assert!(bump.stats().capacity() >= layout.size());
480 /// ```
481 #[must_use]
482 #[inline(always)]
483 #[cfg(feature = "panic-on-alloc")]
484 pub fn with_capacity(layout: Layout) -> Self {
485 panic_on_error(Self::generic_with_capacity(layout))
486 }
487
488 /// Constructs a new `Bump` with a chunk that has at least enough space for `layout`.
489 ///
490 /// To construct a `Bump` with a size hint use <code>[try_with_size](Bump::try_with_size)</code> instead.
491 ///
492 /// # Errors
493 /// Errors if the allocation fails.
494 ///
495 /// # Examples
496 /// ```
497 /// use bump_scope::Bump;
498 /// use core::alloc::Layout;
499 ///
500 /// let layout = Layout::array::<u8>(1234).unwrap();
501 /// let bump: Bump = Bump::try_with_capacity(layout)?;
502 /// assert!(bump.stats().capacity() >= layout.size());
503 /// # Ok::<(), bump_scope::alloc::AllocError>(())
504 /// ```
505 #[inline(always)]
506 pub fn try_with_capacity(layout: Layout) -> Result<Self, AllocError> {
507 Self::generic_with_capacity(layout)
508 }
509
510 #[inline]
511 pub(crate) fn generic_with_capacity<E: ErrorBehavior>(layout: Layout) -> Result<Self, E> {
512 Self::generic_with_capacity_in(layout, Default::default())
513 }
514}
515
516/// Methods that are always available.
517impl<A, S> Bump<A, S>
518where
519 A: Allocator,
520 S: BumpAllocatorSettings,
521{
522 /// Constructs a new `Bump` with a default size hint for the first chunk.
523 ///
524 /// This is equivalent to <code>[with_size_in][]([MINIMUM_CHUNK_SIZE], allocator)</code>.
525 ///
526 /// # Panics
527 /// Panics if the allocation fails.
528 ///
529 /// # Examples
530 /// ```
531 /// use bump_scope::Bump;
532 /// use bump_scope::alloc::Global;
533 ///
534 /// let bump: Bump = Bump::new_in(Global);
535 /// # _ = bump;
536 /// ```
537 ///
538 /// [with_size_in]: Bump::with_size_in
539 /// [MINIMUM_CHUNK_SIZE]: crate::settings
540 #[must_use]
541 #[inline(always)]
542 #[cfg(feature = "panic-on-alloc")]
543 pub fn new_in(allocator: A) -> Self {
544 Self::with_size_in(S::MINIMUM_CHUNK_SIZE, allocator)
545 }
546
547 /// Constructs a new `Bump` with a default size hint for the first chunk.
548 ///
549 /// This is equivalent to <code>[try_with_size_in][]([MINIMUM_CHUNK_SIZE], allocator)</code>.
550 ///
551 /// # Errors
552 /// Errors if the allocation fails.
553 ///
554 /// # Examples
555 /// ```
556 /// use bump_scope::Bump;
557 /// use bump_scope::alloc::Global;
558 ///
559 /// let bump: Bump = Bump::try_new_in(Global)?;
560 /// # _ = bump;
561 /// # Ok::<(), bump_scope::alloc::AllocError>(())
562 /// ```
563 ///
564 /// [try_with_size_in]: Bump::try_with_size_in
565 /// [MINIMUM_CHUNK_SIZE]: crate::settings
566 #[inline(always)]
567 pub fn try_new_in(allocator: A) -> Result<Self, AllocError> {
568 Self::try_with_size_in(S::MINIMUM_CHUNK_SIZE, allocator)
569 }
570
571 /// Constructs a new `Bump` with a size hint for the first chunk.
572 ///
573 /// If you want to ensure a specific capacity, use [`with_capacity_in`](Self::with_capacity_in) instead.
574 ///
575 /// 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.
576 /// 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.
577 /// After that, the size of `[usize; 2]` is subtracted.
578 ///
579 /// If the base allocator returns a memory block that is larger than requested, then the chunk will use the extra space.
580 ///
581 /// **Disclaimer:** The way in which the chunk layout is calculated might change.
582 /// Such a change is not considered semver breaking.
583 ///
584 /// # Panics
585 /// Panics if the allocation fails.
586 ///
587 /// # Examples
588 /// ```
589 /// use bump_scope::Bump;
590 /// use bump_scope::alloc::Global;
591 ///
592 /// // `Bump` with a roughly 1 Mebibyte sized chunk
593 /// let bump_1mib: Bump = Bump::with_size_in(1024 * 1024, Global);
594 /// # _ = bump_1mib;
595 /// ```
596 #[must_use]
597 #[inline(always)]
598 #[cfg(feature = "panic-on-alloc")]
599 pub fn with_size_in(size: usize, allocator: A) -> Self {
600 panic_on_error(Self::generic_with_size_in(size, allocator))
601 }
602
603 /// Constructs a new `Bump` with a size hint for the first chunk.
604 ///
605 /// If you want to ensure a specific capacity, use [`try_with_capacity`](Self::try_with_capacity) instead.
606 ///
607 /// 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.
608 /// 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.
609 /// After that, the size of `[usize; 2]` is subtracted.
610 ///
611 /// If the base allocator returns a memory block that is larger than requested, then the chunk will use the extra space.
612 ///
613 /// **Disclaimer:** The way in which the chunk layout is calculated might change.
614 /// Such a change is not considered semver breaking.
615 ///
616 /// # Errors
617 /// Errors if the allocation fails.
618 ///
619 /// # Examples
620 /// ```
621 /// use bump_scope::Bump;
622 /// use bump_scope::alloc::Global;
623 ///
624 /// // `Bump` with a roughly 1 Mebibyte sized chunk
625 /// let bump_1mib: Bump = Bump::try_with_size_in(1024 * 1024, Global)?;
626 /// # _ = bump_1mib;
627 /// # Ok::<(), bump_scope::alloc::AllocError>(())
628 /// ```
629 #[inline(always)]
630 pub fn try_with_size_in(size: usize, allocator: A) -> Result<Self, AllocError> {
631 Self::generic_with_size_in(size, allocator)
632 }
633
634 #[inline]
635 pub(crate) fn generic_with_size_in<E: ErrorBehavior>(size: usize, allocator: A) -> Result<Self, E> {
636 Ok(Self {
637 raw: RawBump::with_size(
638 ChunkSize::<A, S>::from_hint(size).ok_or_else(E::capacity_overflow)?,
639 allocator,
640 )?,
641 })
642 }
643
644 /// Constructs a new `Bump` with at least enough space for `layout`.
645 ///
646 /// To construct a `Bump` with a size hint use <code>[with_size_in](Bump::with_size_in)</code> instead.
647 ///
648 /// # Panics
649 /// Panics if the allocation fails.
650 ///
651 /// # Examples
652 /// ```
653 /// use bump_scope::Bump;
654 /// use bump_scope::alloc::Global;
655 /// use core::alloc::Layout;
656 ///
657 /// let layout = Layout::array::<u8>(1234).unwrap();
658 /// let bump: Bump = Bump::with_capacity_in(layout, Global);
659 /// assert!(bump.stats().capacity() >= layout.size());
660 /// # Ok::<(), bump_scope::alloc::AllocError>(())
661 /// ```
662 #[must_use]
663 #[inline(always)]
664 #[cfg(feature = "panic-on-alloc")]
665 pub fn with_capacity_in(layout: Layout, allocator: A) -> Self {
666 panic_on_error(Self::generic_with_capacity_in(layout, allocator))
667 }
668
669 /// Constructs a new `Bump` with at least enough space for `layout`.
670 ///
671 /// To construct a `Bump` with a size hint use <code>[try_with_size_in](Bump::try_with_size_in)</code> instead.
672 ///
673 /// # Errors
674 /// Errors if the allocation fails.
675 ///
676 /// # Examples
677 /// ```
678 /// use bump_scope::Bump;
679 /// use bump_scope::alloc::Global;
680 /// use core::alloc::Layout;
681 ///
682 /// let layout = Layout::array::<u8>(1234).unwrap();
683 /// let bump: Bump = Bump::try_with_capacity_in(layout, Global)?;
684 /// assert!(bump.stats().capacity() >= layout.size());
685 /// # Ok::<(), bump_scope::alloc::AllocError>(())
686 /// ```
687 #[inline(always)]
688 pub fn try_with_capacity_in(layout: Layout, allocator: A) -> Result<Self, AllocError> {
689 Self::generic_with_capacity_in(layout, allocator)
690 }
691
692 #[inline]
693 pub(crate) fn generic_with_capacity_in<E: ErrorBehavior>(layout: Layout, allocator: A) -> Result<Self, E> {
694 Ok(Self {
695 raw: RawBump::with_size(
696 ChunkSize::<A, S>::from_capacity(layout).ok_or_else(E::capacity_overflow)?,
697 allocator,
698 )?,
699 })
700 }
701
702 // This needs `&mut self` to make sure that no allocations are alive.
703 /// Deallocates every chunk but the newest, which is also the biggest.
704 ///
705 /// ```
706 /// use bump_scope::Bump;
707 ///
708 /// let mut bump: Bump = Bump::with_size(512);
709 ///
710 /// // won't fit in the first chunk
711 /// bump.alloc_uninit_slice::<u8>(600);
712 ///
713 /// let chunks = bump.stats().small_to_big().collect::<Vec<_>>();
714 /// assert_eq!(chunks.len(), 2);
715 /// assert!(chunks[0].size() < chunks[1].size());
716 /// assert_eq!(chunks[0].allocated(), 0);
717 /// assert_eq!(chunks[1].allocated(), 600);
718 /// let last_chunk_size = chunks[1].size();
719 ///
720 /// bump.reset();
721 ///
722 /// let chunks = bump.stats().small_to_big().collect::<Vec<_>>();
723 /// assert_eq!(chunks.len(), 1);
724 /// assert_eq!(chunks[0].size(), last_chunk_size);
725 /// assert_eq!(chunks[0].allocated(), 0);
726 /// ```
727 #[inline(always)]
728 pub fn reset(&mut self) {
729 self.raw.reset();
730 }
731
732 /// Returns a type which provides statistics about the memory usage of the bump allocator.
733 #[must_use]
734 #[inline(always)]
735 pub fn stats(&self) -> Stats<'_, A, S> {
736 self.as_scope().stats()
737 }
738
739 /// Returns this `&Bump` as a `&BumpScope`.
740 #[must_use]
741 #[inline(always)]
742 pub fn as_scope(&self) -> &BumpScope<'_, A, S> {
743 unsafe { transmute_ref(self) }
744 }
745
746 /// Returns this `&mut Bump` as a `&mut BumpScope`.
747 #[must_use]
748 #[inline(always)]
749 pub fn as_mut_scope(&mut self) -> &mut BumpScope<'_, A, S> {
750 unsafe { transmute_mut(self) }
751 }
752
753 /// Converts this `Bump` into a `Bump` with new settings.
754 ///
755 /// This function will fail to compile if:
756 /// - `NewS::UP != S::UP`
757 ///
758 /// # Panics
759 /// Panics if `!NewS::CLAIMABLE` and the bump allocator is currently [claimed].
760 ///
761 /// Panics if `NewS::GUARANTEED_ALLOCATED` and no chunk has been allocated.
762 ///
763 /// [claimed]: crate::traits::BumpAllocatorScope::claim
764 #[inline]
765 pub fn with_settings<NewS>(self) -> Bump<A, NewS>
766 where
767 A: BaseAllocator<NewS::GuaranteedAllocated>,
768 NewS: BumpAllocatorSettings,
769 {
770 self.raw.ensure_satisfies_settings::<NewS>();
771 unsafe { transmute_value(self) }
772 }
773
774 /// Borrows this `Bump` with new settings.
775 ///
776 /// This function will fail to compile if:
777 /// - `NewS::MIN_ALIGN != S::MIN_ALIGN`
778 /// - `NewS::UP != S::UP`
779 /// - `NewS::CLAIMABLE != S::CLAIMABLE`
780 /// - `NewS::GUARANTEED_ALLOCATED > S::GUARANTEED_ALLOCATED`
781 #[inline]
782 pub fn borrow_with_settings<NewS>(&self) -> &Bump<A, NewS>
783 where
784 A: BaseAllocator<NewS::GuaranteedAllocated>,
785 NewS: BumpAllocatorSettings,
786 {
787 self.raw.ensure_satisfies_settings_for_borrow::<NewS>();
788 unsafe { transmute_ref(self) }
789 }
790
791 /// Borrows this `Bump` mutably with new settings.
792 ///
793 /// This function will fail to compile if:
794 /// - `NewS::MIN_ALIGN < S::MIN_ALIGN`
795 /// - `NewS::UP != S::UP`
796 /// - `NewS::GUARANTEED_ALLOCATED != S::GUARANTEED_ALLOCATED`
797 /// - `NewS::CLAIMABLE != S::CLAIMABLE`
798 #[inline]
799 pub fn borrow_mut_with_settings<NewS>(&mut self) -> &mut Bump<A, NewS>
800 where
801 A: BaseAllocator<NewS::GuaranteedAllocated>,
802 NewS: BumpAllocatorSettings,
803 {
804 self.raw.ensure_satisfies_settings_for_borrow_mut::<NewS>();
805 unsafe { transmute_mut(self) }
806 }
807
808 /// Converts this `Bump` into a raw pointer.
809 ///
810 /// ```
811 /// # use bump_scope::Bump;
812 /// #
813 /// let bump: Bump = Bump::new();
814 /// bump.alloc_str("Hello, ");
815 ///
816 /// let ptr = bump.into_raw();
817 /// let bump: Bump = unsafe { Bump::from_raw(ptr) };
818 ///
819 /// bump.alloc_str("World!");
820 /// # assert_eq!(bump.stats().allocated(), 13);
821 /// ```
822 #[inline]
823 #[must_use]
824 pub fn into_raw(self) -> NonNull<()> {
825 ManuallyDrop::new(self).raw.clone().into_raw()
826 }
827
828 /// Converts the raw pointer that was created with [`into_raw`](Bump::into_raw) back into a `Bump`.
829 ///
830 /// # Safety
831 /// - `ptr` must come from a call to `Self::into_raw`.
832 /// - This function must only be called once with this `ptr`.
833 /// - The settings must match the original ones.
834 #[inline]
835 #[must_use]
836 pub unsafe fn from_raw(ptr: NonNull<()>) -> Self {
837 Self {
838 raw: unsafe { RawBump::from_raw(ptr) },
839 }
840 }
841}
842
843impl<'b, A, S> From<&'b Bump<A, S>> for &'b BumpScope<'b, A, S>
844where
845 A: BaseAllocator<S::GuaranteedAllocated>,
846 S: BumpAllocatorSettings,
847{
848 #[inline(always)]
849 fn from(value: &'b Bump<A, S>) -> Self {
850 value.as_scope()
851 }
852}
853
854impl<'b, A, S> From<&'b mut Bump<A, S>> for &'b mut BumpScope<'b, A, S>
855where
856 A: BaseAllocator<S::GuaranteedAllocated>,
857 S: BumpAllocatorSettings,
858{
859 #[inline(always)]
860 fn from(value: &'b mut Bump<A, S>) -> Self {
861 value.as_mut_scope()
862 }
863}
864
865/// Methods that forward to traits.
866// Documentation is in the forwarded to methods.
867#[allow(clippy::missing_errors_doc, clippy::missing_safety_doc)]
868impl<A, S> Bump<A, S>
869where
870 A: BaseAllocator<S::GuaranteedAllocated>,
871 S: BumpAllocatorSettings,
872{
873 traits::forward_methods! {
874 self: self
875 access: {self.as_scope()}
876 access_mut: {self.as_mut_scope()}
877 lifetime: '_
878 }
879}
880
881/// Additional `alloc` methods that are not available in traits.
882impl<A, S> Bump<A, S>
883where
884 A: BaseAllocator<S::GuaranteedAllocated>,
885 S: BumpAllocatorSettings,
886{
887 /// Allocates the result of `f` in the bump allocator, then moves `E` out of it and deallocates the space it took up.
888 ///
889 /// 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.
890 ///
891 /// There is also [`alloc_try_with_mut`](Self::alloc_try_with_mut), optimized for a mutable reference.
892 ///
893 /// # Panics
894 /// Panics if the allocation fails.
895 ///
896 /// # Examples
897 #[cfg_attr(feature = "nightly-tests", doc = "```")]
898 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
899 /// # #![feature(offset_of_enum)]
900 /// # use core::mem::offset_of;
901 /// # use bump_scope::Bump;
902 /// # let bump: Bump = Bump::new();
903 /// let result = bump.alloc_try_with(|| -> Result<i32, i32> { Ok(123) });
904 /// assert_eq!(result.unwrap(), 123);
905 /// assert_eq!(bump.stats().allocated(), offset_of!(Result<i32, i32>, Ok.0) + size_of::<i32>());
906 /// ```
907 #[cfg_attr(feature = "nightly-tests", doc = "```")]
908 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
909 /// # use bump_scope::Bump;
910 /// # let bump: Bump = Bump::new();
911 /// let result = bump.alloc_try_with(|| -> Result<i32, i32> { Err(123) });
912 /// assert_eq!(result.unwrap_err(), 123);
913 /// assert_eq!(bump.stats().allocated(), 0);
914 /// ```
915 #[inline(always)]
916 #[cfg(feature = "panic-on-alloc")]
917 #[expect(clippy::missing_errors_doc)]
918 pub fn alloc_try_with<T, E>(&self, f: impl FnOnce() -> Result<T, E>) -> Result<BumpBox<'_, T>, E> {
919 self.as_scope().alloc_try_with(f)
920 }
921
922 /// Allocates the result of `f` in the bump allocator, then moves `E` out of it and deallocates the space it took up.
923 ///
924 /// 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.
925 ///
926 /// There is also [`try_alloc_try_with_mut`](Self::try_alloc_try_with_mut), optimized for a mutable reference.
927 ///
928 /// # Errors
929 /// Errors if the allocation fails.
930 ///
931 /// # Examples
932 #[cfg_attr(feature = "nightly-tests", doc = "```")]
933 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
934 /// # #![feature(offset_of_enum)]
935 /// # use core::mem::offset_of;
936 /// # use bump_scope::Bump;
937 /// # let bump: Bump = Bump::new();
938 /// let result = bump.try_alloc_try_with(|| -> Result<i32, i32> { Ok(123) })?;
939 /// assert_eq!(result.unwrap(), 123);
940 /// assert_eq!(bump.stats().allocated(), offset_of!(Result<i32, i32>, Ok.0) + size_of::<i32>());
941 /// # Ok::<(), bump_scope::alloc::AllocError>(())
942 /// ```
943 #[cfg_attr(feature = "nightly-tests", doc = "```")]
944 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
945 /// # use bump_scope::Bump;
946 /// # let bump: Bump = Bump::new();
947 /// let result = bump.try_alloc_try_with(|| -> Result<i32, i32> { Err(123) })?;
948 /// assert_eq!(result.unwrap_err(), 123);
949 /// assert_eq!(bump.stats().allocated(), 0);
950 /// # Ok::<(), bump_scope::alloc::AllocError>(())
951 /// ```
952 #[inline(always)]
953 pub fn try_alloc_try_with<T, E>(
954 &self,
955 f: impl FnOnce() -> Result<T, E>,
956 ) -> Result<Result<BumpBox<'_, T>, E>, AllocError> {
957 self.as_scope().try_alloc_try_with(f)
958 }
959
960 /// Allocates the result of `f` in the bump allocator, then moves `E` out of it and deallocates the space it took up.
961 ///
962 /// 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.
963 ///
964 /// This is just like [`alloc_try_with`](Self::alloc_try_with), but optimized for a mutable reference.
965 ///
966 /// # Panics
967 /// Panics if the allocation fails.
968 ///
969 /// # Examples
970 #[cfg_attr(feature = "nightly-tests", doc = "```")]
971 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
972 /// # #![feature(offset_of_enum)]
973 /// # use core::mem::offset_of;
974 /// # use bump_scope::Bump;
975 /// # let mut bump: Bump = Bump::new();
976 /// let result = bump.alloc_try_with_mut(|| -> Result<i32, i32> { Ok(123) });
977 /// assert_eq!(result.unwrap(), 123);
978 /// assert_eq!(bump.stats().allocated(), offset_of!(Result<i32, i32>, Ok.0) + size_of::<i32>());
979 /// ```
980 #[cfg_attr(feature = "nightly-tests", doc = "```")]
981 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
982 /// # use bump_scope::Bump;
983 /// # let mut bump: Bump = Bump::new();
984 /// let result = bump.alloc_try_with_mut(|| -> Result<i32, i32> { Err(123) });
985 /// assert_eq!(result.unwrap_err(), 123);
986 /// assert_eq!(bump.stats().allocated(), 0);
987 /// ```
988 #[inline(always)]
989 #[cfg(feature = "panic-on-alloc")]
990 #[expect(clippy::missing_errors_doc)]
991 pub fn alloc_try_with_mut<T, E>(&mut self, f: impl FnOnce() -> Result<T, E>) -> Result<BumpBox<'_, T>, E> {
992 self.as_mut_scope().alloc_try_with_mut(f)
993 }
994
995 /// Allocates the result of `f` in the bump allocator, then moves `E` out of it and deallocates the space it took up.
996 ///
997 /// 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.
998 ///
999 /// This is just like [`try_alloc_try_with`](Self::try_alloc_try_with), but optimized for a mutable reference.
1000 ///
1001 /// # Errors
1002 /// Errors if the allocation fails.
1003 ///
1004 /// # Examples
1005 #[cfg_attr(feature = "nightly-tests", doc = "```")]
1006 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
1007 /// # #![feature(offset_of_enum)]
1008 /// # use core::mem::offset_of;
1009 /// # use bump_scope::Bump;
1010 /// # let mut bump: Bump = Bump::new();
1011 /// let result = bump.try_alloc_try_with_mut(|| -> Result<i32, i32> { Ok(123) })?;
1012 /// assert_eq!(result.unwrap(), 123);
1013 /// assert_eq!(bump.stats().allocated(), offset_of!(Result<i32, i32>, Ok.0) + size_of::<i32>());
1014 /// # Ok::<(), bump_scope::alloc::AllocError>(())
1015 /// ```
1016 #[cfg_attr(feature = "nightly-tests", doc = "```")]
1017 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
1018 /// # use bump_scope::Bump;
1019 /// # let mut bump: Bump = Bump::new();
1020 /// let result = bump.try_alloc_try_with_mut(|| -> Result<i32, i32> { Err(123) })?;
1021 /// assert_eq!(result.unwrap_err(), 123);
1022 /// assert_eq!(bump.stats().allocated(), 0);
1023 /// # Ok::<(), bump_scope::alloc::AllocError>(())
1024 /// ```
1025 #[inline(always)]
1026 pub fn try_alloc_try_with_mut<T, E>(
1027 &mut self,
1028 f: impl FnOnce() -> Result<T, E>,
1029 ) -> Result<Result<BumpBox<'_, T>, E>, AllocError> {
1030 self.as_mut_scope().try_alloc_try_with_mut(f)
1031 }
1032}