bump_scope/
lib.rs

1// NB: We avoid using closures to map `Result` and `Option`s in various places because they result in less readable assembly output.
2// When using closures, functions like `capacity_overflow` can get the name of some closure that invokes it instead, like `bump_scope::mut_bump_vec::MutBumpVec<T,_,_,A>::generic_grow_amortized::{{closure}}`.
3
4// This crate uses modified code from the rust standard library. <https://github.com/rust-lang/rust/tree/master/library>.
5// Especially `BumpBox` methods, vectors, strings, `polyfill` and `tests/from_std` are based on code from the standard library.
6
7#![no_std]
8#![cfg_attr(
9    any(feature = "nightly-allocator-api", feature = "nightly-fn-traits"),
10    feature(allocator_api)
11)]
12#![cfg_attr(feature = "nightly-coerce-unsized", feature(coerce_unsized, unsize))]
13#![cfg_attr(feature = "nightly-exact-size-is-empty", feature(exact_size_is_empty))]
14#![cfg_attr(feature = "nightly-trusted-len", feature(trusted_len))]
15#![cfg_attr(feature = "nightly-fn-traits", feature(fn_traits, tuple_trait, unboxed_closures))]
16#![cfg_attr(feature = "nightly-tests", feature(offset_of_enum))]
17#![cfg_attr(feature = "nightly-dropck-eyepatch", feature(dropck_eyepatch))]
18#![cfg_attr(feature = "nightly-clone-to-uninit", feature(clone_to_uninit, ptr_metadata))]
19#![cfg_attr(docsrs,
20    feature(doc_auto_cfg, doc_cfg_hide),
21    doc(cfg_hide(feature = "panic-on-alloc")) // too noisy
22)]
23#![warn(
24    clippy::pedantic,
25    clippy::cargo,
26    clippy::correctness,
27    clippy::perf,
28    clippy::style,
29    clippy::suspicious,
30    missing_docs,
31    rustdoc::missing_crate_level_docs
32)]
33#![allow(
34    clippy::inline_always,
35    clippy::module_name_repetitions,
36    clippy::copy_iterator,
37    clippy::comparison_chain,
38    clippy::partialeq_ne_impl,
39    clippy::collapsible_else_if,
40    clippy::items_after_statements,
41    clippy::missing_transmute_annotations,
42    clippy::range_plus_one,
43    clippy::multiple_crate_versions, // we have allocator-api2 version 0.2 and 0.3
44    rustdoc::invalid_rust_codeblocks, // for our current workaround to conditionally enable doc tests in macro
45)]
46#![doc(test(
47    attr(deny(dead_code, unused_imports, deprecated)),
48    attr(cfg_attr(feature = "nightly-allocator-api", feature(allocator_api, btreemap_alloc))),
49))]
50//! <!-- crate documentation intro start -->
51//! A fast bump allocator that supports allocation scopes / checkpoints. Aka an arena for values of arbitrary types.
52//! <!-- crate documentation intro end -->
53//!
54//! **[Changelog][CHANGELOG] -**
55//! **[Crates.io](https://crates.io/crates/bump-scope) -**
56//! **[Repository](https://github.com/bluurryy/bump-scope)**
57//!
58//! <!-- crate documentation rest start -->
59//! # What is bump allocation?
60//! A bump allocator owns a big chunk of memory. It has a pointer that starts at one end of that chunk.
61//! When an allocation is made that pointer gets aligned and bumped towards the other end of the chunk.
62//! When its chunk is full, this allocator allocates another chunk with twice the size.
63//!
64//! This makes allocations very fast. The drawback is that you can't reclaim memory like you do with a more general allocator.
65//! Memory for the most recent allocation *can* be reclaimed. You can also use [scopes, checkpoints](#scopes-and-checkpoints) and [`reset`](Bump::reset) to reclaim memory.
66//!
67//! A bump allocator is great for *phase-oriented allocations* where you allocate objects in a loop and free them at the end of every iteration.
68//! ```
69//! use bump_scope::Bump;
70//! let mut bump: Bump = Bump::new();
71//! # let mut first = true;
72//!
73//! loop {
74//!     # if !first { break }; first = false;
75//!     // use bump ...
76//!     bump.reset();
77//! }
78//! ```
79//! The fact that the bump allocator allocates ever larger chunks and [`reset`](Bump::reset) only keeps around the largest one means that after a few iterations, every bump allocation
80//! will be done on the same chunk and no more chunks need to be allocated.
81//!
82//! The introduction of scopes makes this bump allocator also great for temporary allocations and stack-like usage.
83//!
84//! # Comparison to [`bumpalo`](https://docs.rs/bumpalo)
85//!
86//! Bumpalo is a popular crate for bump allocation.
87//! This crate was inspired by bumpalo and [Always Bump Downwards](https://fitzgeraldnick.com/2019/11/01/always-bump-downwards.html)
88//! (but ignores the title).
89//!
90//! Unlike `bumpalo`, this crate...
91//! - Supports [scopes and checkpoints](#scopes-and-checkpoints).
92//! - Drop is always called for allocated values unless explicitly [leaked](BumpBox::leak) or [forgotten](core::mem::forget).
93//!   - `alloc*` methods return a [`BumpBox<T>`](BumpBox) which owns and drops `T`. Types that don't need dropping can be turned into references with [`into_ref`](BumpBox::into_ref) and [`into_mut`](BumpBox::into_mut).
94//! - You can allocate a slice from *any* `Iterator` with [`alloc_iter`](Bump::alloc_iter).
95//! - Every method that panics on allocation failure has a fallible `try_*` counterpart.
96//! - `Bump`'s base allocator is generic.
97//! - Won't try to allocate a smaller chunk if allocation failed.
98//! - No built-in allocation limit. You can provide an allocator that enforces an allocation limit (see `tests/limit_memory_usage.rs`).
99//! - Allocations are a tiny bit more optimized. See [./crates/callgrind-benches][benches].
100//! - [You can choose the bump direction.](#bumping-upwards-or-downwards) Bumps upwards by default.
101//!
102//! # Allocator Methods
103//!
104//! The bump allocator provides many methods to conveniently allocate values, strings, and slices.
105//! Have a look at the documentation of [`Bump`] for a method overview.
106//!
107//! # Scopes and Checkpoints
108//!
109//! You can create scopes to make allocations that live only for a part of its parent scope.
110//! Entering and exiting scopes is virtually free. Allocating within a scope has no overhead.
111//!
112//! You can create a new scope either with a [`scoped`](Bump::scoped) closure or with a [`scope_guard`](Bump::scope_guard):
113//! ```
114//! use bump_scope::Bump;
115//!
116//! let mut bump: Bump = Bump::new();
117//!
118//! // you can use a closure
119//! bump.scoped(|mut bump| {
120//!     let hello = bump.alloc_str("hello");
121//!     assert_eq!(bump.stats().allocated(), 5);
122//!
123//!     bump.scoped(|bump| {
124//!         let world = bump.alloc_str("world");
125//!
126//!         println!("{hello} and {world} are both live");
127//!         assert_eq!(bump.stats().allocated(), 10);
128//!     });
129//!
130//!     println!("{hello} is still live");
131//!     assert_eq!(bump.stats().allocated(), 5);
132//! });
133//!
134//! assert_eq!(bump.stats().allocated(), 0);
135//!
136//! // or you can use scope guards
137//! {
138//!     let mut guard = bump.scope_guard();
139//!     let mut bump = guard.scope();
140//!
141//!     let hello = bump.alloc_str("hello");
142//!     assert_eq!(bump.stats().allocated(), 5);
143//!
144//!     {
145//!         let mut guard = bump.scope_guard();
146//!         let bump = guard.scope();
147//!
148//!         let world = bump.alloc_str("world");
149//!
150//!         println!("{hello} and {world} are both live");
151//!         assert_eq!(bump.stats().allocated(), 10);
152//!     }
153//!
154//!     println!("{hello} is still live");
155//!     assert_eq!(bump.stats().allocated(), 5);
156//! }
157//!
158//! assert_eq!(bump.stats().allocated(), 0);
159//! ```
160//! You can also use the unsafe [`checkpoint`](Bump::checkpoint) api
161//! to reset the bump pointer to a previous position.
162//! ```
163//! # use bump_scope::Bump;
164//! let bump: Bump = Bump::new();
165//! let checkpoint = bump.checkpoint();
166//!
167//! {
168//!     let hello = bump.alloc_str("hello");
169//!     assert_eq!(bump.stats().allocated(), 5);
170//!     # _ = hello;
171//! }
172//!
173//! unsafe { bump.reset_to(checkpoint); }
174//! assert_eq!(bump.stats().allocated(), 0);
175//! ```
176//!
177//! # Collections
178//! `bump-scope` provides bump allocated variants of `Vec` and `String` called [`BumpVec`] and [`BumpString`].
179//! They are also available in the following variants:
180//! - [`Fixed*`](FixedBumpVec) for fixed capacity collections
181//! - [`Mut*`](MutBumpVec) for collections optimized for a mutable bump allocator
182//!
183//! #### API changes
184//! The collections are designed to have the same api as their std counterparts with these exceptions:
185//! - [`split_off`](BumpVec::split_off) —  splits the collection in place without allocation; the parameter is a range instead of a single index
186//! - [`retain`](BumpVec::retain) —  takes a closure with a `&mut T` parameter like [`Vec::retain_mut`](alloc_crate::vec::Vec::retain_mut)
187//!
188//! #### New features
189//! - [`append`](BumpVec::append) —  allows appending all kinds of owned slice types like `[T; N]`, `Box<[T]>`, `Vec<T>`, `vec::Drain<T>` etc.
190//! - [`map`](BumpVec::map) —  maps the elements, potentially reusing the existing allocation
191//! - [`map_in_place`](BumpVec::map_in_place) —  maps the elements without allocation, failing to compile if not possible
192//! - conversions between the regular collections, their `Fixed*` variants and `BumpBox<[T]>` / `BumpBox<str>`
193//!
194//! # Parallel Allocation
195//! [`Bump`] is `!Sync` which means it can't be shared between threads.
196//!
197//! To bump allocate in parallel you can use a [`BumpPool`].
198//!
199//! # Allocator API
200//! `Bump` and `BumpScope` implement `bump-scope`'s own [`Allocator`] trait and with the
201//! respective [feature flags](#feature-flags) also implement `allocator_api2@0.2`, `allocator_api2@0.3` and nightly's `Allocator` trait.
202//! All of these traits mirror the nightly `Allocator` trait at the time of writing.
203//!
204//! This allows you to [bump allocate collections](crate::Bump#collections).
205//!
206//! A bump allocator can grow, shrink and deallocate the most recent allocation.
207//! When bumping upwards it can even do so in place.
208//! Growing allocations other than the most recent one will require a new allocation and the old memory block becomes wasted space.
209//! Shrinking or deallocating allocations other than the most recent one does nothing, which means wasted space.
210//!
211//! A bump allocator does not require `deallocate` or `shrink` to free memory.
212//! After all, memory will be reclaimed when exiting a scope, calling `reset` or dropping the `Bump`.
213//! You can set the `DEALLOCATES` const parameter to `false` to make shrinking and deallocating a no-op.
214//! There are also the [`WithoutDealloc`] and [`WithoutShrink`] wrappers.
215//! ```
216//! # #[cfg(feature = "allocator-api2-03")]
217//! # {
218//! use bump_scope::{Bump, WithoutDealloc};
219//! use allocator_api2_03::boxed::Box;
220//!
221//! let bump: Bump = Bump::new();
222//!
223//! let boxed = Box::new_in(5, &bump);
224//! assert_eq!(bump.stats().allocated(), 4);
225//! drop(boxed);
226//! assert_eq!(bump.stats().allocated(), 0);
227//!
228//! let boxed = Box::new_in(5, WithoutDealloc(&bump));
229//! assert_eq!(bump.stats().allocated(), 4);
230//! drop(boxed);
231//! assert_eq!(bump.stats().allocated(), 4);
232//! # }
233//! ```
234//!
235//! # Feature Flags
236//! <!-- feature documentation start -->
237//! - **`std`** *(enabled by default)* — Adds `BumpPool` and implementations of `std::io` traits.
238//! - **`alloc`** *(enabled by default)* — Adds `Global` as the default base allocator and some interactions with `alloc` collections.
239//! - **`panic-on-alloc`** *(enabled by default)* — Adds functions and traits that will panic when the allocation fails.
240//!   Without this feature, allocation failures cannot cause panics, and only
241//!   `try_`-prefixed allocation methods will be available.
242//! - **`serde`** — Adds `Serialize` implementations for `BumpBox`, strings and vectors, and `DeserializeSeed` for strings and vectors.
243//! - **`bytemuck`** — Adds `bytemuck::*` extension traits for
244//!   <code>[alloc_zeroed](bytemuck::BumpExt::alloc_zeroed)([_slice](bytemuck::BumpExt::alloc_zeroed_slice))</code>,
245//!   [`init_zeroed`](bytemuck::InitZeroed::init_zeroed),
246//!   [`extend_zeroed`](bytemuck::VecExt::extend_zeroed) and
247//!   [`resize_zeroed`](bytemuck::VecExt::resize_zeroed).
248//! - **`zerocopy-08`** — Adds `zerocopy_08::*` extension traits for
249//!   <code>[alloc_zeroed](zerocopy_08::BumpExt::alloc_zeroed)([_slice](zerocopy_08::BumpExt::alloc_zeroed_slice))</code>,
250//!   [`init_zeroed`](zerocopy_08::InitZeroed::init_zeroed),
251//!   [`extend_zeroed`](zerocopy_08::VecExt::extend_zeroed) and
252//!   [`resize_zeroed`](zerocopy_08::VecExt::resize_zeroed).
253//! - **`allocator-api2-02`** — Makes `Bump(Scope)` implement `allocator_api2` version `0.2`'s `Allocator` and
254//!   makes it possible to use an `allocator_api2::alloc::Allocator` as a base allocator via
255//!   [`AllocatorApi2V02Compat`](crate::alloc::compat::AllocatorApi2V02Compat).
256//! - **`allocator-api2-03`** — Makes `Bump(Scope)` implement `allocator_api2` version `0.3`'s `Allocator` and
257//!   makes it possible to use an `allocator_api2::alloc::Allocator` as a base allocator via
258//!   [`AllocatorApi2V03Compat`](crate::alloc::compat::AllocatorApi2V03Compat).
259//!
260//! ### Nightly features
261//! These nightly features are not subject to the same semver guarantees as the rest of the library.
262//! Breaking changes to these features might be introduced in minor releases to keep up with changes in the nightly channel.
263//!
264//! - **`nightly`** — Enables all other nightly feature flags.
265//! - **`nightly-allocator-api`** — Makes `Bump(Scope)` implement `alloc`'s `Allocator` and
266//!   allows using an `alloc::alloc::Allocator` as a base allocator via
267//!   [`AllocatorNightlyCompat`](crate::alloc::compat::AllocatorNightlyCompat).
268//!
269//!   This will also enable `allocator-api2` version `0.2`'s `nightly` feature.
270//! - **`nightly-coerce-unsized`** — Makes `BumpBox<T>` implement [`CoerceUnsized`](core::ops::CoerceUnsized).
271//!   With this `BumpBox<[i32;3]>` coerces to `BumpBox<[i32]>`, `BumpBox<dyn Debug>` and so on.
272//!   You can unsize a `BumpBox` in stable without this feature using [`unsize_bump_box`].
273//! - **`nightly-exact-size-is-empty`** — Implements `is_empty` manually for some iterators.
274//! - **`nightly-trusted-len`** — Implements `TrustedLen` for some iterators.
275//! - **`nightly-fn-traits`** — Implements `Fn*` traits for `BumpBox<T>`. Makes `BumpBox<T: FnOnce + ?Sized>` callable. Requires alloc crate.
276//! - **`nightly-tests`** — Enables some tests that require a nightly compiler.
277//! - **`nightly-dropck-eyepatch`** — Adds `#[may_dangle]` attribute to box and vector types' drop implementation.
278//!   This makes it so references don't have to strictly outlive the container.
279//!   (Just like with std's `Box` and `Vec`.)
280//! - **`nightly-clone-to-uninit`** — Adds [`alloc_clone`](Bump::alloc_clone) method to `Bump(Scope)`.
281//! <!-- feature documentation end -->
282//!
283//! # Bumping upwards or downwards?
284//! Bump direction is controlled by the generic parameter `const UP: bool`. By default, `UP` is `true`, so the allocator bumps upwards.
285//!
286//! Bumping upwards has the advantage that the most recent allocation can be grown and shrunk in place.
287//! This benefits collections as well as <code>[alloc_iter](Bump::alloc_iter)([_mut](Bump::alloc_iter_mut))</code> and <code>[alloc_fmt](Bump::alloc_fmt)([_mut](Bump::alloc_fmt_mut))</code>
288//! with the exception of [`MutBumpVecRev`] and [`alloc_iter_mut_rev`](Bump::alloc_iter_mut_rev) which
289//! can be grown and shrunk in place if and only if bumping downwards.
290//!
291//! Bumping downwards can be done in less instructions.
292//!
293//! For the performance impact see [./crates/callgrind-benches][benches].
294//!
295//! # What is minimum alignment?
296//! Minimum alignment is the alignment the bump pointer maintains when doing allocations.
297//!
298//! When allocating a type in a bump allocator with a sufficient minimum alignment,
299//! the bump pointer will not have to be aligned for the allocation but the allocation size
300//! will need to be rounded up to the next multiple of the minimum alignment.
301//!
302//! The minimum alignment is controlled by the generic parameter `const MIN_ALIGN: usize`. By default, `MIN_ALIGN` is `1`.
303//!
304//! For the performance impact see [./crates/callgrind-benches][benches].
305//!
306//! # What does *guaranteed allocated* mean?
307//!
308//! A *guaranteed allocated* bump allocator will own at least one chunk that it has allocated
309//! from its base allocator.
310//!
311//! The constructors [`new`], [`with_size`], [`with_capacity`] and their variants always allocate
312//! one chunk from the base allocator.
313//!
314//! The exception is the [`unallocated`] constructor which creates a `Bump` without allocating any
315//! chunks. Such a `Bump` will have the `GUARANTEED_ALLOCATED` generic parameter of `false`
316//! which will make the [`scoped`], [`scoped_aligned`], [`aligned`] and [`scope_guard`] methods unavailable.
317//!
318//! You can turn any non-`GUARANTEED_ALLOCATED` bump allocator into a guaranteed allocated one using
319//! [`as_guaranteed_allocated`], [`as_mut_guaranteed_allocated`] or [`into_guaranteed_allocated`].
320//!
321//! The point of this is so `Bump`s can be `const` constructed and constructed without allocating.
322//! At the same time `Bump`s that have already allocated a chunk don't suffer additional runtime checks.
323//!
324//! [benches]: https://github.com/bluurryy/bump-scope/tree/main/crates/callgrind-benches
325//! [`new`]: Bump::new
326//! [`with_size`]: Bump::with_size
327//! [`with_capacity`]: Bump::with_capacity
328//! [`unallocated`]: Bump::unallocated
329//! [`scoped`]: Bump::scoped
330//! [`scoped_aligned`]: Bump::scoped_aligned
331//! [`aligned`]: Bump::aligned
332//! [`scope_guard`]: Bump::scope_guard
333//! [`as_guaranteed_allocated`]: Bump::as_guaranteed_allocated
334//! [`as_mut_guaranteed_allocated`]: Bump::as_mut_guaranteed_allocated
335//! [`into_guaranteed_allocated`]: Bump::into_guaranteed_allocated
336//! <!-- crate documentation rest end -->
337
338#[cfg(any(feature = "std", test))]
339extern crate std;
340
341#[cfg(any(feature = "alloc", feature = "nightly-fn-traits"))]
342extern crate alloc as alloc_crate;
343
344pub mod alloc;
345mod allocator_impl;
346mod bump;
347mod bump_align_guard;
348/// Contains [`BumpBox`] and associated types.
349mod bump_box;
350#[cfg(feature = "std")]
351mod bump_pool;
352mod bump_scope;
353mod bump_scope_guard;
354/// Contains [`BumpString`] and associated types.
355mod bump_string;
356/// Contains [`BumpVec`] and associated types.
357pub mod bump_vec;
358mod bumping;
359mod chunk_size;
360mod destructure;
361mod error_behavior;
362mod features;
363mod fixed_bump_string;
364mod fixed_bump_vec;
365mod from_utf16_error;
366mod from_utf8_error;
367mod layout;
368mod mut_bump_string;
369/// Contains [`MutBumpVec`] and associated types.
370pub mod mut_bump_vec;
371/// Contains [`MutBumpVecRev`] and associated types.
372mod mut_bump_vec_rev;
373mod no_drop;
374/// Contains types associated with owned slices.
375pub mod owned_slice;
376/// Contains types associated with owned strings.
377pub mod owned_str;
378mod partial_eq;
379mod polyfill;
380mod raw_bump_box;
381mod raw_chunk;
382mod raw_fixed_bump_string;
383mod raw_fixed_bump_vec;
384mod set_len_on_drop;
385mod set_len_on_drop_by_ptr;
386pub mod stats;
387mod traits;
388mod without_dealloc;
389
390use alloc::Allocator;
391pub use bump::Bump;
392pub use bump_box::BumpBox;
393#[cfg(feature = "std")]
394pub use bump_pool::{BumpPool, BumpPoolGuard};
395pub use bump_scope::BumpScope;
396pub use bump_scope_guard::{BumpScopeGuard, BumpScopeGuardRoot, Checkpoint};
397pub use bump_string::BumpString;
398#[doc(inline)]
399pub use bump_vec::BumpVec;
400use chunk_header::ChunkHeader;
401#[cfg(feature = "panic-on-alloc")]
402use core::convert::Infallible;
403use core::{mem, num::NonZeroUsize, ptr::NonNull};
404use error_behavior::ErrorBehavior;
405pub use fixed_bump_string::FixedBumpString;
406pub use fixed_bump_vec::FixedBumpVec;
407pub use from_utf8_error::FromUtf8Error;
408pub use from_utf16_error::FromUtf16Error;
409use layout::ArrayLayout;
410pub use mut_bump_string::MutBumpString;
411#[doc(inline)]
412pub use mut_bump_vec::MutBumpVec;
413pub use mut_bump_vec_rev::MutBumpVecRev;
414pub use no_drop::NoDrop;
415#[cfg(feature = "panic-on-alloc")]
416use private::{PanicsOnAlloc, capacity_overflow, format_trait_error};
417use raw_chunk::RawChunk;
418use set_len_on_drop::SetLenOnDrop;
419pub use traits::{
420    BumpAllocator, BumpAllocatorExt, BumpAllocatorScope, BumpAllocatorScopeExt, MutBumpAllocator, MutBumpAllocatorExt,
421    MutBumpAllocatorScope, MutBumpAllocatorScopeExt,
422};
423pub use without_dealloc::{WithoutDealloc, WithoutShrink};
424
425#[doc = include_str!("../CHANGELOG.md")]
426#[expect(non_snake_case)]
427pub mod CHANGELOG {}
428
429#[cfg(feature = "bytemuck")]
430/// Contains extension traits.
431pub mod bytemuck {
432    pub use crate::features::bytemuck::{BumpExt, BumpScopeExt, InitZeroed, VecExt};
433}
434
435#[cfg(feature = "zerocopy-08")]
436/// Contains extension traits.
437pub mod zerocopy_08 {
438    pub use crate::features::zerocopy_08::{BumpExt, BumpScopeExt, InitZeroed, VecExt};
439}
440
441/// Specifies the current minimum alignment of a bump allocator.
442#[derive(Clone, Copy)]
443pub struct MinimumAlignment<const ALIGNMENT: usize>;
444
445mod supported_minimum_alignment {
446    use crate::ArrayLayout;
447
448    pub trait Sealed {
449        /// We'd be fine with just an [`core::ptr::Alignment`], but that's not stable.
450        #[doc(hidden)]
451        const LAYOUT: ArrayLayout;
452
453        #[doc(hidden)]
454        const MIN_ALIGN: usize;
455    }
456}
457
458/// Statically guarantees that a minimum alignment is marked as supported.
459///
460/// This trait is *sealed*: the list of implementors below is total. Users do not have the ability to mark additional
461/// `MinimumAlignment<N>` values as supported. Only bump allocators with the supported minimum alignments are constructable.
462#[allow(private_bounds)]
463pub trait SupportedMinimumAlignment: supported_minimum_alignment::Sealed + Copy {}
464
465macro_rules! supported_alignments {
466    ($($i:literal)*) => {
467        $(
468            impl supported_minimum_alignment::Sealed for MinimumAlignment<$i> {
469                const LAYOUT: ArrayLayout = match ArrayLayout::from_size_align(0, $i) {
470                    Ok(layout) => layout,
471                    Err(_) => unreachable!(),
472                };
473
474                const MIN_ALIGN: usize = $i;
475            }
476            impl SupportedMinimumAlignment for MinimumAlignment<$i> {}
477        )*
478    };
479}
480
481supported_alignments!(1 2 4 8 16);
482
483/// Does not check for overflow.
484#[inline(always)]
485fn up_align_usize_unchecked(addr: usize, align: usize) -> usize {
486    debug_assert!(align.is_power_of_two());
487    let mask = align - 1;
488    (addr + mask) & !mask
489}
490
491#[inline(always)]
492fn down_align_usize(addr: usize, align: usize) -> usize {
493    debug_assert!(align.is_power_of_two());
494    let mask = align - 1;
495    addr & !mask
496}
497
498#[inline(always)]
499fn bump_down(addr: NonZeroUsize, size: usize, align: usize) -> usize {
500    let subtracted = addr.get().saturating_sub(size);
501    down_align_usize(subtracted, align)
502}
503
504mod chunk_header;
505#[cfg(test)]
506mod tests;
507
508/// This is not part of the public api!
509///
510/// Any changes to this module are semver-exempt!
511#[doc(hidden)]
512pub mod private {
513    pub use core;
514    use core::ptr::NonNull;
515
516    use crate::BumpBox;
517
518    #[cfg(feature = "panic-on-alloc")]
519    /// Wrapper type, used for ad hoc overwriting of trait implementations, like for `Write` in `alloc_fmt`.
520    #[repr(transparent)]
521    pub struct PanicsOnAlloc<T: ?Sized>(pub T);
522
523    #[cfg(feature = "panic-on-alloc")]
524    impl<T: ?Sized> PanicsOnAlloc<T> {
525        pub(crate) fn from_mut(value: &mut T) -> &mut PanicsOnAlloc<T> {
526            unsafe { &mut *(core::ptr::from_mut::<T>(value) as *mut Self) }
527        }
528    }
529
530    #[cold]
531    #[inline(never)]
532    #[cfg(feature = "panic-on-alloc")]
533    pub const fn capacity_overflow() -> ! {
534        panic!("capacity overflow");
535    }
536
537    #[cold]
538    #[inline(never)]
539    #[cfg(feature = "panic-on-alloc")]
540    pub const fn format_trait_error() -> ! {
541        panic!("formatting trait implementation returned an error");
542    }
543
544    #[must_use]
545    #[allow(clippy::needless_lifetimes, clippy::elidable_lifetime_names)]
546    pub fn bump_box_into_raw_with_lifetime<'a, T: ?Sized>(boxed: BumpBox<'a, T>) -> (NonNull<T>, &'a ()) {
547        (boxed.into_raw(), &())
548    }
549
550    #[must_use]
551    #[allow(clippy::needless_lifetimes, clippy::elidable_lifetime_names)]
552    pub unsafe fn bump_box_from_raw_with_lifetime<'a, T: ?Sized>(ptr: NonNull<T>, _lifetime: &'a ()) -> BumpBox<'a, T> {
553        unsafe { BumpBox::from_raw(ptr) }
554    }
555}
556
557#[cfg(all(feature = "alloc", feature = "panic-on-alloc"))]
558use alloc_crate::alloc::handle_alloc_error;
559
560#[cold]
561#[inline(never)]
562#[cfg(all(not(feature = "alloc"), feature = "panic-on-alloc"))]
563fn handle_alloc_error(_layout: Layout) -> ! {
564    panic!("allocation failed")
565}
566
567// This is just `Result::into_ok` but with a name to match our use case.
568#[inline(always)]
569#[cfg(feature = "panic-on-alloc")]
570fn panic_on_error<T>(result: Result<T, Infallible>) -> T {
571    match result {
572        Ok(value) => value,
573    }
574}
575
576trait SizedTypeProperties: Sized {
577    const SIZE: usize = mem::size_of::<Self>();
578    const ALIGN: usize = mem::align_of::<Self>();
579
580    const IS_ZST: bool = mem::size_of::<Self>() == 0;
581}
582
583impl<T> SizedTypeProperties for T {}
584
585macro_rules! const_param_assert {
586    (
587        ($(const $param_ident:ident: $param_ty:ident),+) => $($assert_args:tt)*
588    ) => {{
589            struct ConstParamAssert<$(const $param_ident: $param_ty),+> {}
590            impl<$(const $param_ident: $param_ty),+> ConstParamAssert<$($param_ident),+> {
591                const CONST_PARAM_ASSERT: () = assert!($($assert_args)*);
592            }
593            #[allow(unused_variables)]
594            let assertion = ConstParamAssert::<$($param_ident),+>::CONST_PARAM_ASSERT;
595    }};
596}
597
598pub(crate) use const_param_assert;
599
600mod supported_base_allocator {
601    pub trait Sealed<const GUARANTEED_ALLOCATED: bool> {
602        #[doc(hidden)]
603        fn default_or_panic() -> Self;
604    }
605
606    impl<A> Sealed<false> for A
607    where
608        A: Default,
609    {
610        fn default_or_panic() -> Self {
611            A::default()
612        }
613    }
614
615    impl<A> Sealed<true> for A {
616        fn default_or_panic() -> Self {
617            unreachable!("default should not be required for `GUARANTEED_ALLOCATED` bump allocators");
618        }
619    }
620}
621
622/// Trait that the base allocator of a `Bump` is required to implement to make allocations.
623///
624/// Every [`Allocator`] that implements [`Clone`] automatically implements `BaseAllocator` when `GUARANTEED_ALLOCATED`.
625/// When not guaranteed allocated, allocators are additionally required to implement [`Default`].
626///
627/// This trait is *sealed*: the list of implementors below is total.
628pub trait BaseAllocator<const GUARANTEED_ALLOCATED: bool = true>:
629    Allocator + Clone + supported_base_allocator::Sealed<GUARANTEED_ALLOCATED>
630{
631}
632
633impl<A> BaseAllocator<false> for A where A: Allocator + Clone + Default {}
634
635impl<A> BaseAllocator<true> for A where A: Allocator + Clone {}
636
637/// Call this with a macro that accepts tokens of either `A` or `A = $crate::alloc::Global`.
638///
639/// We do it this way instead of having a parameter like
640/// ```ignore
641/// #[cfg(feature = "alloc")] A = $crate::alloc::Global,
642/// #[cfg(not(feature = "alloc"))] A,
643/// ```
644/// because Rust Analyzer thinks those are two parameters and gets confused.
645macro_rules! maybe_default_allocator {
646    ($macro:ident) => {
647        #[cfg(feature = "alloc")]
648        $macro!(A = $crate::alloc::Global);
649
650        #[cfg(not(feature = "alloc"))]
651        $macro!(A);
652    };
653}
654
655pub(crate) use maybe_default_allocator;
656
657// (copied from rust standard library)
658//
659// Tiny Vecs are dumb. Skip to:
660// - 8 if the element size is 1, because any heap allocators is likely
661//   to round up a request of less than 8 bytes to at least 8 bytes.
662// - 4 if elements are moderate-sized (<= 1 KiB).
663// - 1 otherwise, to avoid wasting too much space for very short Vecs.
664const fn min_non_zero_cap(size: usize) -> usize {
665    if size == 1 {
666        8
667    } else if size <= 1024 {
668        4
669    } else {
670        1
671    }
672}
673
674/// Aligns a bump address to the `MIN_ALIGN`.
675///
676/// This is a noop when `MIN_ALIGN` is `0`.
677#[must_use]
678#[inline(always)]
679fn align_pos<const MIN_ALIGN: usize, const UP: bool>(pos: NonZeroUsize) -> usize
680where
681    MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
682{
683    if UP {
684        // Aligning an address that is `<= range.end` with an alignment
685        // that is `<= MIN_CHUNK_ALIGN` cannot exceed `range.end` and
686        // cannot overflow as `range.end` is always aligned to `MIN_CHUNK_ALIGN`.
687        up_align_usize_unchecked(pos.get(), MIN_ALIGN)
688    } else {
689        // The chunk start is non-null and is aligned to `MIN_CHUNK_ALIGN`
690        // `MIN_ALIGN <= MIN_CHUNK_ALIGN` will never pass the chunk start
691        // and stay non-zero.
692        down_align_usize(pos.get(), MIN_ALIGN)
693    }
694}