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