bump_scope/bump.rs
1use core::{
2 alloc::Layout,
3 ffi::CStr,
4 fmt::{self, Debug},
5 mem::{ManuallyDrop, MaybeUninit},
6 panic::{RefUnwindSafe, UnwindSafe},
7 ptr::NonNull,
8};
9
10#[cfg(feature = "nightly-clone-to-uninit")]
11use core::clone::CloneToUninit;
12
13use crate::{
14 BaseAllocator, BumpBox, BumpClaimGuard, BumpScope, BumpScopeGuard, Checkpoint, ErrorBehavior,
15 alloc::{AllocError, Allocator},
16 allocator_impl,
17 chunk::ChunkSize,
18 maybe_default_allocator,
19 owned_slice::OwnedSlice,
20 polyfill::{transmute_mut, transmute_ref, transmute_value},
21 raw_bump::RawBump,
22 settings::{BumpAllocatorSettings, BumpSettings, False, MinimumAlignment, SupportedMinimumAlignment},
23 stats::{AnyStats, Stats},
24 traits::{
25 self, BumpAllocator, BumpAllocatorCore, BumpAllocatorScope, BumpAllocatorTyped, BumpAllocatorTypedScope,
26 MutBumpAllocatorTypedScope,
27 },
28};
29
30#[cfg(feature = "panic-on-alloc")]
31use crate::panic_on_error;
32
33macro_rules! make_type {
34 ($($allocator_parameter:tt)*) => {
35 /// The bump allocator.
36 ///
37 /// # Generic parameters
38 /// - **`A`** — the base allocator, defaults to `Global` when the `alloc` feature is enabled
39 /// - **`S`** — the bump allocator settings, see [`settings`](crate::settings)
40 ///
41 /// # Overview
42 /// All of the mentioned methods that do allocations panic if the base allocator returned an error.
43 /// For every such panicking method, there is a corresponding `try_`-prefixed version that returns a `Result` instead.
44 ///
45 /// #### Create a `Bump` ...
46 /// - with a default size hint: <code>[new]\([_in][new_in])</code> / <code>[default]</code>
47 /// - provide a size hint: <code>[with_size]\([_in][with_size_in])</code>
48 /// - provide a minimum capacity: <code>[with_capacity]\([_in][with_capacity_in])</code>
49 /// - const, without allocating a chunk: <code>[unallocated]</code>
50 ///
51 /// [new]: Bump::new
52 /// [new_in]: Bump::new_in
53 /// [default]: Bump::default
54 /// [with_size]: Bump::with_size
55 /// [with_size_in]: Bump::with_size_in
56 /// [with_capacity]: Bump::with_capacity
57 /// [with_capacity_in]: Bump::with_capacity_in
58 /// [unallocated]: Bump::unallocated
59 ///
60 /// #### Allocate ...
61 /// - sized values: [`alloc`], [`alloc_with`], [`alloc_default`], [`alloc_zeroed`]
62 /// - strings: [`alloc_str`], <code>[alloc_fmt](BumpAllocatorTypedScope::alloc_fmt)([_mut](MutBumpAllocatorTypedScope::alloc_fmt_mut))</code>
63 /// - c strings: [`alloc_cstr`], [`alloc_cstr_from_str`], <code>[alloc_cstr_fmt](BumpAllocatorTypedScope::alloc_cstr_fmt)([_mut](MutBumpAllocatorTypedScope::alloc_cstr_fmt_mut))</code>
64 /// - slices: <code>alloc_slice_{[copy](BumpAllocatorTypedScope::alloc_slice_copy), [clone](BumpAllocatorTypedScope::alloc_slice_clone), [move](BumpAllocatorTypedScope::alloc_slice_move), [fill](BumpAllocatorTypedScope::alloc_slice_fill), [fill_with](BumpAllocatorTypedScope::alloc_slice_fill_with)}</code>,
65 /// [`alloc_zeroed_slice`]
66 /// - slices from an iterator: [`alloc_iter`], [`alloc_iter_exact`], [`alloc_iter_mut`], [`alloc_iter_mut_rev`]
67 /// - uninitialized values: [`alloc_uninit`], [`alloc_uninit_slice`], [`alloc_uninit_slice_for`]
68 ///
69 /// which can then be conveniently initialized by the [`init*` methods of `BumpBox`](crate::BumpBox#bumpbox-has-a-lot-of-methods).
70 /// - results: [`alloc_try_with`], [`alloc_try_with_mut`]
71 /// - via clone *(nightly only)*: [`alloc_clone`]
72 ///
73 /// #### Free memory using ...
74 /// - scopes: [`scoped`], [`scoped_aligned`], [`scope_guard`]
75 /// - checkpoints: [`checkpoint`], [`reset_to`]
76 /// - reset: [`reset`]
77 /// - dealloc: [`dealloc`]
78 ///
79 /// #### Configure allocator settings ...
80 /// - [`with_settings`], [`borrow_with_settings`], [`borrow_mut_with_settings`]
81 ///
82 /// ## Collections
83 /// A `Bump` (and [`BumpScope`]) can be used to allocate collections of this crate...
84 /// ```
85 /// use bump_scope::{Bump, BumpString};
86 /// let bump: Bump = Bump::new();
87 ///
88 /// let mut string = BumpString::new_in(&bump);
89 /// string.push_str("Hello,");
90 /// string.push_str(" world!");
91 /// ```
92 ///
93 /// ... and collections from crates that use `allocator_api2`'s `Allocator` like [hashbrown](https://docs.rs/hashbrown)'s [`HashMap`](https://docs.rs/hashbrown/latest/hashbrown/struct.HashMap.html):
94 ///
95 /// *This requires the `allocator-api2-02` feature OR the `nightly-allocator-api` feature along with hashbrown's `nightly` feature.*
96 // NOTE: This code is tested in `crates/test-hashbrown/lib.rs`.
97 // It's not tested here because using hashbrown requires us to either have both the crate features for a nightly allocator api in bump-scope and hashbrown or neither.
98 // This could be solved by making bump-scope's "nightly-allocator-api" depend on "hashbrown/nightly" but that currently breaks tools like cargo-hack and cargo-minimal-versions.
99 /// ```
100 /// # /*
101 /// use bump_scope::Bump;
102 /// use hashbrown::HashMap;
103 ///
104 /// let bump: Bump = Bump::new();
105 /// let mut map = HashMap::new_in(&bump);
106 /// map.insert("tau", 6.283);
107 /// # */
108 /// # ()
109 /// ```
110 ///
111 /// On nightly and with the feature `nightly-allocator-api` you can also allocate collections from `std` that have an allocator parameter:
112 #[cfg_attr(feature = "nightly-allocator-api", doc = "```")]
113 #[cfg_attr(not(feature = "nightly-allocator-api"), doc = "```no_run")]
114 /// # /*
115 /// # those features are already been enabled by a `doc(test(attr`
116 /// # but we still want it here for demonstration
117 /// #![feature(allocator_api, btreemap_alloc)]
118 /// # */
119 /// # #[cfg(feature = "nightly-allocator-api")] fn main() {
120 /// use bump_scope::Bump;
121 /// use std::collections::{VecDeque, BTreeMap, LinkedList};
122 ///
123 /// let bump: Bump = Bump::new();
124 /// let vec = Vec::new_in(&bump);
125 /// let queue = VecDeque::new_in(&bump);
126 /// let map = BTreeMap::new_in(&bump);
127 /// let list = LinkedList::new_in(&bump);
128 /// # let _: Vec<i32, _> = vec;
129 /// # let _: VecDeque<i32, _> = queue;
130 /// # let _: BTreeMap<i32, i32, _> = map;
131 /// # let _: LinkedList<i32, _> = list;
132 /// # }
133 /// # #[cfg(not(feature = "nightly-allocator-api"))] fn main() {}
134 /// ```
135 ///
136 /// [`alloc`]: BumpAllocatorTypedScope::alloc
137 /// [`alloc_with`]: BumpAllocatorTypedScope::alloc_with
138 /// [`alloc_default`]: BumpAllocatorTypedScope::alloc_default
139 /// [`alloc_zeroed`]: crate::zerocopy_08::BumpAllocatorTypedScopeExt::alloc_zeroed
140 ///
141 /// [`alloc_str`]: BumpAllocatorTypedScope::alloc_str
142 ///
143 /// [`alloc_cstr`]: BumpAllocatorTypedScope::alloc_cstr
144 /// [`alloc_cstr_from_str`]: BumpAllocatorTypedScope::alloc_cstr_from_str
145 ///
146 /// [`alloc_zeroed_slice`]: crate::zerocopy_08::BumpAllocatorTypedScopeExt::alloc_zeroed_slice
147 ///
148 /// [`alloc_iter`]: BumpAllocatorTypedScope::alloc_iter
149 /// [`alloc_iter_exact`]: BumpAllocatorTypedScope::alloc_iter_exact
150 /// [`alloc_iter_mut`]: MutBumpAllocatorTypedScope::alloc_iter_mut
151 /// [`alloc_iter_mut_rev`]: MutBumpAllocatorTypedScope::alloc_iter_mut_rev
152 ///
153 /// [`alloc_uninit`]: BumpAllocatorTypedScope::alloc_uninit
154 /// [`alloc_uninit_slice`]: BumpAllocatorTypedScope::alloc_uninit_slice
155 /// [`alloc_uninit_slice_for`]: BumpAllocatorTypedScope::alloc_uninit_slice_for
156 ///
157 /// [`alloc_try_with`]: Bump::alloc_try_with
158 /// [`alloc_try_with_mut`]: Bump::alloc_try_with_mut
159 ///
160 /// [`alloc_clone`]: BumpAllocatorTypedScope::alloc_clone
161 ///
162 /// [`scoped`]: crate::traits::BumpAllocator::scoped
163 /// [`scoped_aligned`]: crate::traits::BumpAllocator::scoped_aligned
164 /// [`scope_guard`]: crate::traits::BumpAllocator::scope_guard
165 ///
166 /// [`checkpoint`]: BumpAllocatorCore::checkpoint
167 /// [`reset_to`]: BumpAllocatorCore::reset_to
168 ///
169 /// [`reset`]: Bump::reset
170 /// [`dealloc`]: BumpAllocatorTyped::dealloc
171 ///
172 /// [`aligned`]: BumpAllocatorScope::aligned
173 ///
174 /// [`with_settings`]: Bump::with_settings
175 /// [`borrow_with_settings`]: Bump::borrow_with_settings
176 /// [`borrow_mut_with_settings`]: Bump::borrow_with_settings
177 ///
178 /// # Gotcha
179 ///
180 /// Having live allocations and entering bump scopes at the same time requires a `BumpScope`.
181 /// This is due to the way lifetimes work, since `Bump` returns allocations with the lifetime
182 /// of its own borrow instead of a separate lifetime like `BumpScope` does.
183 ///
184 /// So you can't do this:
185 /// ```compile_fail,E0502
186 /// # use bump_scope::Bump;
187 /// let mut bump: Bump = Bump::new();
188 ///
189 /// let one = bump.alloc(1);
190 ///
191 /// bump.scoped(|bump| {
192 /// // whatever
193 /// # _ = bump;
194 /// });
195 /// # _ = one;
196 /// ```
197 /// But you can make the code work by converting the `Bump` it to a [`BumpScope`] first using [`as_mut_scope`]:
198 /// ```
199 /// # use bump_scope::Bump;
200 /// let mut bump: Bump = Bump::new();
201 /// let bump = bump.as_mut_scope();
202 ///
203 /// let one = bump.alloc(1);
204 ///
205 /// bump.scoped(|bump| {
206 /// // whatever
207 /// # _ = bump;
208 /// });
209 /// # _ = one;
210 /// ```
211 ///
212 /// [`as_mut_scope`]: Bump::as_mut_scope
213 #[repr(transparent)]
214 pub struct Bump<$($allocator_parameter)*, S = BumpSettings>
215 where
216 A: Allocator,
217 S: BumpAllocatorSettings,
218 {
219 pub(crate) raw: RawBump<A, S>,
220 }
221 };
222}
223
224maybe_default_allocator!(make_type);
225
226// Sending Bumps when nothing is allocated is fine.
227// When something is allocated Bump is borrowed and sending is not possible.
228unsafe impl<A, S> Send for Bump<A, S>
229where
230 A: Allocator,
231 S: BumpAllocatorSettings,
232{
233}
234
235impl<A, S> UnwindSafe for Bump<A, S>
236where
237 A: Allocator + UnwindSafe,
238 S: BumpAllocatorSettings,
239{
240}
241
242impl<A, S> RefUnwindSafe for Bump<A, S>
243where
244 A: Allocator + RefUnwindSafe,
245 S: BumpAllocatorSettings,
246{
247}
248
249impl<A, S> Drop for Bump<A, S>
250where
251 A: Allocator,
252 S: BumpAllocatorSettings,
253{
254 fn drop(&mut self) {
255 unsafe { self.raw.manually_drop() }
256 }
257}
258
259impl<A, S> Debug for Bump<A, S>
260where
261 A: Allocator,
262 S: BumpAllocatorSettings,
263{
264 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
265 AnyStats::from(self.stats()).debug_format("Bump", f)
266 }
267}
268
269#[cfg(feature = "panic-on-alloc")]
270impl<A, S> Default for Bump<A, S>
271where
272 A: Allocator + Default,
273 S: BumpAllocatorSettings,
274{
275 /// With [`GUARANTEED_ALLOCATED`] this does the same as [`new`], otherwise it does the same as [`unallocated`].
276 ///
277 /// [`GUARANTEED_ALLOCATED`]: crate::settings
278 /// [`new`]: Bump::new
279 /// [`unallocated`]: Bump::unallocated
280 #[inline(always)]
281 fn default() -> Self {
282 if S::GUARANTEED_ALLOCATED {
283 Self::new_in(Default::default())
284 } else {
285 use core::{cell::Cell, marker::PhantomData};
286
287 use crate::{chunk::ChunkHeader, raw_bump::RawChunk};
288
289 Self {
290 raw: RawBump {
291 chunk: Cell::new(RawChunk {
292 header: ChunkHeader::unallocated::<S>().cast(),
293 marker: PhantomData,
294 }),
295 },
296 }
297 }
298 }
299}
300
301#[cfg(not(feature = "panic-on-alloc"))]
302impl<A, S> Default for Bump<A, S>
303where
304 A: Allocator + Default,
305 S: BumpAllocatorSettings<GuaranteedAllocated = False>,
306{
307 /// Does the same as [`unallocated`].
308 ///
309 /// [`unallocated`]: Bump::unallocated
310 #[inline(always)]
311 fn default() -> Self {
312 Self::unallocated()
313 }
314}
315
316impl<A, S> Bump<A, S>
317where
318 A: Allocator,
319 S: BumpAllocatorSettings<GuaranteedAllocated = False>,
320{
321 /// Constructs a new `Bump` without allocating a chunk.
322 ///
323 /// This requires the `GUARANTEED_ALLOCATED` setting to be `false`, see [`settings`].
324 ///
325 /// # Examples
326 ///
327 /// ```
328 /// use bump_scope::{
329 /// alloc::Global,
330 /// Bump,
331 /// settings::{BumpSettings, BumpAllocatorSettings}
332 /// };
333 ///
334 /// type Settings = <BumpSettings as BumpAllocatorSettings>::WithGuaranteedAllocated<false>;
335 ///
336 /// let bump: Bump<Global, Settings> = Bump::unallocated();
337 /// # _ = bump;
338 /// ```
339 ///
340 /// [`settings`]: crate::settings
341 #[must_use]
342 pub const fn unallocated() -> Self {
343 Self { raw: RawBump::new() }
344 }
345}
346
347/// Methods for a `Bump` with a default base allocator.
348impl<A, S> Bump<A, S>
349where
350 A: Allocator + Default,
351 S: BumpAllocatorSettings,
352{
353 /// Constructs a new `Bump` with a default size hint for the first chunk.
354 ///
355 /// This is equivalent to <code>[with_size][]([MINIMUM_CHUNK_SIZE])</code>.
356 ///
357 /// # Panics
358 /// Panics if the allocation fails.
359 ///
360 /// # Examples
361 /// ```
362 /// use bump_scope::Bump;
363 ///
364 /// let bump: Bump = Bump::new();
365 /// # _ = bump;
366 /// ```
367 ///
368 /// [with_size]: Bump::with_size
369 /// [MINIMUM_CHUNK_SIZE]: crate::settings
370 #[must_use]
371 #[inline(always)]
372 #[cfg(feature = "panic-on-alloc")]
373 pub fn new() -> Self {
374 Self::with_size(S::MINIMUM_CHUNK_SIZE)
375 }
376
377 /// Constructs a new `Bump` with a default size hint for the first chunk.
378 ///
379 /// This is equivalent to <code>[try_with_size][]([MINIMUM_CHUNK_SIZE])</code>.
380 ///
381 /// # Errors
382 /// Errors if the allocation fails.
383 ///
384 /// # Examples
385 /// ```
386 /// use bump_scope::Bump;
387 ///
388 /// let bump: Bump = Bump::try_new()?;
389 /// # _ = bump;
390 /// # Ok::<(), bump_scope::alloc::AllocError>(())
391 /// ```
392 ///
393 /// [try_with_size]: Bump::try_with_size
394 /// [MINIMUM_CHUNK_SIZE]: crate::settings
395 #[inline(always)]
396 pub fn try_new() -> Result<Self, AllocError> {
397 Self::try_with_size(S::MINIMUM_CHUNK_SIZE)
398 }
399
400 /// Constructs a new `Bump` with a size hint for the first chunk.
401 ///
402 /// If you want to ensure a specific capacity, use [`with_capacity`](Self::with_capacity) instead.
403 ///
404 /// An effort is made to ensure the size requested from the base allocator is friendly to an allocator that uses size classes and stores metadata alongside allocations.
405 /// To achieve this, the requested size is rounded up to either the next power of two or the next multiple of `0x1000`, whichever is smaller.
406 /// After that, the size of `[usize; 2]` is subtracted.
407 ///
408 /// If the base allocator returns a memory block that is larger than requested, then the chunk will use the extra space.
409 ///
410 /// **Disclaimer:** The way in which the chunk layout is calculated might change.
411 /// Such a change is not considered semver breaking.
412 ///
413 /// # Panics
414 /// Panics if the allocation fails.
415 ///
416 /// # Examples
417 /// ```
418 /// use bump_scope::Bump;
419 ///
420 /// // `Bump` with a roughly 1 Mebibyte sized chunk
421 /// let bump_1mib: Bump = Bump::with_size(1024 * 1024);
422 /// # _ = bump_1mib;
423 /// ```
424 #[must_use]
425 #[inline(always)]
426 #[cfg(feature = "panic-on-alloc")]
427 pub fn with_size(size: usize) -> Self {
428 panic_on_error(Self::generic_with_size(size))
429 }
430
431 /// Constructs a new `Bump` with a size hint for the first chunk.
432 ///
433 /// If you want to ensure a specific capacity, use [`try_with_capacity`](Self::try_with_capacity) instead.
434 ///
435 /// An effort is made to ensure the size requested from the base allocator is friendly to an allocator that uses size classes and stores metadata alongside allocations.
436 /// To achieve this, the requested size is rounded up to either the next power of two or the next multiple of `0x1000`, whichever is smaller.
437 /// After that, the size of `[usize; 2]` is subtracted.
438 ///
439 /// If the base allocator returns a memory block that is larger than requested, then the chunk will use the extra space.
440 ///
441 /// **Disclaimer:** The way in which the chunk layout is calculated might change.
442 /// Such a change is not considered semver breaking.
443 ///
444 /// # Errors
445 /// Errors if the allocation fails.
446 ///
447 /// # Examples
448 /// ```
449 /// use bump_scope::Bump;
450 ///
451 /// // `Bump` with a roughly 1 Mebibyte sized chunk
452 /// let bump_1mib: Bump = Bump::try_with_size(1024 * 1024)?;
453 /// # _ = bump_1mib;
454 /// # Ok::<(), bump_scope::alloc::AllocError>(())
455 /// ```
456 #[inline(always)]
457 pub fn try_with_size(size: usize) -> Result<Self, AllocError> {
458 Self::generic_with_size(size)
459 }
460
461 #[inline]
462 pub(crate) fn generic_with_size<E: ErrorBehavior>(size: usize) -> Result<Self, E> {
463 Self::generic_with_size_in(size, Default::default())
464 }
465
466 /// Constructs a new `Bump` with a chunk that has at least enough space for `layout`.
467 ///
468 /// To construct a `Bump` with a size hint use <code>[with_size](Bump::with_size)</code> instead.
469 ///
470 /// # Panics
471 /// Panics if the allocation fails.
472 ///
473 /// # Examples
474 /// ```
475 /// use bump_scope::Bump;
476 /// use core::alloc::Layout;
477 ///
478 /// let layout = Layout::array::<u8>(1234).unwrap();
479 /// let bump: Bump = Bump::with_capacity(layout);
480 /// assert!(bump.stats().capacity() >= layout.size());
481 /// ```
482 #[must_use]
483 #[inline(always)]
484 #[cfg(feature = "panic-on-alloc")]
485 pub fn with_capacity(layout: Layout) -> Self {
486 panic_on_error(Self::generic_with_capacity(layout))
487 }
488
489 /// Constructs a new `Bump` with a chunk that has at least enough space for `layout`.
490 ///
491 /// To construct a `Bump` with a size hint use <code>[try_with_size](Bump::try_with_size)</code> instead.
492 ///
493 /// # Errors
494 /// Errors if the allocation fails.
495 ///
496 /// # Examples
497 /// ```
498 /// use bump_scope::Bump;
499 /// use core::alloc::Layout;
500 ///
501 /// let layout = Layout::array::<u8>(1234).unwrap();
502 /// let bump: Bump = Bump::try_with_capacity(layout)?;
503 /// assert!(bump.stats().capacity() >= layout.size());
504 /// # Ok::<(), bump_scope::alloc::AllocError>(())
505 /// ```
506 #[inline(always)]
507 pub fn try_with_capacity(layout: Layout) -> Result<Self, AllocError> {
508 Self::generic_with_capacity(layout)
509 }
510
511 #[inline]
512 pub(crate) fn generic_with_capacity<E: ErrorBehavior>(layout: Layout) -> Result<Self, E> {
513 Self::generic_with_capacity_in(layout, Default::default())
514 }
515}
516
517/// Methods that are always available.
518impl<A, S> Bump<A, S>
519where
520 A: Allocator,
521 S: BumpAllocatorSettings,
522{
523 /// Constructs a new `Bump` with a default size hint for the first chunk.
524 ///
525 /// This is equivalent to <code>[with_size_in][]([MINIMUM_CHUNK_SIZE], allocator)</code>.
526 ///
527 /// # Panics
528 /// Panics if the allocation fails.
529 ///
530 /// # Examples
531 /// ```
532 /// use bump_scope::Bump;
533 /// use bump_scope::alloc::Global;
534 ///
535 /// let bump: Bump = Bump::new_in(Global);
536 /// # _ = bump;
537 /// ```
538 ///
539 /// [with_size_in]: Bump::with_size_in
540 /// [MINIMUM_CHUNK_SIZE]: crate::settings
541 #[must_use]
542 #[inline(always)]
543 #[cfg(feature = "panic-on-alloc")]
544 pub fn new_in(allocator: A) -> Self {
545 Self::with_size_in(S::MINIMUM_CHUNK_SIZE, allocator)
546 }
547
548 /// Constructs a new `Bump` with a default size hint for the first chunk.
549 ///
550 /// This is equivalent to <code>[try_with_size_in][]([MINIMUM_CHUNK_SIZE], allocator)</code>.
551 ///
552 /// # Errors
553 /// Errors if the allocation fails.
554 ///
555 /// # Examples
556 /// ```
557 /// use bump_scope::Bump;
558 /// use bump_scope::alloc::Global;
559 ///
560 /// let bump: Bump = Bump::try_new_in(Global)?;
561 /// # _ = bump;
562 /// # Ok::<(), bump_scope::alloc::AllocError>(())
563 /// ```
564 ///
565 /// [try_with_size_in]: Bump::try_with_size_in
566 /// [MINIMUM_CHUNK_SIZE]: crate::settings
567 #[inline(always)]
568 pub fn try_new_in(allocator: A) -> Result<Self, AllocError> {
569 Self::try_with_size_in(S::MINIMUM_CHUNK_SIZE, allocator)
570 }
571
572 /// Constructs a new `Bump` with a size hint for the first chunk.
573 ///
574 /// If you want to ensure a specific capacity, use [`with_capacity_in`](Self::with_capacity_in) instead.
575 ///
576 /// An effort is made to ensure the size requested from the base allocator is friendly to an allocator that uses size classes and stores metadata alongside allocations.
577 /// To achieve this, the requested size is rounded up to either the next power of two or the next multiple of `0x1000`, whichever is smaller.
578 /// After that, the size of `[usize; 2]` is subtracted.
579 ///
580 /// If the base allocator returns a memory block that is larger than requested, then the chunk will use the extra space.
581 ///
582 /// **Disclaimer:** The way in which the chunk layout is calculated might change.
583 /// Such a change is not considered semver breaking.
584 ///
585 /// # Panics
586 /// Panics if the allocation fails.
587 ///
588 /// # Examples
589 /// ```
590 /// use bump_scope::Bump;
591 /// use bump_scope::alloc::Global;
592 ///
593 /// // `Bump` with a roughly 1 Mebibyte sized chunk
594 /// let bump_1mib: Bump = Bump::with_size_in(1024 * 1024, Global);
595 /// # _ = bump_1mib;
596 /// ```
597 #[must_use]
598 #[inline(always)]
599 #[cfg(feature = "panic-on-alloc")]
600 pub fn with_size_in(size: usize, allocator: A) -> Self {
601 panic_on_error(Self::generic_with_size_in(size, allocator))
602 }
603
604 /// Constructs a new `Bump` with a size hint for the first chunk.
605 ///
606 /// If you want to ensure a specific capacity, use [`try_with_capacity`](Self::try_with_capacity) instead.
607 ///
608 /// An effort is made to ensure the size requested from the base allocator is friendly to an allocator that uses size classes and stores metadata alongside allocations.
609 /// To achieve this, the requested size is rounded up to either the next power of two or the next multiple of `0x1000`, whichever is smaller.
610 /// After that, the size of `[usize; 2]` is subtracted.
611 ///
612 /// If the base allocator returns a memory block that is larger than requested, then the chunk will use the extra space.
613 ///
614 /// **Disclaimer:** The way in which the chunk layout is calculated might change.
615 /// Such a change is not considered semver breaking.
616 ///
617 /// # Errors
618 /// Errors if the allocation fails.
619 ///
620 /// # Examples
621 /// ```
622 /// use bump_scope::Bump;
623 /// use bump_scope::alloc::Global;
624 ///
625 /// // `Bump` with a roughly 1 Mebibyte sized chunk
626 /// let bump_1mib: Bump = Bump::try_with_size_in(1024 * 1024, Global)?;
627 /// # _ = bump_1mib;
628 /// # Ok::<(), bump_scope::alloc::AllocError>(())
629 /// ```
630 #[inline(always)]
631 pub fn try_with_size_in(size: usize, allocator: A) -> Result<Self, AllocError> {
632 Self::generic_with_size_in(size, allocator)
633 }
634
635 #[inline]
636 pub(crate) fn generic_with_size_in<E: ErrorBehavior>(size: usize, allocator: A) -> Result<Self, E> {
637 Ok(Self {
638 raw: RawBump::with_size(
639 ChunkSize::<A, S>::from_hint(size).ok_or_else(E::capacity_overflow)?,
640 allocator,
641 )?,
642 })
643 }
644
645 /// Constructs a new `Bump` with at least enough space for `layout`.
646 ///
647 /// To construct a `Bump` with a size hint use <code>[with_size_in](Bump::with_size_in)</code> instead.
648 ///
649 /// # Panics
650 /// Panics if the allocation fails.
651 ///
652 /// # Examples
653 /// ```
654 /// use bump_scope::Bump;
655 /// use bump_scope::alloc::Global;
656 /// use core::alloc::Layout;
657 ///
658 /// let layout = Layout::array::<u8>(1234).unwrap();
659 /// let bump: Bump = Bump::with_capacity_in(layout, Global);
660 /// assert!(bump.stats().capacity() >= layout.size());
661 /// # Ok::<(), bump_scope::alloc::AllocError>(())
662 /// ```
663 #[must_use]
664 #[inline(always)]
665 #[cfg(feature = "panic-on-alloc")]
666 pub fn with_capacity_in(layout: Layout, allocator: A) -> Self {
667 panic_on_error(Self::generic_with_capacity_in(layout, allocator))
668 }
669
670 /// Constructs a new `Bump` with at least enough space for `layout`.
671 ///
672 /// To construct a `Bump` with a size hint use <code>[try_with_size_in](Bump::try_with_size_in)</code> instead.
673 ///
674 /// # Errors
675 /// Errors if the allocation fails.
676 ///
677 /// # Examples
678 /// ```
679 /// use bump_scope::Bump;
680 /// use bump_scope::alloc::Global;
681 /// use core::alloc::Layout;
682 ///
683 /// let layout = Layout::array::<u8>(1234).unwrap();
684 /// let bump: Bump = Bump::try_with_capacity_in(layout, Global)?;
685 /// assert!(bump.stats().capacity() >= layout.size());
686 /// # Ok::<(), bump_scope::alloc::AllocError>(())
687 /// ```
688 #[inline(always)]
689 pub fn try_with_capacity_in(layout: Layout, allocator: A) -> Result<Self, AllocError> {
690 Self::generic_with_capacity_in(layout, allocator)
691 }
692
693 #[inline]
694 pub(crate) fn generic_with_capacity_in<E: ErrorBehavior>(layout: Layout, allocator: A) -> Result<Self, E> {
695 Ok(Self {
696 raw: RawBump::with_size(
697 ChunkSize::<A, S>::from_capacity(layout).ok_or_else(E::capacity_overflow)?,
698 allocator,
699 )?,
700 })
701 }
702
703 /// Resets this bump allocator and deallocates all but the largest chunk.
704 ///
705 /// This deallocates all allocations at once by resetting
706 /// the bump pointer to the start of the retained chunk.
707 ///
708 /// For a version of this function that doesn't deallocate chunks, see [`reset_to_start`].
709 ///
710 /// [`reset_to_start`]: Self::reset_to_start
711 ///
712 /// ```
713 /// use bump_scope::Bump;
714 ///
715 /// let mut bump: Bump = Bump::with_size(512);
716 ///
717 /// // won't fit in the first chunk
718 /// bump.alloc_uninit_slice::<u8>(600);
719 ///
720 /// let chunks = bump.stats().small_to_big().collect::<Vec<_>>();
721 /// assert_eq!(chunks.len(), 2);
722 /// assert!(chunks[0].size() < chunks[1].size());
723 /// assert_eq!(chunks[0].allocated(), 0);
724 /// assert_eq!(chunks[1].allocated(), 600);
725 /// let last_chunk_size = chunks[1].size();
726 ///
727 /// bump.reset();
728 ///
729 /// let chunks = bump.stats().small_to_big().collect::<Vec<_>>();
730 /// assert_eq!(chunks.len(), 1);
731 /// assert_eq!(chunks[0].size(), last_chunk_size);
732 /// assert_eq!(chunks[0].allocated(), 0);
733 /// ```
734 #[inline(always)]
735 pub fn reset(&mut self) {
736 self.raw.reset();
737 }
738
739 /// Resets this bump allocator.
740 ///
741 /// This deallocates all allocations at once by resetting
742 /// the bump pointer to the start of the first chunk.
743 ///
744 /// For a version of this function that also deallocates chunks, see [`reset`].
745 ///
746 /// [`reset`]: Self::reset
747 ///
748 /// # Examples
749 ///
750 /// ```
751 /// # use bump_scope::Bump;
752 /// let mut bump: Bump = Bump::new();
753 ///
754 /// {
755 /// let hello = bump.alloc_str("hello");
756 /// assert_eq!(bump.stats().allocated(), 5);
757 /// # _ = hello;
758 /// }
759 ///
760 /// unsafe { bump.reset_to_start(); }
761 /// assert_eq!(bump.stats().allocated(), 0);
762 /// ```
763 #[inline(always)]
764 pub fn reset_to_start(&mut self) {
765 self.raw.reset_to_start();
766 }
767
768 /// Returns a type which provides statistics about the memory usage of the bump allocator.
769 #[must_use]
770 #[inline(always)]
771 pub fn stats(&self) -> Stats<'_, A, S> {
772 self.as_scope().stats()
773 }
774
775 /// Returns this `&Bump` as a `&BumpScope`.
776 #[must_use]
777 #[inline(always)]
778 pub fn as_scope(&self) -> &BumpScope<'_, A, S> {
779 unsafe { transmute_ref(self) }
780 }
781
782 /// Returns this `&mut Bump` as a `&mut BumpScope`.
783 #[must_use]
784 #[inline(always)]
785 pub fn as_mut_scope(&mut self) -> &mut BumpScope<'_, A, S> {
786 unsafe { transmute_mut(self) }
787 }
788
789 /// Converts this `Bump` into a `Bump` with new settings.
790 ///
791 /// This function will fail to compile if:
792 /// - `NewS::UP != S::UP`
793 ///
794 /// # Panics
795 /// Panics if `!NewS::CLAIMABLE` and the bump allocator is currently [claimed].
796 ///
797 /// Panics if `NewS::GUARANTEED_ALLOCATED` and no chunk has been allocated.
798 ///
799 /// [claimed]: crate::traits::BumpAllocatorScope::claim
800 #[inline]
801 pub fn with_settings<NewS>(self) -> Bump<A, NewS>
802 where
803 A: BaseAllocator<NewS::GuaranteedAllocated>,
804 NewS: BumpAllocatorSettings,
805 {
806 self.raw.ensure_satisfies_settings::<NewS>();
807 unsafe { transmute_value(self) }
808 }
809
810 /// Borrows this `Bump` with new settings.
811 ///
812 /// This function will fail to compile if:
813 /// - `NewS::MIN_ALIGN != S::MIN_ALIGN`
814 /// - `NewS::UP != S::UP`
815 /// - `NewS::CLAIMABLE != S::CLAIMABLE`
816 /// - `NewS::GUARANTEED_ALLOCATED > S::GUARANTEED_ALLOCATED`
817 #[inline]
818 pub fn borrow_with_settings<NewS>(&self) -> &Bump<A, NewS>
819 where
820 A: BaseAllocator<NewS::GuaranteedAllocated>,
821 NewS: BumpAllocatorSettings,
822 {
823 self.raw.ensure_satisfies_settings_for_borrow::<NewS>();
824 unsafe { transmute_ref(self) }
825 }
826
827 /// Borrows this `Bump` mutably with new settings.
828 ///
829 /// This function will fail to compile if:
830 /// - `NewS::MIN_ALIGN < S::MIN_ALIGN`
831 /// - `NewS::UP != S::UP`
832 /// - `NewS::GUARANTEED_ALLOCATED != S::GUARANTEED_ALLOCATED`
833 /// - `NewS::CLAIMABLE != S::CLAIMABLE`
834 #[inline]
835 pub fn borrow_mut_with_settings<NewS>(&mut self) -> &mut Bump<A, NewS>
836 where
837 A: BaseAllocator<NewS::GuaranteedAllocated>,
838 NewS: BumpAllocatorSettings,
839 {
840 self.raw.ensure_satisfies_settings_for_borrow_mut::<NewS>();
841 unsafe { transmute_mut(self) }
842 }
843
844 /// Converts this `Bump` into a raw pointer.
845 ///
846 /// ```
847 /// # use bump_scope::Bump;
848 /// #
849 /// let bump: Bump = Bump::new();
850 /// bump.alloc_str("Hello, ");
851 ///
852 /// let ptr = bump.into_raw();
853 /// let bump: Bump = unsafe { Bump::from_raw(ptr) };
854 ///
855 /// bump.alloc_str("World!");
856 /// # assert_eq!(bump.stats().allocated(), 13);
857 /// ```
858 #[inline]
859 #[must_use]
860 pub fn into_raw(self) -> NonNull<()> {
861 ManuallyDrop::new(self).raw.clone().into_raw()
862 }
863
864 /// Converts the raw pointer that was created with [`into_raw`](Bump::into_raw) back into a `Bump`.
865 ///
866 /// # Safety
867 /// - `ptr` must come from a call to `Self::into_raw`.
868 /// - This function must only be called once with this `ptr`.
869 /// - The settings must match the original ones.
870 #[inline]
871 #[must_use]
872 pub unsafe fn from_raw(ptr: NonNull<()>) -> Self {
873 Self {
874 raw: unsafe { RawBump::from_raw(ptr) },
875 }
876 }
877}
878
879impl<'b, A, S> From<&'b Bump<A, S>> for &'b BumpScope<'b, A, S>
880where
881 A: BaseAllocator<S::GuaranteedAllocated>,
882 S: BumpAllocatorSettings,
883{
884 #[inline(always)]
885 fn from(value: &'b Bump<A, S>) -> Self {
886 value.as_scope()
887 }
888}
889
890impl<'b, A, S> From<&'b mut Bump<A, S>> for &'b mut BumpScope<'b, A, S>
891where
892 A: BaseAllocator<S::GuaranteedAllocated>,
893 S: BumpAllocatorSettings,
894{
895 #[inline(always)]
896 fn from(value: &'b mut Bump<A, S>) -> Self {
897 value.as_mut_scope()
898 }
899}
900
901/// Methods that forward to traits.
902// Documentation is in the forwarded to methods.
903#[allow(clippy::missing_errors_doc, clippy::missing_safety_doc)]
904impl<A, S> Bump<A, S>
905where
906 A: BaseAllocator<S::GuaranteedAllocated>,
907 S: BumpAllocatorSettings,
908{
909 traits::forward_methods! {
910 self: self
911 access: {self.as_scope()}
912 access_mut: {self.as_mut_scope()}
913 lifetime: '_
914 }
915}
916
917/// Additional `alloc` methods that are not available in traits.
918impl<A, S> Bump<A, S>
919where
920 A: BaseAllocator<S::GuaranteedAllocated>,
921 S: BumpAllocatorSettings,
922{
923 /// Allocates the result of `f` in the bump allocator, then moves `E` out of it and deallocates the space it took up.
924 ///
925 /// This can be more performant than allocating `T` after the fact, as `Result<T, E>` may be constructed in the bump allocators memory instead of on the stack and then copied over.
926 ///
927 /// There is also [`alloc_try_with_mut`](Self::alloc_try_with_mut), optimized for a mutable reference.
928 ///
929 /// # Panics
930 /// Panics if the allocation fails.
931 ///
932 /// # Examples
933 #[cfg_attr(feature = "nightly-tests", doc = "```")]
934 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
935 /// # #![feature(offset_of_enum)]
936 /// # use core::mem::offset_of;
937 /// # use bump_scope::Bump;
938 /// # let bump: Bump = Bump::new();
939 /// let result = bump.alloc_try_with(|| -> Result<i32, i32> { Ok(123) });
940 /// assert_eq!(result.unwrap(), 123);
941 /// assert_eq!(bump.stats().allocated(), offset_of!(Result<i32, i32>, Ok.0) + size_of::<i32>());
942 /// ```
943 #[cfg_attr(feature = "nightly-tests", doc = "```")]
944 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
945 /// # use bump_scope::Bump;
946 /// # let bump: Bump = Bump::new();
947 /// let result = bump.alloc_try_with(|| -> Result<i32, i32> { Err(123) });
948 /// assert_eq!(result.unwrap_err(), 123);
949 /// assert_eq!(bump.stats().allocated(), 0);
950 /// ```
951 #[inline(always)]
952 #[cfg(feature = "panic-on-alloc")]
953 #[expect(clippy::missing_errors_doc)]
954 pub fn alloc_try_with<T, E>(&self, f: impl FnOnce() -> Result<T, E>) -> Result<BumpBox<'_, T>, E> {
955 self.as_scope().alloc_try_with(f)
956 }
957
958 /// Allocates the result of `f` in the bump allocator, then moves `E` out of it and deallocates the space it took up.
959 ///
960 /// This can be more performant than allocating `T` after the fact, as `Result<T, E>` may be constructed in the bump allocators memory instead of on the stack and then copied over.
961 ///
962 /// There is also [`try_alloc_try_with_mut`](Self::try_alloc_try_with_mut), optimized for a mutable reference.
963 ///
964 /// # Errors
965 /// Errors if the allocation fails.
966 ///
967 /// # Examples
968 #[cfg_attr(feature = "nightly-tests", doc = "```")]
969 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
970 /// # #![feature(offset_of_enum)]
971 /// # use core::mem::offset_of;
972 /// # use bump_scope::Bump;
973 /// # let bump: Bump = Bump::new();
974 /// let result = bump.try_alloc_try_with(|| -> Result<i32, i32> { Ok(123) })?;
975 /// assert_eq!(result.unwrap(), 123);
976 /// assert_eq!(bump.stats().allocated(), offset_of!(Result<i32, i32>, Ok.0) + size_of::<i32>());
977 /// # Ok::<(), bump_scope::alloc::AllocError>(())
978 /// ```
979 #[cfg_attr(feature = "nightly-tests", doc = "```")]
980 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
981 /// # use bump_scope::Bump;
982 /// # let bump: Bump = Bump::new();
983 /// let result = bump.try_alloc_try_with(|| -> Result<i32, i32> { Err(123) })?;
984 /// assert_eq!(result.unwrap_err(), 123);
985 /// assert_eq!(bump.stats().allocated(), 0);
986 /// # Ok::<(), bump_scope::alloc::AllocError>(())
987 /// ```
988 #[inline(always)]
989 pub fn try_alloc_try_with<T, E>(
990 &self,
991 f: impl FnOnce() -> Result<T, E>,
992 ) -> Result<Result<BumpBox<'_, T>, E>, AllocError> {
993 self.as_scope().try_alloc_try_with(f)
994 }
995
996 /// Allocates the result of `f` in the bump allocator, then moves `E` out of it and deallocates the space it took up.
997 ///
998 /// This can be more performant than allocating `T` after the fact, as `Result<T, E>` may be constructed in the bump allocators memory instead of on the stack and then copied over.
999 ///
1000 /// This is just like [`alloc_try_with`](Self::alloc_try_with), but optimized for a mutable reference.
1001 ///
1002 /// # Panics
1003 /// Panics if the allocation fails.
1004 ///
1005 /// # Examples
1006 #[cfg_attr(feature = "nightly-tests", doc = "```")]
1007 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
1008 /// # #![feature(offset_of_enum)]
1009 /// # use core::mem::offset_of;
1010 /// # use bump_scope::Bump;
1011 /// # let mut bump: Bump = Bump::new();
1012 /// let result = bump.alloc_try_with_mut(|| -> Result<i32, i32> { Ok(123) });
1013 /// assert_eq!(result.unwrap(), 123);
1014 /// assert_eq!(bump.stats().allocated(), offset_of!(Result<i32, i32>, Ok.0) + size_of::<i32>());
1015 /// ```
1016 #[cfg_attr(feature = "nightly-tests", doc = "```")]
1017 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
1018 /// # use bump_scope::Bump;
1019 /// # let mut bump: Bump = Bump::new();
1020 /// let result = bump.alloc_try_with_mut(|| -> Result<i32, i32> { Err(123) });
1021 /// assert_eq!(result.unwrap_err(), 123);
1022 /// assert_eq!(bump.stats().allocated(), 0);
1023 /// ```
1024 #[inline(always)]
1025 #[cfg(feature = "panic-on-alloc")]
1026 #[expect(clippy::missing_errors_doc)]
1027 pub fn alloc_try_with_mut<T, E>(&mut self, f: impl FnOnce() -> Result<T, E>) -> Result<BumpBox<'_, T>, E> {
1028 self.as_mut_scope().alloc_try_with_mut(f)
1029 }
1030
1031 /// Allocates the result of `f` in the bump allocator, then moves `E` out of it and deallocates the space it took up.
1032 ///
1033 /// This can be more performant than allocating `T` after the fact, as `Result<T, E>` may be constructed in the bump allocators memory instead of on the stack and then copied over.
1034 ///
1035 /// This is just like [`try_alloc_try_with`](Self::try_alloc_try_with), but optimized for a mutable reference.
1036 ///
1037 /// # Errors
1038 /// Errors if the allocation fails.
1039 ///
1040 /// # Examples
1041 #[cfg_attr(feature = "nightly-tests", doc = "```")]
1042 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
1043 /// # #![feature(offset_of_enum)]
1044 /// # use core::mem::offset_of;
1045 /// # use bump_scope::Bump;
1046 /// # let mut bump: Bump = Bump::new();
1047 /// let result = bump.try_alloc_try_with_mut(|| -> Result<i32, i32> { Ok(123) })?;
1048 /// assert_eq!(result.unwrap(), 123);
1049 /// assert_eq!(bump.stats().allocated(), offset_of!(Result<i32, i32>, Ok.0) + size_of::<i32>());
1050 /// # Ok::<(), bump_scope::alloc::AllocError>(())
1051 /// ```
1052 #[cfg_attr(feature = "nightly-tests", doc = "```")]
1053 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
1054 /// # use bump_scope::Bump;
1055 /// # let mut bump: Bump = Bump::new();
1056 /// let result = bump.try_alloc_try_with_mut(|| -> Result<i32, i32> { Err(123) })?;
1057 /// assert_eq!(result.unwrap_err(), 123);
1058 /// assert_eq!(bump.stats().allocated(), 0);
1059 /// # Ok::<(), bump_scope::alloc::AllocError>(())
1060 /// ```
1061 #[inline(always)]
1062 pub fn try_alloc_try_with_mut<T, E>(
1063 &mut self,
1064 f: impl FnOnce() -> Result<T, E>,
1065 ) -> Result<Result<BumpBox<'_, T>, E>, AllocError> {
1066 self.as_mut_scope().try_alloc_try_with_mut(f)
1067 }
1068}
1069
1070unsafe impl<A, S> Allocator for Bump<A, S>
1071where
1072 A: BaseAllocator<S::GuaranteedAllocated>,
1073 S: BumpAllocatorSettings,
1074{
1075 #[inline(always)]
1076 fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
1077 allocator_impl::allocate(&self.raw, layout)
1078 }
1079
1080 #[inline(always)]
1081 unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
1082 unsafe { allocator_impl::deallocate(&self.raw, ptr, layout) };
1083 }
1084
1085 #[inline(always)]
1086 unsafe fn grow(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
1087 unsafe { allocator_impl::grow(&self.raw, ptr, old_layout, new_layout) }
1088 }
1089
1090 #[inline(always)]
1091 unsafe fn grow_zeroed(
1092 &self,
1093 ptr: NonNull<u8>,
1094 old_layout: Layout,
1095 new_layout: Layout,
1096 ) -> Result<NonNull<[u8]>, AllocError> {
1097 unsafe { allocator_impl::grow_zeroed(&self.raw, ptr, old_layout, new_layout) }
1098 }
1099
1100 #[inline(always)]
1101 unsafe fn shrink(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
1102 unsafe { allocator_impl::shrink(&self.raw, ptr, old_layout, new_layout) }
1103 }
1104}