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