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](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}