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