Skip to main content

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::items_after_statements,
39    clippy::missing_transmute_annotations,
40    clippy::multiple_crate_versions, // we have allocator-api2 version 0.2 and 0.3
41)]
42#![allow(
43    clippy::wildcard_imports, // `expect` is broken for this lint
44    clippy::collapsible_else_if, // this is not `expect` because nightly as of 2025-12-28 doesn't warn about this for some reason
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 `examples/limit_memory_usage.rs`).
98//! - Allocations are a tiny bit more optimized. See [./crates/callgrind-benches][benches].
99//! - [You can choose the bump direction.](crate::settings#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//! When using a `Bump(Scope)` as an allocator for collections you will find that you can no longer
176//! call `scoped` or `scope_guard` because those functions require `&mut self` which does not allow
177//! any outstanding references to the allocator.
178//!
179//! As a workaround you can use the [`claim`] method on a `&Bump(Scope)` to return a `BumpClaimGuard` which
180//! mutably dereferences to a `BumpScope`, allowing you to call `.scoped()` / `.scope_guard()`.
181//!
182//! A `bump.claim()` call replaces the `bump` allocator with a dummy allocator while the returned `BumpClaimGuard`
183//! is live. This dummy allocator errors on `allocate` / `grow`, does nothing on `deallocate` / `shrink` and
184//! reports an empty bump allocator from the `stats` api.
185//!
186//! This makes it possible to enter scopes while a there are still outstanding
187//! references to that bump allocator:
188//! ```
189//! # use bump_scope::{ Bump, BumpScope, BumpVec as Vec };
190//! let bump: Bump = Bump::new();
191//! let mut vec: Vec<u8, &Bump> = Vec::new_in(&bump);
192//!
193//! bump.claim().scoped(|bump_scope| {
194//!     // you can allocate in the scope as usual
195//!     let mut vec2: Vec<u8, &BumpScope> = Vec::new_in(bump_scope);
196//!     vec2.reserve(456);
197//!
198//!     // allocating on the `bump` outside the scope will fail
199//!     assert!(vec.try_reserve(123).is_err());
200//! });
201//!
202//! // now allocating on `bump` is possible again
203//! vec.reserve(123);
204//! ```
205//!
206//! # Collections
207//! `bump-scope` provides bump allocated versions of `Vec` and `String` called [`BumpVec`] and [`BumpString`].
208//! They are also available in the following variants:
209//! - [`Fixed*`](FixedBumpVec) for fixed capacity collections
210//! - [`Mut*`](MutBumpVec) for collections optimized for a mutable bump allocator
211//!
212//! #### API changes
213//! The collections are designed to have the same api as their std counterparts with these exceptions:
214//! - [`split_off`](BumpVec::split_off) —  splits the collection in place without allocation; the parameter is a range instead of a single index
215//! - [`retain`](BumpVec::retain) —  takes a closure with a `&mut T` parameter like [`Vec::retain_mut`](alloc_crate::vec::Vec::retain_mut)
216//!
217//! #### New features
218//! - [`append`](BumpVec::append) —  allows appending all kinds of owned slice types like `[T; N]`, `Box<[T]>`, `Vec<T>`, `vec::Drain<T>` etc.
219//! - [`map`](BumpVec::map) —  maps the elements, potentially reusing the existing allocation
220//! - [`map_in_place`](BumpVec::map_in_place) —  maps the elements without allocation, failing to compile if not possible
221//! - conversions between the regular collections, their `Fixed*` variants and `BumpBox<[T]>` / `BumpBox<str>`
222//!
223//! # Parallel Allocation
224//! [`Bump`] is `!Sync` which means it can't be shared between threads.
225//!
226//! To bump allocate in parallel you can use a [`BumpPool`].
227//!
228//! # Allocator API
229//! `Bump` and `BumpScope` implement `bump-scope`'s own [`Allocator`] trait and with the
230//! respective [feature flags](#feature-flags) also implement `allocator_api2` version `0.2`,
231//! `0.3`, `0.4` and nightly's `Allocator` trait.
232//!
233//! This allows you to [bump allocate collections](crate::Bump#collections).
234//!
235//! A bump allocator can grow, shrink and deallocate the most recent allocation.
236//! When bumping upwards it can even do so in place.
237//! Growing allocations other than the most recent one will require a new allocation and the old memory block becomes wasted space.
238//! Shrinking or deallocating allocations other than the most recent one does nothing, which means wasted space.
239//!
240//! A bump allocator does not require `deallocate` or `shrink` to free memory.
241//! After all, memory will be reclaimed when exiting a scope, calling `reset` or dropping the `Bump`.
242//! You can set [the `DEALLOCATES` and `SHRINKS` parameters](crate::settings) to false or use the [`WithoutDealloc`] and [`WithoutShrink`] wrappers
243//! to make deallocating and shrinking a no-op.
244//!
245//! # Feature Flags
246//! <!-- feature documentation start -->
247//! - **`std`** *(enabled by default)* — Adds `BumpPool` and implementations of `std::io` traits.
248//! - **`alloc`** *(enabled by default)* — Adds `Global` as the default base allocator and some interactions with `alloc` collections.
249//! - **`panic-on-alloc`** *(enabled by default)* — Adds functions and traits that will panic when allocations fail.
250//!   Without this feature, allocation failures cannot cause panics, and only
251//!   `try_`-prefixed allocation methods will be available.
252//! - **`serde`** — Adds `Serialize` implementations for `BumpBox`, strings and vectors, and `DeserializeSeed` for strings and vectors.
253//! - **`bytemuck`** — Adds `bytemuck::*` extension traits for
254//!   <code>[alloc_zeroed](bytemuck::BumpAllocatorTypedScopeExt::alloc_zeroed)([_slice](bytemuck::BumpAllocatorTypedScopeExt::alloc_zeroed_slice))</code>,
255//!   [`init_zeroed`](bytemuck::InitZeroed::init_zeroed),
256//!   [`extend_zeroed`](bytemuck::VecExt::extend_zeroed) and
257//!   [`resize_zeroed`](bytemuck::VecExt::resize_zeroed).
258//! - **`zerocopy-08`** — Adds `zerocopy_08::*` extension traits for
259//!   <code>[alloc_zeroed](zerocopy_08::BumpAllocatorTypedScopeExt::alloc_zeroed)([_slice](zerocopy_08::BumpAllocatorTypedScopeExt::alloc_zeroed_slice))</code>,
260//!   [`init_zeroed`](zerocopy_08::InitZeroed::init_zeroed),
261//!   [`extend_zeroed`](zerocopy_08::VecExt::extend_zeroed) and
262//!   [`resize_zeroed`](zerocopy_08::VecExt::resize_zeroed).
263//! - **`allocator-api2-02`** — Makes `Bump(Scope)` implement `allocator_api2` version `0.2`'s `Allocator` and
264//!   makes it possible to use an `allocator_api2::alloc::Allocator` as a base allocator via
265//!   [`AllocatorApi2V02Compat`](crate::alloc::compat::AllocatorApi2V02Compat).
266//! - **`allocator-api2-03`** — Makes `Bump(Scope)` implement `allocator_api2` version `0.3`'s `Allocator` and
267//!   makes it possible to use an `allocator_api2::alloc::Allocator` as a base allocator via
268//!   [`AllocatorApi2V03Compat`](crate::alloc::compat::AllocatorApi2V03Compat).
269//! - **`allocator-api2-04`** — Makes `Bump(Scope)` implement `allocator_api2` version `0.4`'s `Allocator` and
270//!   makes it possible to use an `allocator_api2::alloc::Allocator` as a base allocator via
271//!   [`AllocatorApi2V04Compat`](crate::alloc::compat::AllocatorApi2V04Compat).
272//!
273//! ### Nightly features
274//! These nightly features are not subject to the same semver guarantees as the rest of the library.
275//! Breaking changes to these features might be introduced in minor releases to keep up with changes in the nightly channel.
276//!
277//! - **`nightly`** — Enables all other nightly feature flags.
278//! - **`nightly-allocator-api`** — Makes `Bump(Scope)` implement `alloc`'s `Allocator` and
279//!   allows using an `core::alloc::Allocator` as a base allocator via
280//!   [`AllocatorNightlyCompat`](crate::alloc::compat::AllocatorNightlyCompat).
281//!
282//!   This will also enable `allocator-api2` version `0.2`'s `nightly` feature.
283//! - **`nightly-coerce-unsized`** — Makes `BumpBox<T>` implement [`CoerceUnsized`](core::ops::CoerceUnsized).
284//!   With this `BumpBox<[i32;3]>` coerces to `BumpBox<[i32]>`, `BumpBox<dyn Debug>` and so on.
285//!   You can unsize a `BumpBox` in stable without this feature using [`unsize_bump_box`].
286//! - **`nightly-exact-size-is-empty`** — Implements `is_empty` manually for some iterators.
287//! - **`nightly-trusted-len`** — Implements `TrustedLen` for some iterators.
288//! - **`nightly-fn-traits`** — Implements `Fn*` traits for `BumpBox<T>`. Makes `BumpBox<T: FnOnce + ?Sized>` callable. Requires alloc crate.
289//! - **`nightly-tests`** — Enables some tests that require a nightly compiler.
290//! - **`nightly-dropck-eyepatch`** — Adds `#[may_dangle]` attribute to box and vector types' drop implementation.
291//!   This makes it so references don't have to strictly outlive the container.
292//!   (Just like with std's `Box` and `Vec`.)
293//! - **`nightly-clone-to-uninit`** — Adds [`alloc_clone`](crate::traits::BumpAllocatorTypedScope::alloc_clone) method.
294//! <!-- feature documentation end -->
295//!
296//! [benches]: https://github.com/bluurryy/bump-scope/tree/main/crates/callgrind-benches
297//! [`new`]: Bump::new
298//! [`Allocator`]: crate::alloc::Allocator
299//! [`with_size`]: Bump::with_size
300//! [`with_capacity`]: Bump::with_capacity
301//! [`scoped`]: crate::traits::BumpAllocator::scoped
302//! [`scoped_aligned`]: crate::traits::BumpAllocator::scoped_aligned
303//! [`aligned`]: crate::traits::BumpAllocatorScope::aligned
304//! [`scope_guard`]: crate::traits::BumpAllocator::scope_guard
305//! [`claim`]: crate::traits::BumpAllocatorScope::claim
306//! <!-- crate documentation rest end -->
307
308#[cfg(any(feature = "std", test))]
309extern crate std;
310
311#[cfg(any(feature = "alloc", feature = "nightly-fn-traits"))]
312extern crate alloc as alloc_crate;
313
314pub mod alloc;
315mod allocator_impl;
316mod bump;
317mod bump_align_guard;
318/// Contains [`BumpBox`] and associated types.
319mod bump_box;
320mod bump_claim_guard;
321#[cfg(feature = "std")]
322mod bump_pool;
323mod bump_scope;
324mod bump_scope_guard;
325/// Contains [`BumpString`] and associated types.
326mod bump_string;
327/// Contains [`BumpVec`] and associated types.
328pub mod bump_vec;
329mod bumping;
330mod chunk;
331mod destructure;
332mod error_behavior;
333mod features;
334mod fixed_bump_string;
335mod fixed_bump_vec;
336mod from_utf16_error;
337mod from_utf8_error;
338mod layout;
339mod mut_bump_string;
340/// Contains [`MutBumpVec`] and associated types.
341pub mod mut_bump_vec;
342/// Contains [`MutBumpVecRev`] and associated types.
343mod mut_bump_vec_rev;
344mod no_drop;
345/// Contains types associated with owned slices.
346pub mod owned_slice;
347/// Contains types associated with owned strings.
348pub mod owned_str;
349mod partial_eq;
350mod polyfill;
351mod raw_bump;
352mod set_len_on_drop;
353mod set_len_on_drop_by_ptr;
354pub mod settings;
355pub mod stats;
356/// Traits that provide ways to be generic over `Bump(Scope)`s.
357pub mod traits;
358mod without_dealloc;
359
360pub use bump::Bump;
361pub use bump_box::BumpBox;
362pub use bump_claim_guard::BumpClaimGuard;
363#[cfg(feature = "std")]
364pub use bump_pool::{BumpPool, BumpPoolGuard};
365pub use bump_scope::BumpScope;
366pub use bump_scope_guard::{BumpScopeGuard, Checkpoint};
367pub use bump_string::BumpString;
368#[doc(inline)]
369pub use bump_vec::BumpVec;
370#[cfg(feature = "panic-on-alloc")]
371use core::convert::Infallible;
372use core::{mem, num::NonZeroUsize, ptr::NonNull};
373use error_behavior::ErrorBehavior;
374pub use fixed_bump_string::FixedBumpString;
375pub use fixed_bump_vec::FixedBumpVec;
376pub use from_utf8_error::FromUtf8Error;
377pub use from_utf16_error::FromUtf16Error;
378use layout::ArrayLayout;
379pub use mut_bump_string::MutBumpString;
380#[doc(inline)]
381pub use mut_bump_vec::MutBumpVec;
382pub use mut_bump_vec_rev::MutBumpVecRev;
383pub use no_drop::NoDrop;
384#[cfg(feature = "panic-on-alloc")]
385use private::{PanicsOnAlloc, capacity_overflow, format_trait_error};
386use set_len_on_drop::SetLenOnDrop;
387pub use without_dealloc::{WithoutDealloc, WithoutShrink};
388
389#[doc = include_str!("../CHANGELOG.md")]
390#[expect(non_snake_case)]
391pub mod CHANGELOG {}
392
393#[cfg(feature = "bytemuck")]
394features::bytemuck_or_zerocopy! {
395    mod bytemuck
396    trait Zeroable
397}
398
399#[cfg(feature = "zerocopy-08")]
400features::bytemuck_or_zerocopy! {
401    mod zerocopy_08
402    trait FromZeros
403}
404
405/// Does not check for overflow.
406#[inline(always)]
407fn up_align_usize_unchecked(addr: usize, align: usize) -> usize {
408    debug_assert!(align.is_power_of_two());
409    let mask = align - 1;
410    (addr + mask) & !mask
411}
412
413#[inline(always)]
414fn down_align_usize(addr: usize, align: usize) -> usize {
415    debug_assert!(align.is_power_of_two());
416    let mask = align - 1;
417    addr & !mask
418}
419
420#[inline(always)]
421fn bump_down(addr: NonZeroUsize, size: usize, align: usize) -> usize {
422    let subtracted = addr.get().saturating_sub(size);
423    down_align_usize(subtracted, align)
424}
425
426#[cfg(test)]
427mod tests;
428
429/// This is not part of the public api!
430///
431/// Any changes to this module are semver-exempt!
432#[doc(hidden)]
433pub mod private {
434    pub use core;
435    use core::ptr::NonNull;
436
437    use crate::BumpBox;
438
439    #[cfg(feature = "panic-on-alloc")]
440    /// Wrapper type, used for ad hoc overwriting of trait implementations, like for `Write` in `alloc_fmt`.
441    #[repr(transparent)]
442    pub struct PanicsOnAlloc<T: ?Sized>(pub T);
443
444    #[cfg(feature = "panic-on-alloc")]
445    impl<T: ?Sized> PanicsOnAlloc<T> {
446        pub(crate) fn from_mut(value: &mut T) -> &mut PanicsOnAlloc<T> {
447            unsafe { &mut *(core::ptr::from_mut::<T>(value) as *mut Self) }
448        }
449    }
450
451    #[cold]
452    #[inline(never)]
453    #[cfg(feature = "panic-on-alloc")]
454    pub const fn capacity_overflow() -> ! {
455        panic!("capacity overflow");
456    }
457
458    #[cold]
459    #[inline(never)]
460    #[cfg(feature = "panic-on-alloc")]
461    pub const fn format_trait_error() -> ! {
462        panic!("formatting trait implementation returned an error");
463    }
464
465    #[must_use]
466    #[expect(clippy::elidable_lifetime_names)]
467    pub fn bump_box_into_raw_with_lifetime<'a, T: ?Sized>(boxed: BumpBox<'a, T>) -> (NonNull<T>, &'a ()) {
468        (boxed.into_raw(), &())
469    }
470
471    #[must_use]
472    #[expect(clippy::elidable_lifetime_names)]
473    pub unsafe fn bump_box_from_raw_with_lifetime<'a, T: ?Sized>(ptr: NonNull<T>, _lifetime: &'a ()) -> BumpBox<'a, T> {
474        unsafe { BumpBox::from_raw(ptr) }
475    }
476}
477
478#[cfg(all(feature = "alloc", feature = "panic-on-alloc"))]
479use alloc_crate::alloc::handle_alloc_error;
480
481#[cold]
482#[inline(never)]
483#[cfg(all(not(feature = "alloc"), feature = "panic-on-alloc"))]
484fn handle_alloc_error(_layout: Layout) -> ! {
485    panic!("allocation failed")
486}
487
488// This is just `Result::into_ok` but with a name to match our use case.
489#[inline(always)]
490#[cfg(feature = "panic-on-alloc")]
491fn panic_on_error<T>(result: Result<T, Infallible>) -> T {
492    match result {
493        Ok(value) => value,
494    }
495}
496
497trait SizedTypeProperties: Sized {
498    const SIZE: usize = mem::size_of::<Self>();
499    const ALIGN: usize = mem::align_of::<Self>();
500
501    const IS_ZST: bool = mem::size_of::<Self>() == 0;
502}
503
504impl<T> SizedTypeProperties for T {}
505
506/// Call this with a macro that accepts tokens of either `A` or `A = $crate::alloc::Global`.
507///
508/// We do it this way instead of having a parameter like
509/// ```ignore
510/// #[cfg(feature = "alloc")] A = $crate::alloc::Global,
511/// #[cfg(not(feature = "alloc"))] A,
512/// ```
513/// because Rust Analyzer thinks those are two parameters and gets confused.
514macro_rules! maybe_default_allocator {
515    ($macro:ident) => {
516        #[cfg(feature = "alloc")]
517        $macro!(A = $crate::alloc::Global);
518
519        #[cfg(not(feature = "alloc"))]
520        $macro!(A);
521    };
522}
523
524pub(crate) use maybe_default_allocator;
525
526use crate::{
527    alloc::Allocator,
528    settings::{Boolean, False, True},
529};
530
531// (copied from rust standard library)
532//
533// Tiny Vecs are dumb. Skip to:
534// - 8 if the element size is 1, because any heap allocators is likely
535//   to round up a request of less than 8 bytes to at least 8 bytes.
536// - 4 if elements are moderate-sized (<= 1 KiB).
537// - 1 otherwise, to avoid wasting too much space for very short Vecs.
538const fn min_non_zero_cap(size: usize) -> usize {
539    if size == 1 {
540        8
541    } else if size <= 1024 {
542        4
543    } else {
544        1
545    }
546}
547
548/// Aligns a bump address to the `min_align`.
549///
550/// This is a noop when `min_align` is `0`.
551#[must_use]
552#[inline(always)]
553fn align_pos(up: bool, min_align: usize, pos: usize) -> usize {
554    if up {
555        // Aligning an address that is `<= range.end` with an alignment
556        // that is `<= MIN_CHUNK_ALIGN` cannot exceed `range.end` and
557        // cannot overflow as `range.end` is always aligned to `MIN_CHUNK_ALIGN`.
558        up_align_usize_unchecked(pos, min_align)
559    } else {
560        // The chunk start is non-null and is aligned to `MIN_CHUNK_ALIGN`
561        // `MIN_ALIGN <= MIN_CHUNK_ALIGN` will never pass the chunk start
562        // and stay non-zero.
563        down_align_usize(pos, min_align)
564    }
565}
566
567mod supported_base_allocator {
568    use crate::settings::{Boolean, False, True};
569
570    pub trait Sealed<GuaranteedAllocated: Boolean> {
571        #[doc(hidden)]
572        fn default_or_panic() -> Self;
573    }
574
575    impl<A> Sealed<False> for A
576    where
577        A: Default,
578    {
579        fn default_or_panic() -> Self {
580            A::default()
581        }
582    }
583
584    impl<A> Sealed<True> for A {
585        fn default_or_panic() -> Self {
586            unreachable!("default should not be required for `GUARANTEED_ALLOCATED` bump allocators");
587        }
588    }
589}
590
591/// Trait that the base allocator of a `Bump` is required to implement to make allocations.
592///
593/// Every [`Allocator`] that implements [`Clone`] automatically implements `BaseAllocator` when `GuaranteedAllocated`.
594/// When not guaranteed allocated, allocators are additionally required to implement [`Default`].
595///
596/// This trait is *sealed*: the list of implementors below is total.
597pub trait BaseAllocator<GuaranteedAllocated: Boolean>:
598    Allocator + Clone + supported_base_allocator::Sealed<GuaranteedAllocated>
599{
600}
601
602impl<A> BaseAllocator<False> for A where A: Allocator + Clone + Default {}
603
604impl<A> BaseAllocator<True> for A where A: Allocator + Clone {}