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