Skip to main content

bump_scope/
settings.rs

1//! Types to configure bump allocation.
2//!
3//! You can configure various settings of the bump allocator:
4//! - **`MIN_ALIGN`** *default: 1* —
5//!   The alignment the bump pointer maintains when doing allocations.
6//!
7//!   When allocating a type in a bump allocator with a sufficient minimum alignment,
8//!   the bump pointer will not have to be aligned for the allocation but the allocation size
9//!   will need to be rounded up to the next multiple of the minimum alignment.
10//!
11//!   For the performance impact see [crates/callgrind-benches][benches].
12//! - **`UP`** *default: true* —
13//!   Controls the bump direction.
14//!
15//!   Bumping upwards has the advantage that the most recent allocation can be grown and shrunk in place.
16//!   This benefits collections as well as <code>[alloc_iter][]([_mut][alloc_iter_mut])</code> and <code>[alloc_fmt][]([_mut][alloc_fmt_mut])</code>
17//!   with the exception of [`MutBumpVecRev`] and [`alloc_iter_mut_rev`] which
18//!   can be grown and shrunk in place if and only if bumping downwards.
19//!
20//!   Bumping downwards can be done in less instructions.
21//!
22//!   For the performance impact see [crates/callgrind-benches][benches].
23//! - **`GUARANTEED_ALLOCATED`** *default: true* —
24//!   Whether at least one chunk has been allocated.
25//!
26//!   The <code>[unallocated]</code> constructor will create a bump allocator without allocating a chunk.
27//!   It will only compile when `GUARANTEED_ALLOCATED` is `false`.
28//!
29//!   The constructors <code>[new]\([_in][new_in])</code>, <code>[default]</code>, <code>[with_size]\([_in][with_size_in])</code> and <code>[with_capacity]\([_in][with_capacity_in])</code>
30//!   will allocate a chunk and are always available.
31//!
32//!   Setting `GUARANTEED_ALLOCATED` to `false` adds additional checks and code paths for handling the no-chunk-allocated state when calling [`reset_to`], exiting scopes or calling [`by_value`].
33//! - **`CLAIMABLE`** *default: true* — Enables the [`claim`] api.
34//!
35//!   When this is `false`, calling `claim` will fail to compile.
36//! - **`DEALLOCATES`** *default: true* — Toggles deallocation.
37//!
38//!   When this is `false`, [`Allocator::deallocate`] does nothing.
39//! - **`SHRINKS`** *default: true* — Toggles shrinking.
40//!
41//!   When this is `false`, [`Allocator::shrink`] and [`BumpAllocatorTyped::shrink_slice`] do nothing.
42//!   Calling `shrink` with a new layout of a greater alignment may still reallocate.
43//!   
44//!   This also affects the temporary collections used in [`alloc_iter`][alloc_iter], [`alloc_fmt`][alloc_fmt], etc.
45//! - **`MINIMUM_CHUNK_SIZE`** *default: 512* — Configures the minimum chunk size.
46//!
47//!   The final chunk size is calculated like described in [`with_size`],
48//!   thus it can be slightly smaller than requested.
49//!
50//! # Example
51//!
52//! You can configure the allocator settings using [`BumpSettings`]:
53//! ```
54//! use bump_scope::{ Bump, alloc::Global, settings::BumpSettings };
55//!
56//! type MyBumpSettings = BumpSettings<
57//!     /* MIN_ALIGN */ 8,
58//!     /* UP */ false,
59//!     /* GUARANTEED_ALLOCATED */ false,
60//!     /* CLAIMABLE */ false,
61//!     /* DEALLOCATES */ false,
62//!     /* SHRINKS */ false,
63//!     /* MINIMUM_CHUNK_SIZE */ 4096,
64//! >;
65//!
66//! type MyBump = Bump<Global, MyBumpSettings>;
67//!
68//! let bump = MyBump::unallocated();
69//! assert_eq!(bump.stats().size(), 0);
70//!
71//! # let str =
72//! bump.alloc_str("Hello, world!");
73//! # assert_eq!(str, "Hello, world!");
74//! assert_eq!(bump.stats().size(), 4096 - size_of::<[usize; 2]>());
75//! ```
76//!
77//! [benches]: https://github.com/bluurryy/bump-scope/tree/main/crates/callgrind-benches
78//! [unallocated]: crate::Bump::unallocated
79//! [new]: crate::Bump::new
80//! [new_in]: crate::Bump::new_in
81//! [default]: crate::Bump::default
82//! [with_size]: crate::Bump::with_size
83//! [`with_size`]: crate::Bump::with_size
84//! [with_size_in]: crate::Bump::with_size_in
85//! [with_capacity]: crate::Bump::with_capacity
86//! [with_capacity_in]: crate::Bump::with_capacity_in
87//! [`scoped`]: crate::Bump::scoped
88//! [`scoped_aligned`]: crate::Bump::scoped_aligned
89//! [`aligned`]: crate::Bump::aligned
90//! [`scope_guard`]: crate::Bump::scope_guard
91//! [`BumpSettings`]: crate::settings::BumpSettings
92//! [`MutBumpVecRev`]: crate::MutBumpVecRev
93//! [`reset_to`]: crate::traits::BumpAllocatorCore::reset_to
94//! [`claim`]: crate::traits::BumpAllocatorScope::claim
95//! [alloc_iter]: crate::traits::BumpAllocatorTypedScope::alloc_iter
96//! [alloc_iter_mut]: crate::traits::MutBumpAllocatorTypedScope::alloc_iter_mut
97//! [alloc_fmt]: crate::traits::BumpAllocatorTypedScope::alloc_fmt
98//! [alloc_fmt_mut]: crate::traits::MutBumpAllocatorTypedScope::alloc_fmt_mut
99//! [`alloc_iter_mut_rev`]: crate::traits::MutBumpAllocatorTypedScope::alloc_iter_mut_rev
100//! [`Allocator::allocate`]: crate::alloc::Allocator::allocate
101//! [`Allocator::deallocate`]: crate::alloc::Allocator::deallocate
102//! [`Allocator::shrink`]: crate::alloc::Allocator::shrink
103//! [`BumpAllocatorTyped::shrink_slice`]: crate::traits::BumpAllocatorTyped::shrink_slice
104//! [`by_value`]: crate::BumpScope::by_value
105
106use crate::ArrayLayout;
107
108trait Sealed {}
109
110/// The trait powering bump allocator configuration.
111///
112/// Read the [module documentation] to learn about the settings.
113///
114/// The setting values are provided as associated constants.
115///
116/// Additionally they are provided as types so they can be used in equality bounds like this:
117/// ```ignore
118/// S: BumpAllocatorSettings<GuaranteedAllocated = True>
119/// ```
120/// Doing the same with associated constants is not (yet) possible:
121/// ```ignore,warn
122/// // won't compile on stable
123/// S: BumpAllocatorSettings<GUARANTEED_ALLOCATED = true>
124/// ```
125///
126/// In the future this trait could be simplified when the following features are stabilized:
127/// - [`generic_const_exprs`]
128/// - [`associated_const_equality`]
129///
130/// [`generic_const_exprs`]: https://github.com/rust-lang/rust/issues/76560
131/// [`associated_const_equality`]: https://github.com/rust-lang/rust/issues/92827
132/// [module documentation]: crate::settings
133#[expect(private_bounds)]
134pub trait BumpAllocatorSettings: Sealed {
135    /// The minimum alignment.
136    const MIN_ALIGN: usize = Self::MinimumAlignment::VALUE;
137
138    /// The bump direction.
139    const UP: bool = Self::Up::VALUE;
140
141    /// Whether the allocator is guaranteed to have a chunk allocated.
142    const GUARANTEED_ALLOCATED: bool = Self::GuaranteedAllocated::VALUE;
143
144    /// Whether the allocator can be [claimed].
145    ///
146    /// [claimed]: crate::traits::BumpAllocatorScope::claim
147    const CLAIMABLE: bool = Self::Claimable::VALUE;
148
149    /// Whether the allocator tries to free allocations.
150    const DEALLOCATES: bool = Self::Deallocates::VALUE;
151
152    /// Whether the allocator tries to shrink allocations.
153    const SHRINKS: bool = Self::Shrinks::VALUE;
154
155    /// The minimum size for bump allocation chunk.
156    const MINIMUM_CHUNK_SIZE: usize;
157
158    /// The minimum alignment.
159    type MinimumAlignment: SupportedMinimumAlignment;
160
161    /// The bump direction.
162    type Up: Boolean;
163
164    /// Whether the allocator is guaranteed to have a chunk allocated.
165    type GuaranteedAllocated: Boolean;
166
167    /// Whether the allocator can be [claimed].
168    ///
169    /// [claimed]: crate::traits::BumpAllocatorScope::claim
170    type Claimable: Boolean;
171
172    /// Whether the allocator tries to free allocations.
173    type Deallocates: Boolean;
174
175    /// Whether the allocator tries to shrink allocations.
176    type Shrinks: Boolean;
177
178    /// Changes the minimum alignment.
179    type WithMinimumAlignment<const NEW_MIN_ALIGN: usize>: BumpAllocatorSettings<
180            MinimumAlignment = MinimumAlignment<NEW_MIN_ALIGN>,
181            Up = Self::Up,
182            GuaranteedAllocated = Self::GuaranteedAllocated,
183            Claimable = Self::Claimable,
184            Deallocates = Self::Deallocates,
185            Shrinks = Self::Shrinks,
186        >
187    where
188        MinimumAlignment<NEW_MIN_ALIGN>: SupportedMinimumAlignment;
189
190    /// Changes the bump direction.
191    type WithUp<const VALUE: bool>: BumpAllocatorSettings<
192            MinimumAlignment = Self::MinimumAlignment,
193            Up = Bool<VALUE>,
194            GuaranteedAllocated = Self::GuaranteedAllocated,
195            Claimable = Self::Claimable,
196            Deallocates = Self::Deallocates,
197            Shrinks = Self::Shrinks,
198        >;
199
200    /// Changes whether the allocator is guaranteed to have a chunk allocated.
201    type WithGuaranteedAllocated<const VALUE: bool>: BumpAllocatorSettings<
202            MinimumAlignment = Self::MinimumAlignment,
203            Up = Self::Up,
204            GuaranteedAllocated = Bool<VALUE>,
205            Claimable = Self::Claimable,
206            Deallocates = Self::Deallocates,
207            Shrinks = Self::Shrinks,
208        >;
209
210    /// Changes whether the allocator can be [claimed].
211    ///
212    /// [claimed]: crate::traits::BumpAllocatorScope::claim
213    type WithClaimable<const VALUE: bool>: BumpAllocatorSettings<
214            MinimumAlignment = Self::MinimumAlignment,
215            Up = Self::Up,
216            GuaranteedAllocated = Self::GuaranteedAllocated,
217            Claimable = Bool<VALUE>,
218            Deallocates = Self::Deallocates,
219            Shrinks = Self::Shrinks,
220        >;
221
222    /// Changes whether the allocator tries to free allocations.
223    type WithDeallocates<const VALUE: bool>: BumpAllocatorSettings<
224            MinimumAlignment = Self::MinimumAlignment,
225            Up = Self::Up,
226            GuaranteedAllocated = Self::GuaranteedAllocated,
227            Claimable = Self::Claimable,
228            Deallocates = Bool<VALUE>,
229            Shrinks = Self::Shrinks,
230        >;
231
232    /// Changes whether the allocator tries to shrink allocations.
233    type WithShrinks<const VALUE: bool>: BumpAllocatorSettings<
234            MinimumAlignment = Self::MinimumAlignment,
235            Up = Self::Up,
236            GuaranteedAllocated = Self::GuaranteedAllocated,
237            Claimable = Self::Claimable,
238            Deallocates = Self::Deallocates,
239            Shrinks = Bool<VALUE>,
240        >;
241
242    /// Changes the minimum chunk size.
243    type WithMinimumChunkSize<const VALUE: usize>: BumpAllocatorSettings<
244            MinimumAlignment = Self::MinimumAlignment,
245            Up = Self::Up,
246            GuaranteedAllocated = Self::GuaranteedAllocated,
247            Claimable = Self::Claimable,
248            Deallocates = Self::Deallocates,
249            Shrinks = Self::Shrinks,
250        >;
251}
252
253/// Implementor of [`BumpAllocatorSettings`].
254///
255/// See the [module documentation](crate::settings) for how to use this type.
256pub struct BumpSettings<
257    const MIN_ALIGN: usize = 1,
258    const UP: bool = true,
259    const GUARANTEED_ALLOCATED: bool = true,
260    const CLAIMABLE: bool = true,
261    const DEALLOCATES: bool = true,
262    const SHRINKS: bool = true,
263    const MINIMUM_CHUNK_SIZE: usize = 512,
264>;
265
266impl<
267    const MIN_ALIGN: usize,
268    const UP: bool,
269    const GUARANTEED_ALLOCATED: bool,
270    const CLAIMABLE: bool,
271    const DEALLOCATES: bool,
272    const SHRINKS: bool,
273    const MINIMUM_CHUNK_SIZE: usize,
274> Sealed for BumpSettings<MIN_ALIGN, UP, GUARANTEED_ALLOCATED, CLAIMABLE, DEALLOCATES, SHRINKS, MINIMUM_CHUNK_SIZE>
275{
276}
277
278impl<
279    const MIN_ALIGN: usize,
280    const UP: bool,
281    const GUARANTEED_ALLOCATED: bool,
282    const CLAIMABLE: bool,
283    const DEALLOCATES: bool,
284    const SHRINKS: bool,
285    const MINIMUM_CHUNK_SIZE: usize,
286> BumpAllocatorSettings
287    for BumpSettings<MIN_ALIGN, UP, GUARANTEED_ALLOCATED, CLAIMABLE, DEALLOCATES, SHRINKS, MINIMUM_CHUNK_SIZE>
288where
289    MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
290{
291    const MINIMUM_CHUNK_SIZE: usize = MINIMUM_CHUNK_SIZE;
292
293    type MinimumAlignment = MinimumAlignment<MIN_ALIGN>;
294    type Up = Bool<UP>;
295    type GuaranteedAllocated = Bool<GUARANTEED_ALLOCATED>;
296    type Claimable = Bool<CLAIMABLE>;
297    type Deallocates = Bool<DEALLOCATES>;
298    type Shrinks = Bool<SHRINKS>;
299
300    type WithMinimumAlignment<const VALUE: usize>
301        = BumpSettings<VALUE, UP, GUARANTEED_ALLOCATED, CLAIMABLE, DEALLOCATES, SHRINKS, MINIMUM_CHUNK_SIZE>
302    where
303        MinimumAlignment<VALUE>: SupportedMinimumAlignment;
304    type WithUp<const VALUE: bool> =
305        BumpSettings<MIN_ALIGN, VALUE, GUARANTEED_ALLOCATED, CLAIMABLE, DEALLOCATES, SHRINKS, MINIMUM_CHUNK_SIZE>;
306    type WithGuaranteedAllocated<const VALUE: bool> =
307        BumpSettings<MIN_ALIGN, UP, VALUE, CLAIMABLE, DEALLOCATES, SHRINKS, MINIMUM_CHUNK_SIZE>;
308    type WithClaimable<const VALUE: bool> =
309        BumpSettings<MIN_ALIGN, UP, GUARANTEED_ALLOCATED, VALUE, DEALLOCATES, SHRINKS, MINIMUM_CHUNK_SIZE>;
310    type WithDeallocates<const VALUE: bool> =
311        BumpSettings<MIN_ALIGN, UP, GUARANTEED_ALLOCATED, CLAIMABLE, VALUE, SHRINKS, MINIMUM_CHUNK_SIZE>;
312    type WithShrinks<const VALUE: bool> =
313        BumpSettings<MIN_ALIGN, UP, GUARANTEED_ALLOCATED, CLAIMABLE, DEALLOCATES, VALUE, MINIMUM_CHUNK_SIZE>;
314    type WithMinimumChunkSize<const VALUE: usize> =
315        BumpSettings<MIN_ALIGN, UP, GUARANTEED_ALLOCATED, CLAIMABLE, DEALLOCATES, SHRINKS, VALUE>;
316}
317
318/// Either [`True`] or [`False`].
319#[expect(private_bounds)]
320pub trait Boolean: Sealed {
321    /// The boolean's value.
322    const VALUE: bool;
323}
324
325/// A type representing `true`.
326pub type True = Bool<true>;
327
328/// A type representing `false`.
329pub type False = Bool<false>;
330
331/// Used to create [`True`] and [`False`] types.
332pub struct Bool<const VALUE: bool>;
333
334impl<const VALUE: bool> Sealed for Bool<VALUE> {}
335
336impl<const VALUE: bool> Boolean for Bool<VALUE> {
337    const VALUE: bool = VALUE;
338}
339
340/// Specifies the current minimum alignment of a bump allocator.
341pub struct MinimumAlignment<const ALIGNMENT: usize>;
342
343mod supported_minimum_alignment {
344    use crate::ArrayLayout;
345
346    pub trait Sealed {
347        /// We'd be fine with just an [`core::ptr::Alignment`], but that's not stable.
348        #[doc(hidden)]
349        #[expect(private_interfaces)]
350        const LAYOUT: ArrayLayout;
351    }
352}
353
354/// Statically guarantees that a minimum alignment is supported.
355///
356/// This trait is *sealed*: the list of implementors below is total. Users do not have the ability to mark additional
357/// `MinimumAlignment<N>` values as supported. Only bump allocators with the supported minimum alignments are constructable.
358pub trait SupportedMinimumAlignment: supported_minimum_alignment::Sealed {
359    /// The minimum alignment in bytes.
360    const VALUE: usize;
361}
362
363macro_rules! supported_alignments {
364    ($($i:literal)*) => {
365        $(
366            impl supported_minimum_alignment::Sealed for MinimumAlignment<$i> {
367                #[expect(private_interfaces)]
368                const LAYOUT: ArrayLayout = match ArrayLayout::from_size_align(0, $i) {
369                    Ok(layout) => layout,
370                    Err(_) => unreachable!(),
371                };
372            }
373            impl SupportedMinimumAlignment for MinimumAlignment<$i> {
374                const VALUE: usize = $i;
375            }
376        )*
377    };
378}
379
380supported_alignments!(1 2 4 8 16);