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