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