Skip to main content

bump_scope/
settings.rs

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