Skip to main content

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}