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()` and `.scope_guard()`.
181//!
182//! A `bump.claim()` call replaces the allocator referred to by `bump` 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/// [`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/// [`BumpString`] and associated types.
326mod bump_string;
327/// [`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/// [`MutBumpVec`] and associated types.
341pub mod mut_bump_vec;
342/// [`MutBumpVecRev`] and associated types.
343mod mut_bump_vec_rev;
344mod no_drop;
345/// Types and traits associated with owned slices.
346pub mod owned_slice;
347/// 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/// Changelog.
390///
391#[doc = include_str!("../CHANGELOG.md")]
392#[expect(non_snake_case)]
393pub mod CHANGELOG {}
394
395#[cfg(feature = "bytemuck")]
396features::bytemuck_or_zerocopy! {
397 crate "bytemuck"
398 mod bytemuck
399 trait Zeroable
400}
401
402#[cfg(feature = "zerocopy-08")]
403features::bytemuck_or_zerocopy! {
404 crate "zerocopy"
405 mod zerocopy_08
406 trait FromZeros
407}
408
409/// Does not check for overflow.
410#[inline(always)]
411fn up_align_usize_unchecked(addr: usize, align: usize) -> usize {
412 debug_assert!(align.is_power_of_two());
413 let mask = align - 1;
414 (addr + mask) & !mask
415}
416
417#[inline(always)]
418fn down_align_usize(addr: usize, align: usize) -> usize {
419 debug_assert!(align.is_power_of_two());
420 let mask = align - 1;
421 addr & !mask
422}
423
424#[inline(always)]
425fn bump_down(addr: NonZeroUsize, size: usize, align: usize) -> usize {
426 let subtracted = addr.get().saturating_sub(size);
427 down_align_usize(subtracted, align)
428}
429
430#[cfg(test)]
431mod tests;
432
433/// This is not part of the public api!
434///
435/// Any changes to this module are semver-exempt!
436#[doc(hidden)]
437pub mod private {
438 pub use core;
439 use core::ptr::NonNull;
440
441 use crate::BumpBox;
442
443 #[cfg(feature = "panic-on-alloc")]
444 /// Wrapper type, used for ad hoc overwriting of trait implementations, like for `Write` in `alloc_fmt`.
445 #[repr(transparent)]
446 pub struct PanicsOnAlloc<T: ?Sized>(pub T);
447
448 #[cfg(feature = "panic-on-alloc")]
449 impl<T: ?Sized> PanicsOnAlloc<T> {
450 pub(crate) fn from_mut(value: &mut T) -> &mut PanicsOnAlloc<T> {
451 unsafe { &mut *(core::ptr::from_mut::<T>(value) as *mut Self) }
452 }
453 }
454
455 #[cold]
456 #[inline(never)]
457 #[cfg(feature = "panic-on-alloc")]
458 pub const fn capacity_overflow() -> ! {
459 panic!("capacity overflow");
460 }
461
462 #[cold]
463 #[inline(never)]
464 #[cfg(feature = "panic-on-alloc")]
465 pub const fn format_trait_error() -> ! {
466 panic!("formatting trait implementation returned an error");
467 }
468
469 #[must_use]
470 #[expect(clippy::elidable_lifetime_names)]
471 pub fn bump_box_into_raw_with_lifetime<'a, T: ?Sized>(boxed: BumpBox<'a, T>) -> (NonNull<T>, &'a ()) {
472 (boxed.into_raw(), &())
473 }
474
475 #[must_use]
476 #[expect(clippy::elidable_lifetime_names)]
477 pub unsafe fn bump_box_from_raw_with_lifetime<'a, T: ?Sized>(ptr: NonNull<T>, _lifetime: &'a ()) -> BumpBox<'a, T> {
478 unsafe { BumpBox::from_raw(ptr) }
479 }
480}
481
482#[cfg(all(feature = "alloc", feature = "panic-on-alloc"))]
483use alloc_crate::alloc::handle_alloc_error;
484
485#[cold]
486#[inline(never)]
487#[cfg(all(not(feature = "alloc"), feature = "panic-on-alloc"))]
488fn handle_alloc_error(_layout: Layout) -> ! {
489 panic!("allocation failed")
490}
491
492// This is just `Result::into_ok` but with a name to match our use case.
493#[inline(always)]
494#[cfg(feature = "panic-on-alloc")]
495fn panic_on_error<T>(result: Result<T, Infallible>) -> T {
496 match result {
497 Ok(value) => value,
498 }
499}
500
501trait SizedTypeProperties: Sized {
502 const SIZE: usize = mem::size_of::<Self>();
503 const ALIGN: usize = mem::align_of::<Self>();
504
505 const IS_ZST: bool = mem::size_of::<Self>() == 0;
506}
507
508impl<T> SizedTypeProperties for T {}
509
510/// Call this with a macro that accepts tokens of either `A` or `A = $crate::alloc::Global`.
511///
512/// We do it this way instead of having a parameter like
513/// ```ignore
514/// #[cfg(feature = "alloc")] A = $crate::alloc::Global,
515/// #[cfg(not(feature = "alloc"))] A,
516/// ```
517/// because Rust Analyzer thinks those are two parameters and gets confused.
518macro_rules! maybe_default_allocator {
519 ($macro:ident) => {
520 #[cfg(feature = "alloc")]
521 $macro!(A = $crate::alloc::Global);
522
523 #[cfg(not(feature = "alloc"))]
524 $macro!(A);
525 };
526}
527
528pub(crate) use maybe_default_allocator;
529
530use crate::{
531 alloc::Allocator,
532 settings::{Boolean, False, True},
533};
534
535// (copied from rust standard library)
536//
537// Tiny Vecs are dumb. Skip to:
538// - 8 if the element size is 1, because any heap allocators is likely
539// to round up a request of less than 8 bytes to at least 8 bytes.
540// - 4 if elements are moderate-sized (<= 1 KiB).
541// - 1 otherwise, to avoid wasting too much space for very short Vecs.
542const fn min_non_zero_cap(size: usize) -> usize {
543 if size == 1 {
544 8
545 } else if size <= 1024 {
546 4
547 } else {
548 1
549 }
550}
551
552/// Aligns a bump address to the `min_align`.
553///
554/// This is a noop when `min_align` is `0`.
555#[must_use]
556#[inline(always)]
557fn align_pos(up: bool, min_align: usize, pos: usize) -> usize {
558 if up {
559 // Aligning an address that is `<= range.end` with an alignment
560 // that is `<= MIN_CHUNK_ALIGN` cannot exceed `range.end` and
561 // cannot overflow as `range.end` is always aligned to `MIN_CHUNK_ALIGN`.
562 up_align_usize_unchecked(pos, min_align)
563 } else {
564 // The chunk start is non-null and is aligned to `MIN_CHUNK_ALIGN`
565 // `MIN_ALIGN <= MIN_CHUNK_ALIGN` will never pass the chunk start
566 // and stay non-zero.
567 down_align_usize(pos, min_align)
568 }
569}
570
571mod supported_base_allocator {
572 use crate::settings::{Boolean, False, True};
573
574 pub trait Sealed<GuaranteedAllocated: Boolean> {
575 #[doc(hidden)]
576 fn default_or_panic() -> Self;
577 }
578
579 impl<A> Sealed<False> for A
580 where
581 A: Default,
582 {
583 fn default_or_panic() -> Self {
584 A::default()
585 }
586 }
587
588 impl<A> Sealed<True> for A {
589 fn default_or_panic() -> Self {
590 unreachable!("default should not be required for `GUARANTEED_ALLOCATED` bump allocators");
591 }
592 }
593}
594
595/// Trait that the base allocator of a `Bump` is required to implement to make allocations.
596///
597/// Every [`Allocator`] that implements [`Clone`] automatically implements `BaseAllocator` when `GuaranteedAllocated`.
598/// When not guaranteed allocated, allocators are additionally required to implement [`Default`].
599///
600/// This trait is *sealed*: the list of implementors below is total.
601pub trait BaseAllocator<GuaranteedAllocated: Boolean>:
602 Allocator + Clone + supported_base_allocator::Sealed<GuaranteedAllocated>
603{
604}
605
606impl<A> BaseAllocator<False> for A where A: Allocator + Clone + Default {}
607
608impl<A> BaseAllocator<True> for A where A: Allocator + Clone {}