bump_scope/bump_scope.rs
1use core::{
2 alloc::Layout,
3 cell::Cell,
4 ffi::CStr,
5 fmt::{self, Debug},
6 marker::PhantomData,
7 mem::{ManuallyDrop, MaybeUninit, transmute},
8 num::NonZeroUsize,
9 ops::Range,
10 panic::{RefUnwindSafe, UnwindSafe},
11 ptr::{self, NonNull},
12};
13
14#[cfg(feature = "nightly-clone-to-uninit")]
15use core::clone::CloneToUninit;
16
17use crate::{
18 BaseAllocator, Bump, BumpBox, BumpScopeGuard, BumpString, BumpVec, Checkpoint, ErrorBehavior, FixedBumpString,
19 FixedBumpVec, MinimumAlignment, MutBumpString, MutBumpVec, MutBumpVecRev, NoDrop, RawChunk, SizedTypeProperties,
20 SupportedMinimumAlignment, align_pos,
21 alloc::{AllocError, Allocator},
22 allocator_impl,
23 bump_align_guard::BumpAlignGuard,
24 chunk_header::ChunkHeader,
25 chunk_size::ChunkSize,
26 const_param_assert, down_align_usize,
27 layout::{ArrayLayout, CustomLayout, LayoutProps, SizedLayout},
28 maybe_default_allocator,
29 owned_slice::OwnedSlice,
30 polyfill::{non_null, transmute_mut, transmute_ref},
31 stats::{AnyStats, Stats},
32 up_align_usize_unchecked,
33};
34
35#[cfg(feature = "panic-on-alloc")]
36use crate::panic_on_error;
37
38macro_rules! make_type {
39 ($($allocator_parameter:tt)*) => {
40 /// A bump allocation scope.
41 ///
42 /// A `BumpScope`'s allocations are live for `'a`, which is the lifetime of its associated `BumpScopeGuard(Root)` or `scoped` closure.
43 ///
44 /// `BumpScope` has the same allocation api as `Bump`.
45 /// The only thing that is missing is [`reset`] and methods that consume the `Bump`.
46 /// For a method overview and examples, have a look at the [`Bump` docs][`Bump`].
47 ///
48 /// This type is provided as a parameter to the closure of [`Bump::scoped`], [`BumpScope::scoped`] or created
49 /// by [`BumpScopeGuard::scope`] and [`BumpScopeGuardRoot::scope`]. A [`Bump`] can also be turned into a `BumpScope` using
50 /// [`as_scope`], [`as_mut_scope`] or [`into`].
51 ///
52 /// [`Bump::scoped`]: crate::Bump::scoped
53 /// [`BumpScopeGuard::scope`]: crate::BumpScopeGuard::scope
54 /// [`BumpScopeGuardRoot::scope`]: crate::BumpScopeGuardRoot::scope
55 /// [`Bump`]: crate::Bump
56 /// [`scoped`]: Self::scoped
57 /// [`as_scope`]: crate::Bump::as_scope
58 /// [`as_mut_scope`]: crate::Bump::as_mut_scope
59 /// [`reset`]: crate::Bump::reset
60 /// [`into`]: crate::Bump#impl-From<%26Bump<A,+MIN_ALIGN,+UP,+GUARANTEED_ALLOCATED>>-for-%26BumpScope<'b,+A,+MIN_ALIGN,+UP,+GUARANTEED_ALLOCATED>
61 #[repr(transparent)]
62 pub struct BumpScope<
63 'a,
64 $($allocator_parameter)*,
65 const MIN_ALIGN: usize = 1,
66 const UP: bool = true,
67 const GUARANTEED_ALLOCATED: bool = true,
68 const DEALLOCATES: bool = true,
69 > {
70 pub(crate) chunk: Cell<RawChunk<A, UP, GUARANTEED_ALLOCATED>>,
71
72 /// Marks the lifetime of the mutably borrowed `BumpScopeGuard(Root)`.
73 marker: PhantomData<&'a ()>,
74 }
75 };
76}
77
78maybe_default_allocator!(make_type);
79
80impl<A, const MIN_ALIGN: usize, const UP: bool, const GUARANTEED_ALLOCATED: bool, const DEALLOCATES: bool> UnwindSafe
81 for BumpScope<'_, A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES>
82where
83 MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
84 A: UnwindSafe,
85{
86}
87
88impl<A, const MIN_ALIGN: usize, const UP: bool, const GUARANTEED_ALLOCATED: bool, const DEALLOCATES: bool> RefUnwindSafe
89 for BumpScope<'_, A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES>
90where
91 MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
92 A: UnwindSafe,
93{
94}
95
96impl<A, const MIN_ALIGN: usize, const UP: bool, const GUARANTEED_ALLOCATED: bool, const DEALLOCATES: bool> Debug
97 for BumpScope<'_, A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES>
98where
99 MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
100{
101 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102 AnyStats::from(self.stats()).debug_format("BumpScope", f)
103 }
104}
105
106unsafe impl<A, const MIN_ALIGN: usize, const UP: bool, const GUARANTEED_ALLOCATED: bool, const DEALLOCATES: bool> Allocator
107 for BumpScope<'_, A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES>
108where
109 MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
110 A: BaseAllocator<GUARANTEED_ALLOCATED>,
111{
112 #[inline(always)]
113 fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
114 allocator_impl::allocate(self, layout)
115 }
116
117 #[inline(always)]
118 unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
119 unsafe { allocator_impl::deallocate(self, ptr, layout) };
120 }
121
122 #[inline(always)]
123 unsafe fn grow(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
124 unsafe { allocator_impl::grow(self, ptr, old_layout, new_layout) }
125 }
126
127 #[inline(always)]
128 unsafe fn grow_zeroed(
129 &self,
130 ptr: NonNull<u8>,
131 old_layout: Layout,
132 new_layout: Layout,
133 ) -> Result<NonNull<[u8]>, AllocError> {
134 unsafe { allocator_impl::grow_zeroed(self, ptr, old_layout, new_layout) }
135 }
136
137 #[inline(always)]
138 unsafe fn shrink(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
139 unsafe { allocator_impl::shrink(self, ptr, old_layout, new_layout) }
140 }
141}
142
143/// Methods for a [*guaranteed allocated*](crate#what-does-guaranteed-allocated-mean) `BumpScope`.
144impl<'a, A, const MIN_ALIGN: usize, const UP: bool, const DEALLOCATES: bool>
145 BumpScope<'a, A, MIN_ALIGN, UP, true, DEALLOCATES>
146where
147 MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
148{
149 /// Returns a reference to the base allocator.
150 #[must_use]
151 #[inline(always)]
152 pub fn allocator(&self) -> &'a A {
153 self.stats().current_chunk().allocator()
154 }
155
156 /// Calls `f` with a new child scope.
157 ///
158 /// # Examples
159 ///
160 /// ```
161 /// # use bump_scope::Bump;
162 /// let mut bump: Bump = Bump::new();
163 ///
164 /// bump.scoped(|bump| {
165 /// bump.alloc_str("Hello, world!");
166 /// assert_eq!(bump.stats().allocated(), 13);
167 /// });
168 ///
169 /// assert_eq!(bump.stats().allocated(), 0);
170 /// ```
171 #[inline(always)]
172 pub fn scoped<R>(&mut self, f: impl FnOnce(BumpScope<A, MIN_ALIGN, UP, true, DEALLOCATES>) -> R) -> R {
173 let mut guard = self.scope_guard();
174 f(guard.scope())
175 }
176
177 /// Calls `f` with a new child scope of a new minimum alignment.
178 ///
179 /// # Examples
180 ///
181 #[cfg_attr(feature = "nightly-tests", doc = "```")]
182 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
183 /// # #![feature(pointer_is_aligned_to)]
184 /// # use bump_scope::Bump;
185 /// let mut bump: Bump = Bump::new();
186 ///
187 /// // bump starts off by being aligned to 16
188 /// assert!(bump.stats().current_chunk().bump_position().is_aligned_to(16));
189 ///
190 /// // allocate one byte
191 /// bump.alloc(1u8);
192 ///
193 /// // now the bump is only aligned to 1
194 /// // (if our `MIN_ALIGN` was higher, it would be that)
195 /// assert!(bump.stats().current_chunk().bump_position().addr().get() % 2 == 1);
196 /// assert_eq!(bump.stats().allocated(), 1);
197 ///
198 /// bump.scoped_aligned::<8, ()>(|bump| {
199 /// // in here, the bump will have the specified minimum alignment of 8
200 /// assert!(bump.stats().current_chunk().bump_position().is_aligned_to(8));
201 /// assert_eq!(bump.stats().allocated(), 8);
202 ///
203 /// // allocating a value with its size being a multiple of 8 will no longer have
204 /// // to align the bump pointer before allocation
205 /// bump.alloc(1u64);
206 /// assert!(bump.stats().current_chunk().bump_position().is_aligned_to(8));
207 /// assert_eq!(bump.stats().allocated(), 16);
208 ///
209 /// // allocating a value smaller than the minimum alignment must align the bump pointer
210 /// // after the allocation, resulting in some wasted space
211 /// bump.alloc(1u8);
212 /// assert!(bump.stats().current_chunk().bump_position().is_aligned_to(8));
213 /// assert_eq!(bump.stats().allocated(), 24);
214 /// });
215 ///
216 /// assert_eq!(bump.stats().allocated(), 1);
217 /// ```
218 #[inline(always)]
219 pub fn scoped_aligned<const NEW_MIN_ALIGN: usize, R>(
220 &mut self,
221 f: impl FnOnce(BumpScope<A, NEW_MIN_ALIGN, UP, true, DEALLOCATES>) -> R,
222 ) -> R
223 where
224 MinimumAlignment<NEW_MIN_ALIGN>: SupportedMinimumAlignment,
225 {
226 // This guard will reset the bump pointer to the current position, which is aligned to `MIN_ALIGN`.
227 let mut guard = self.scope_guard();
228 let scope = guard.scope();
229 scope.align::<NEW_MIN_ALIGN>();
230 f(unsafe { scope.cast_align() })
231 }
232
233 /// Calls `f` with this scope but with a new minimum alignment.
234 ///
235 /// # Examples
236 ///
237 /// Increase the minimum alignment:
238 #[cfg_attr(feature = "nightly-tests", doc = "```")]
239 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
240 /// # #![feature(pointer_is_aligned_to)]
241 /// # use bump_scope::Bump;
242 /// let mut bump: Bump = Bump::new();
243 /// let bump = bump.as_mut_scope();
244 ///
245 /// // here we're allocating with a `MIN_ALIGN` of `1`
246 /// let foo = bump.alloc_str("foo");
247 /// assert_eq!(bump.stats().allocated(), 3);
248 ///
249 /// let bar = bump.aligned::<8, _>(|bump| {
250 /// // in here the bump position has been aligned to `8`
251 /// assert_eq!(bump.stats().allocated(), 8);
252 /// assert!(bump.stats().current_chunk().bump_position().is_aligned_to(8));
253 ///
254 /// // make some allocations that benefit from the higher `MIN_ALIGN` of `8`
255 /// let bar = bump.alloc(0u64);
256 /// assert_eq!(bump.stats().allocated(), 16);
257 ///
258 /// // the bump position will stay aligned to `8`
259 /// bump.alloc(0u8);
260 /// assert_eq!(bump.stats().allocated(), 24);
261 ///
262 /// bar
263 /// });
264 ///
265 /// assert_eq!(bump.stats().allocated(), 24);
266 ///
267 /// // continue making allocations with a `MIN_ALIGN` of `1`
268 /// let baz = bump.alloc_str("baz");
269 /// assert_eq!(bump.stats().allocated(), 24 + 3);
270 ///
271 /// dbg!(foo, bar, baz);
272 /// ```
273 ///
274 /// Decrease the minimum alignment:
275 #[cfg_attr(feature = "nightly-tests", doc = "```")]
276 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
277 /// # #![feature(pointer_is_aligned_to)]
278 /// # use bump_scope::{Bump, alloc::Global};
279 /// let mut bump: Bump<Global, 8> = Bump::new();
280 /// let bump = bump.as_mut_scope();
281 ///
282 /// // make some allocations that benefit from the `MIN_ALIGN` of `8`
283 /// let foo = bump.alloc(0u64);
284 ///
285 /// let bar = bump.aligned::<1, _>(|bump| {
286 /// // make some allocations that benefit from the lower `MIN_ALIGN` of `1`
287 /// let bar = bump.alloc(0u8);
288 ///
289 /// // the bump position will not get aligned to `8` in here
290 /// assert_eq!(bump.stats().allocated(), 8 + 1);
291 ///
292 /// bar
293 /// });
294 ///
295 /// // after `aligned()`, the bump position will be aligned to `8` again
296 /// // to satisfy our `MIN_ALIGN`
297 /// assert!(bump.stats().current_chunk().bump_position().is_aligned_to(8));
298 /// assert_eq!(bump.stats().allocated(), 16);
299 ///
300 /// // continue making allocations that benefit from the `MIN_ALIGN` of `8`
301 /// let baz = bump.alloc(0u64);
302 ///
303 /// dbg!(foo, bar, baz);
304 /// ```
305 #[inline(always)]
306 pub fn aligned<const NEW_MIN_ALIGN: usize, R>(
307 &mut self,
308 f: impl FnOnce(BumpScope<'a, A, NEW_MIN_ALIGN, UP, true, DEALLOCATES>) -> R,
309 ) -> R
310 where
311 MinimumAlignment<NEW_MIN_ALIGN>: SupportedMinimumAlignment,
312 {
313 if NEW_MIN_ALIGN < MIN_ALIGN {
314 // This guard will align whatever the future bump position is back to `MIN_ALIGN`.
315 let guard = BumpAlignGuard::new(self);
316 f(unsafe { guard.scope.clone_unchecked().cast_align() })
317 } else {
318 self.align::<NEW_MIN_ALIGN>();
319 f(unsafe { self.clone_unchecked().cast_align() })
320 }
321 }
322
323 /// Creates a new [`BumpScopeGuard`].
324 ///
325 /// This allows for creation of child scopes.
326 ///
327 /// # Examples
328 ///
329 /// ```
330 /// # use bump_scope::Bump;
331 /// let mut bump: Bump = Bump::new();
332 ///
333 /// {
334 /// let mut guard = bump.scope_guard();
335 /// let bump = guard.scope();
336 /// bump.alloc_str("Hello, world!");
337 /// assert_eq!(bump.stats().allocated(), 13);
338 /// }
339 ///
340 /// assert_eq!(bump.stats().allocated(), 0);
341 /// ```
342 #[must_use]
343 #[inline(always)]
344 pub fn scope_guard(&mut self) -> BumpScopeGuard<'_, A, MIN_ALIGN, UP, DEALLOCATES> {
345 BumpScopeGuard::new(self)
346 }
347}
348
349/// Methods for a **not** [*guaranteed allocated*](crate#what-does-guaranteed-allocated-mean) `BumpScope`.
350impl<'a, A, const MIN_ALIGN: usize, const UP: bool, const DEALLOCATES: bool>
351 BumpScope<'a, A, MIN_ALIGN, UP, false, DEALLOCATES>
352where
353 MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
354{
355 /// Returns a reference to the base allocator.
356 #[must_use]
357 #[inline(always)]
358 pub fn allocator(&self) -> Option<&'a A> {
359 self.stats().current_chunk().map(|c| c.allocator())
360 }
361}
362
363/// Methods that are always available.
364impl<'a, A, const MIN_ALIGN: usize, const UP: bool, const GUARANTEED_ALLOCATED: bool, const DEALLOCATES: bool>
365 BumpScope<'a, A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES>
366where
367 MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
368{
369 #[inline(always)]
370 pub(crate) unsafe fn new_unchecked(chunk: RawChunk<A, UP, GUARANTEED_ALLOCATED>) -> Self {
371 Self {
372 chunk: Cell::new(chunk),
373 marker: PhantomData,
374 }
375 }
376
377 /// Creates a checkpoint of the current bump position.
378 ///
379 /// The bump position can be reset to this checkpoint with [`reset_to`].
380 ///
381 /// [`reset_to`]: Self::reset_to
382 ///
383 /// # Examples
384 ///
385 /// ```
386 /// # use bump_scope::Bump;
387 /// let bump: Bump = Bump::new();
388 /// let checkpoint = bump.checkpoint();
389 ///
390 /// {
391 /// let hello = bump.alloc_str("hello");
392 /// assert_eq!(bump.stats().allocated(), 5);
393 /// # _ = hello;
394 /// }
395 ///
396 /// unsafe { bump.reset_to(checkpoint); }
397 /// assert_eq!(bump.stats().allocated(), 0);
398 /// ```
399 #[inline]
400 pub fn checkpoint(&self) -> Checkpoint {
401 Checkpoint::new(self.chunk.get())
402 }
403
404 /// Resets the bump position to a previously created checkpoint.
405 /// The memory that has been allocated since then will be reused by future allocations.
406 ///
407 /// # Safety
408 ///
409 /// - the checkpoint must have been created by this bump allocator
410 /// - the bump allocator must not have been [`reset`] since creation of this checkpoint
411 /// - there must be no references to allocations made since creation of this checkpoint
412 /// - the checkpoint must not have been created by an`!GUARANTEED_ALLOCATED` when self is `GUARANTEED_ALLOCATED`
413 ///
414 /// [`reset`]: crate::Bump::reset
415 ///
416 /// # Examples
417 ///
418 /// ```
419 /// # use bump_scope::Bump;
420 /// let bump: Bump = Bump::new();
421 /// let checkpoint = bump.checkpoint();
422 ///
423 /// {
424 /// let hello = bump.alloc_str("hello");
425 /// assert_eq!(bump.stats().allocated(), 5);
426 /// # _ = hello;
427 /// }
428 ///
429 /// unsafe { bump.reset_to(checkpoint); }
430 /// assert_eq!(bump.stats().allocated(), 0);
431 /// ```
432 #[inline]
433 #[expect(clippy::missing_panics_doc)] // just debug assertions
434 pub unsafe fn reset_to(&self, checkpoint: Checkpoint) {
435 // If the checkpoint was created when the bump allocator had no allocated chunk
436 // then the chunk pointer will point to the unallocated chunk header.
437 //
438 // In such cases we reset the bump pointer to the very start of the very first chunk.
439 //
440 // We don't check if the chunk pointer points to the unallocated chunk header
441 // if the bump allocator is `GUARANTEED_ALLOCATED`. We are allowed to not do this check
442 // because of this safety condition of `reset_to`:
443 // > the checkpoint must not have been created by an`!GUARANTEED_ALLOCATED` when self is `GUARANTEED_ALLOCATED`
444 if !GUARANTEED_ALLOCATED && checkpoint.chunk == ChunkHeader::UNALLOCATED {
445 if let Some(mut chunk) = self.chunk.get().guaranteed_allocated() {
446 while let Some(prev) = chunk.prev() {
447 chunk = prev;
448 }
449
450 chunk.reset();
451 self.chunk.set(chunk.coerce_guaranteed_allocated());
452 }
453 } else {
454 debug_assert_ne!(
455 checkpoint.chunk,
456 ChunkHeader::UNALLOCATED,
457 "the safety conditions state that \"the checkpoint must not have been created by an`!GUARANTEED_ALLOCATED` when self is `GUARANTEED_ALLOCATED`\""
458 );
459
460 #[cfg(debug_assertions)]
461 {
462 let chunk = self
463 .stats()
464 .small_to_big()
465 .find(|chunk| chunk.header() == checkpoint.chunk.cast())
466 .expect("this checkpoint does not refer to any chunk of this bump allocator");
467
468 assert!(
469 chunk.contains_addr_or_end(checkpoint.address.get()),
470 "checkpoint address does not point within its chunk"
471 );
472 }
473
474 unsafe {
475 checkpoint.reset_within_chunk();
476 let chunk = RawChunk::from_header(checkpoint.chunk.cast());
477 self.chunk.set(chunk);
478 }
479 }
480 }
481
482 /// "Returns a type which provides statistics about the memory usage of the bump allocator.
483 #[must_use]
484 #[inline(always)]
485 pub fn stats(&self) -> Stats<'a, A, UP, GUARANTEED_ALLOCATED> {
486 self.chunk.get().stats()
487 }
488
489 #[inline(always)]
490 pub(crate) fn align<const ALIGN: usize>(&self)
491 where
492 MinimumAlignment<ALIGN>: SupportedMinimumAlignment,
493 {
494 if ALIGN > MIN_ALIGN {
495 // The UNALLOCATED chunk is always aligned.
496 if let Some(chunk) = self.chunk.get().guaranteed_allocated() {
497 let pos = chunk.pos().addr();
498 let addr = align_pos::<ALIGN, UP>(pos);
499 unsafe { chunk.set_pos_addr(addr) };
500 }
501 }
502 }
503
504 /// Converts this `BumpScope` into a ***not*** [guaranteed allocated](crate#what-does-guaranteed-allocated-mean) `BumpScope`.
505 #[inline(always)]
506 pub fn into_not_guaranteed_allocated(self) -> BumpScope<'a, A, MIN_ALIGN, UP, false, DEALLOCATES> {
507 // SAFETY: it's always valid to interpret a guaranteed allocated as a non guaranteed allocated
508 unsafe { transmute(self) }
509 }
510
511 /// Borrows `BumpScope` as a ***not*** [guaranteed allocated](crate#what-does-guaranteed-allocated-mean) `BumpScope`.
512 ///
513 /// Note that it's not possible to mutably borrow as a not guaranteed allocated bump allocator. That's because
514 /// a user could `mem::swap` it with an actual unallocated bump allocator which in turn would make `&mut self`
515 /// unallocated.
516 #[inline(always)]
517 pub fn as_not_guaranteed_allocated(&self) -> &BumpScope<'a, A, MIN_ALIGN, UP, false, DEALLOCATES> {
518 // SAFETY: it's always valid to interpret a guaranteed allocated as a non guaranteed allocated
519 unsafe { transmute_ref(self) }
520 }
521
522 /// # Safety
523 ///
524 /// - `self` must not be used until this clone is gone
525 #[inline(always)]
526 pub(crate) unsafe fn clone_unchecked(&self) -> BumpScope<'a, A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES> {
527 unsafe { BumpScope::new_unchecked(self.chunk.get()) }
528 }
529
530 /// Converts this `BumpScope` into a raw pointer.
531 #[inline]
532 #[must_use]
533 pub fn into_raw(self) -> NonNull<()> {
534 let this = ManuallyDrop::new(self);
535 this.chunk.get().header().cast()
536 }
537
538 /// Converts the raw pointer that was created with [`into_raw`](Self::into_raw) back into a `BumpScope`.
539 ///
540 /// # Safety
541 /// This is highly unsafe, due to the number of invariants that aren't checked:
542 /// - `ptr` must have been created with `Self::into_raw`.
543 /// - This function must only be called once with this `ptr`.
544 /// - The lifetime must be the original one.
545 /// - Nothing must have been allocated since then.
546 #[inline]
547 #[must_use]
548 pub unsafe fn from_raw(ptr: NonNull<()>) -> Self {
549 Self {
550 chunk: Cell::new(unsafe { RawChunk::from_header(ptr.cast()) }),
551 marker: PhantomData,
552 }
553 }
554
555 #[inline(always)]
556 pub(crate) unsafe fn cast_align<const NEW_MIN_ALIGN: usize>(
557 self,
558 ) -> BumpScope<'a, A, NEW_MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES>
559 where
560 MinimumAlignment<NEW_MIN_ALIGN>: SupportedMinimumAlignment,
561 {
562 BumpScope {
563 chunk: self.chunk,
564 marker: PhantomData,
565 }
566 }
567
568 #[inline(always)]
569 pub(crate) unsafe fn cast_align_mut<const NEW_MIN_ALIGN: usize>(
570 &mut self,
571 ) -> &mut BumpScope<'a, A, NEW_MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES>
572 where
573 MinimumAlignment<NEW_MIN_ALIGN>: SupportedMinimumAlignment,
574 {
575 unsafe { &mut *ptr::from_mut(self).cast::<BumpScope<'a, A, NEW_MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES>>() }
576 }
577
578 /// Will error at compile time if `NEW_MIN_ALIGN < MIN_ALIGN`.
579 #[inline(always)]
580 pub(crate) fn must_align_more<const NEW_MIN_ALIGN: usize>(&self)
581 where
582 MinimumAlignment<NEW_MIN_ALIGN>: SupportedMinimumAlignment,
583 {
584 const_param_assert! {
585 (const MIN_ALIGN: usize, const NEW_MIN_ALIGN: usize) => NEW_MIN_ALIGN >= MIN_ALIGN, "`into_aligned` or `as_mut_aligned` can't decrease the minimum alignment"
586 }
587
588 self.align::<NEW_MIN_ALIGN>();
589 }
590
591 /// Mutably borrows `BumpScope` with a new minimum alignment.
592 ///
593 /// **This cannot decrease the alignment.** Trying to decrease alignment will result in a compile error.
594 /// You can use [`aligned`](Self::aligned) or [`scoped_aligned`](Self::scoped_aligned) to decrease the alignment.
595 ///
596 /// When decreasing the alignment we need to make sure that the bump position is realigned to the original alignment.
597 /// That can only be ensured by having a function that takes a closure, like the methods mentioned above do.
598 #[inline(always)]
599 pub fn as_mut_aligned<const NEW_MIN_ALIGN: usize>(
600 &mut self,
601 ) -> &mut BumpScope<'a, A, NEW_MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES>
602 where
603 MinimumAlignment<NEW_MIN_ALIGN>: SupportedMinimumAlignment,
604 {
605 self.must_align_more::<NEW_MIN_ALIGN>();
606 unsafe { self.cast_align_mut() }
607 }
608
609 #[doc(hidden)]
610 #[inline(always)]
611 #[deprecated = "renamed to `as_mut_aligned`"]
612 pub fn as_aligned_mut<const NEW_MIN_ALIGN: usize>(
613 &mut self,
614 ) -> &mut BumpScope<'a, A, NEW_MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES>
615 where
616 MinimumAlignment<NEW_MIN_ALIGN>: SupportedMinimumAlignment,
617 {
618 self.as_mut_aligned()
619 }
620
621 /// Returns `&self` as is. This is useful for macros that support both `Bump` and `BumpScope`.
622 #[inline(always)]
623 pub fn as_scope(&self) -> &Self {
624 self
625 }
626
627 /// Returns `&mut self` as is. This is useful for macros that support both `Bump` and `BumpScope`.
628 #[inline(always)]
629 pub fn as_mut_scope(&mut self) -> &mut Self {
630 self
631 }
632
633 /// Converts this `BumpScope` into a `BumpScope` with a new minimum alignment.
634 ///
635 /// **This cannot decrease the alignment.** Trying to decrease alignment will result in a compile error.
636 /// You can use [`aligned`](Self::aligned) or [`scoped_aligned`](Self::scoped_aligned) to decrease the alignment.
637 ///
638 /// When decreasing the alignment we need to make sure that the bump position is realigned to the original alignment.
639 /// That can only be ensured by having a function that takes a closure, like the methods mentioned above do.
640 ///
641 /// If this was allowed to decrease the alignment it would break minimum alignment:
642 ///
643 /// ```ignore
644 /// # // We can't `compile_fail,E0080` this doc test because it does not do the compile step
645 /// # // that triggers the error.
646 /// # use bump_scope::{Bump, alloc::Global};
647 /// let mut bump: Bump<Global, 8, true> = Bump::new();
648 /// let mut guard = bump.scope_guard();
649 ///
650 /// {
651 /// let scope = guard.scope().into_aligned::<1>();
652 /// scope.alloc(0u8);
653 /// }
654 ///
655 /// {
656 /// let scope = guard.scope();
657 /// // scope is not aligned to `MIN_ALIGN`!!
658 /// }
659 ///
660 /// ```
661 #[inline(always)]
662 pub fn into_aligned<const NEW_MIN_ALIGN: usize>(
663 self,
664 ) -> BumpScope<'a, A, NEW_MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES>
665 where
666 MinimumAlignment<NEW_MIN_ALIGN>: SupportedMinimumAlignment,
667 {
668 self.must_align_more::<NEW_MIN_ALIGN>();
669 unsafe { self.cast_align() }
670 }
671
672 #[inline(always)]
673 pub(crate) unsafe fn use_prepared_slice_allocation<T>(&self, start: NonNull<T>, len: usize, cap: usize) -> NonNull<[T]> {
674 unsafe {
675 let end = start.add(len);
676
677 if UP {
678 self.set_aligned_pos(end.addr(), T::ALIGN);
679 NonNull::slice_from_raw_parts(start, len)
680 } else {
681 let dst_end = start.add(cap);
682 let dst = dst_end.sub(len);
683 start.copy_to(dst, len);
684 self.set_aligned_pos(dst.addr(), T::ALIGN);
685 NonNull::slice_from_raw_parts(dst, len)
686 }
687 }
688 }
689
690 #[inline(always)]
691 pub(crate) unsafe fn use_prepared_slice_allocation_rev<T>(
692 &self,
693 end: NonNull<T>,
694 len: usize,
695 cap: usize,
696 ) -> NonNull<[T]> {
697 unsafe {
698 if UP {
699 let dst = end.sub(cap);
700 let dst_end = dst.add(len);
701
702 let src = end.sub(len);
703
704 src.copy_to(dst, len);
705
706 self.set_aligned_pos(dst_end.addr(), T::ALIGN);
707 NonNull::slice_from_raw_parts(dst, len)
708 } else {
709 let dst = end.sub(len);
710 self.set_aligned_pos(dst.addr(), T::ALIGN);
711 NonNull::slice_from_raw_parts(dst, len)
712 }
713 }
714 }
715
716 /// Sets the bump position and aligns it to the required `MIN_ALIGN`.
717 ///
718 /// This does nothing if the current chunk is the UNALLOCATED one.
719 #[inline(always)]
720 pub(crate) unsafe fn set_pos(&self, pos: NonZeroUsize) {
721 unsafe {
722 let addr = align_pos::<MIN_ALIGN, UP>(pos);
723
724 if let Some(chunk) = self.chunk.get().guaranteed_allocated() {
725 chunk.set_pos_addr(addr);
726 }
727 }
728 }
729
730 /// A version of [`set_pos`](Self::set_pos) that only aligns the pointer
731 /// if it the `pos_align` is smaller than the `MIN_ALIGN`.
732 ///
733 /// This should only be called when the `pos_align` is statically known so
734 /// the branch gets optimized out.
735 ///
736 /// This does nothing if the current chunk is the UNALLOCATED one.
737 #[inline(always)]
738 pub(crate) unsafe fn set_aligned_pos(&self, pos: NonZeroUsize, pos_align: usize) {
739 debug_assert_eq!(pos.get() % pos_align, 0);
740
741 let addr = if pos_align < MIN_ALIGN {
742 align_pos::<MIN_ALIGN, UP>(pos)
743 } else {
744 pos.get()
745 };
746
747 if let Some(chunk) = self.chunk.get().guaranteed_allocated() {
748 unsafe { chunk.set_pos_addr(addr) };
749 }
750 }
751
752 /// Turns off deallocation and shrinking.
753 pub fn into_without_dealloc(self) -> BumpScope<'a, A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, false> {
754 unsafe { transmute(self) }
755 }
756
757 /// Turns off deallocation and shrinking.
758 pub fn as_without_dealloc(&self) -> &BumpScope<'a, A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, false> {
759 unsafe { transmute_ref(self) }
760 }
761
762 /// Turns off deallocation and shrinking.
763 pub fn as_mut_without_dealloc(&mut self) -> &mut BumpScope<'a, A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, false> {
764 unsafe { transmute_mut(self) }
765 }
766
767 /// Turns on deallocation and shrinking.
768 pub fn into_with_dealloc(self) -> BumpScope<'a, A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, true> {
769 unsafe { transmute(self) }
770 }
771
772 /// Turns on deallocation and shrinking.
773 pub fn as_with_dealloc(&self) -> &BumpScope<'a, A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, true> {
774 unsafe { transmute_ref(self) }
775 }
776
777 /// Turns on deallocation and shrinking.
778 pub fn as_mut_with_dealloc(&mut self) -> &mut BumpScope<'a, A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, true> {
779 unsafe { transmute_mut(self) }
780 }
781}
782
783/// Methods that are always available. (but with `A: Allocator`)
784impl<'a, A, const MIN_ALIGN: usize, const UP: bool, const GUARANTEED_ALLOCATED: bool, const DEALLOCATES: bool>
785 BumpScope<'a, A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES>
786where
787 MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
788 A: Allocator,
789{
790 /// Converts this `BumpScope` into a [guaranteed allocated](crate#what-does-guaranteed-allocated-mean) `BumpScope`.
791 ///
792 /// See [`Bump::into_guaranteed_allocated`].
793 ///
794 /// # Panics
795 ///
796 /// Panics if the closure panics.
797 #[inline(always)]
798 #[cfg(feature = "panic-on-alloc")]
799 pub fn into_guaranteed_allocated(
800 self,
801 f: impl FnOnce() -> Bump<A, MIN_ALIGN, UP, true, DEALLOCATES>,
802 ) -> BumpScope<'a, A, MIN_ALIGN, UP, true, DEALLOCATES> {
803 self.ensure_allocated(f);
804 unsafe { transmute(self) }
805 }
806
807 /// Converts this `BumpScope` into a [guaranteed allocated](crate#what-does-guaranteed-allocated-mean) `BumpScope`.
808 ///
809 /// See [`Bump::try_into_guaranteed_allocated`].
810 ///
811 /// # Errors
812 ///
813 /// Errors if the closure fails.
814 #[inline(always)]
815 pub fn try_into_guaranteed_allocated(
816 self,
817 f: impl FnOnce() -> Result<Bump<A, MIN_ALIGN, UP, true, DEALLOCATES>, AllocError>,
818 ) -> Result<BumpScope<'a, A, MIN_ALIGN, UP, true, DEALLOCATES>, AllocError> {
819 self.try_ensure_allocated(f)?;
820 Ok(unsafe { transmute(self) })
821 }
822
823 /// Borrows `BumpScope` as a [guaranteed allocated](crate#what-does-guaranteed-allocated-mean) `BumpScope`.
824 ///
825 /// See [`Bump::as_guaranteed_allocated`].
826 ///
827 /// # Panics
828 ///
829 /// Panics if the closure panics.
830 #[inline(always)]
831 #[cfg(feature = "panic-on-alloc")]
832 pub fn as_guaranteed_allocated(
833 &self,
834 f: impl FnOnce() -> Bump<A, MIN_ALIGN, UP, true, DEALLOCATES>,
835 ) -> &BumpScope<'a, A, MIN_ALIGN, UP, true, DEALLOCATES> {
836 self.ensure_allocated(f);
837 unsafe { transmute_ref(self) }
838 }
839
840 /// Borrows `BumpScope` as a [guaranteed allocated](crate#what-does-guaranteed-allocated-mean) `BumpScope`.
841 ///
842 /// See [`Bump::try_as_guaranteed_allocated`].
843 ///
844 /// # Errors
845 ///
846 /// Errors if the closure fails.
847 #[inline(always)]
848 pub fn try_as_guaranteed_allocated(
849 &self,
850 f: impl FnOnce() -> Result<Bump<A, MIN_ALIGN, UP, true, DEALLOCATES>, AllocError>,
851 ) -> Result<&BumpScope<'a, A, MIN_ALIGN, UP, true, DEALLOCATES>, AllocError> {
852 self.try_ensure_allocated(f)?;
853 Ok(unsafe { transmute_ref(self) })
854 }
855
856 /// Mutably borrows `BumpScope` as a [guaranteed allocated](crate#what-does-guaranteed-allocated-mean) `BumpScope`.
857 ///
858 /// See [`Bump::as_mut_guaranteed_allocated`].
859 ///
860 /// # Panics
861 ///
862 /// Panics if the closure panics.
863 #[inline(always)]
864 #[cfg(feature = "panic-on-alloc")]
865 pub fn as_mut_guaranteed_allocated(
866 &mut self,
867 f: impl FnOnce() -> Bump<A, MIN_ALIGN, UP, true, DEALLOCATES>,
868 ) -> &mut BumpScope<'a, A, MIN_ALIGN, UP, true, DEALLOCATES> {
869 self.ensure_allocated(f);
870 unsafe { transmute_mut(self) }
871 }
872
873 /// Mutably borrows `BumpScope` as a [guaranteed allocated](crate#what-does-guaranteed-allocated-mean) `BumpScope`.
874 ///
875 /// See [`Bump::try_as_mut_guaranteed_allocated`].
876 ///
877 /// # Errors
878 ///
879 /// Errors if the closure fails.
880 #[inline(always)]
881 pub fn try_as_mut_guaranteed_allocated(
882 &mut self,
883 f: impl FnOnce() -> Result<Bump<A, MIN_ALIGN, UP, true, DEALLOCATES>, AllocError>,
884 ) -> Result<&mut BumpScope<'a, A, MIN_ALIGN, UP, true, DEALLOCATES>, AllocError> {
885 self.try_ensure_allocated(f)?;
886 Ok(unsafe { transmute_mut(self) })
887 }
888
889 #[inline(always)]
890 #[cfg(feature = "panic-on-alloc")]
891 pub(crate) fn ensure_allocated(&self, f: impl FnOnce() -> Bump<A, MIN_ALIGN, UP, true, DEALLOCATES>) {
892 if self.chunk.get().is_unallocated() {
893 unsafe {
894 self.chunk.set(RawChunk::from_header(f().into_raw().cast()));
895 }
896 }
897 }
898
899 #[inline(always)]
900 pub(crate) fn try_ensure_allocated(
901 &self,
902 f: impl FnOnce() -> Result<Bump<A, MIN_ALIGN, UP, true, DEALLOCATES>, AllocError>,
903 ) -> Result<(), AllocError> {
904 if self.chunk.get().is_unallocated() {
905 unsafe {
906 self.chunk.set(RawChunk::from_header(f()?.into_raw().cast()));
907 }
908 }
909
910 Ok(())
911 }
912}
913
914impl<A, const MIN_ALIGN: usize, const UP: bool, const GUARANTEED_ALLOCATED: bool, const DEALLOCATES: bool>
915 BumpScope<'_, A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES>
916where
917 MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
918 A: BaseAllocator<GUARANTEED_ALLOCATED>,
919{
920 #[inline(always)]
921 pub(crate) fn generic_prepare_allocation<B: ErrorBehavior, T>(&self) -> Result<NonNull<T>, B> {
922 match self
923 .chunk
924 .get()
925 .prepare_allocation(MinimumAlignment::<MIN_ALIGN>, SizedLayout::new::<T>())
926 {
927 Some(ptr) => Ok(ptr.cast()),
928 None => match self.prepare_allocation_in_another_chunk::<B, T>() {
929 Ok(ptr) => Ok(ptr.cast()),
930 Err(err) => Err(err),
931 },
932 }
933 }
934
935 #[cold]
936 #[inline(never)]
937 pub(crate) fn prepare_allocation_in_another_chunk<E: ErrorBehavior, T>(&self) -> Result<NonNull<u8>, E>
938 where
939 MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
940 {
941 let layout = CustomLayout(Layout::new::<T>());
942
943 unsafe {
944 self.in_another_chunk(layout, |chunk, layout| {
945 chunk.prepare_allocation(MinimumAlignment::<MIN_ALIGN>, layout)
946 })
947 }
948 }
949
950 pub(crate) fn generic_prepare_slice_allocation<B: ErrorBehavior, T>(&self, min_cap: usize) -> Result<NonNull<[T]>, B> {
951 let range = self.prepare_allocation_range::<B, T>(min_cap)?;
952
953 // NB: We can't use `offset_from_unsigned`, because the size is not a multiple of `T`'s.
954 let cap = unsafe { non_null::byte_offset_from_unsigned(range.end, range.start) } / T::SIZE;
955
956 let ptr = if UP { range.start } else { unsafe { range.end.sub(cap) } };
957
958 Ok(NonNull::slice_from_raw_parts(ptr, cap))
959 }
960
961 /// Returns a pointer range.
962 /// The start and end pointers are aligned.
963 /// But `end - start` is *not* a multiple of `size_of::<T>()`.
964 /// So `end.offset_from_unsigned(start)` may not be used!
965 #[inline(always)]
966 pub(crate) fn prepare_allocation_range<B: ErrorBehavior, T>(&self, cap: usize) -> Result<Range<NonNull<T>>, B> {
967 let Ok(layout) = ArrayLayout::array::<T>(cap) else {
968 return Err(B::capacity_overflow());
969 };
970
971 let range = match self
972 .chunk
973 .get()
974 .prepare_allocation_range(MinimumAlignment::<MIN_ALIGN>, layout)
975 {
976 Some(ptr) => ptr,
977 None => self.prepare_allocation_range_in_another_chunk(layout)?,
978 };
979
980 Ok(range.start.cast::<T>()..range.end.cast::<T>())
981 }
982
983 #[cold]
984 #[inline(never)]
985 pub(crate) fn prepare_allocation_range_in_another_chunk<E: ErrorBehavior>(
986 &self,
987 layout: ArrayLayout,
988 ) -> Result<Range<NonNull<u8>>, E> {
989 unsafe {
990 self.in_another_chunk(layout, |chunk, layout| {
991 chunk.prepare_allocation_range(MinimumAlignment::<MIN_ALIGN>, layout)
992 })
993 }
994 }
995
996 #[inline(always)]
997 pub(crate) fn alloc_in_current_chunk(&self, layout: Layout) -> Option<NonNull<u8>> {
998 self.chunk.get().alloc(MinimumAlignment::<MIN_ALIGN>, CustomLayout(layout))
999 }
1000
1001 /// Allocation slow path.
1002 /// The active chunk must *not* have space for `layout`.
1003 #[cold]
1004 #[inline(never)]
1005 pub(crate) fn alloc_in_another_chunk<E: ErrorBehavior>(&self, layout: Layout) -> Result<NonNull<u8>, E> {
1006 unsafe {
1007 self.in_another_chunk(CustomLayout(layout), |chunk, layout| {
1008 chunk.alloc(MinimumAlignment::<MIN_ALIGN>, layout)
1009 })
1010 }
1011 }
1012
1013 #[inline(always)]
1014 pub(crate) fn do_alloc_sized<E: ErrorBehavior, T>(&self) -> Result<NonNull<T>, E> {
1015 match self.chunk.get().alloc(MinimumAlignment::<MIN_ALIGN>, SizedLayout::new::<T>()) {
1016 Some(ptr) => Ok(ptr.cast()),
1017 None => match self.do_alloc_sized_in_another_chunk::<E, T>() {
1018 Ok(ptr) => Ok(ptr.cast()),
1019 Err(err) => Err(err),
1020 },
1021 }
1022 }
1023
1024 #[cold]
1025 #[inline(never)]
1026 pub(crate) fn do_alloc_sized_in_another_chunk<E: ErrorBehavior, T>(&self) -> Result<NonNull<u8>, E>
1027 where
1028 MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
1029 {
1030 self.alloc_in_another_chunk(Layout::new::<T>())
1031 }
1032
1033 #[inline(always)]
1034 pub(crate) fn do_alloc_slice<E: ErrorBehavior, T>(&self, len: usize) -> Result<NonNull<T>, E> {
1035 let Ok(layout) = ArrayLayout::array::<T>(len) else {
1036 return Err(E::capacity_overflow());
1037 };
1038
1039 match self.chunk.get().alloc(MinimumAlignment::<MIN_ALIGN>, layout) {
1040 Some(ptr) => Ok(ptr.cast()),
1041 None => match self.do_alloc_slice_in_another_chunk::<E, T>(len) {
1042 Ok(ptr) => Ok(ptr.cast()),
1043 Err(err) => Err(err),
1044 },
1045 }
1046 }
1047
1048 #[inline(always)]
1049 pub(crate) fn do_alloc_slice_for<E: ErrorBehavior, T>(&self, value: &[T]) -> Result<NonNull<T>, E> {
1050 let layout = ArrayLayout::for_value(value);
1051
1052 match self.chunk.get().alloc(MinimumAlignment::<MIN_ALIGN>, layout) {
1053 Some(ptr) => Ok(ptr.cast()),
1054 None => match self.do_alloc_slice_in_another_chunk::<E, T>(value.len()) {
1055 Ok(ptr) => Ok(ptr.cast()),
1056 Err(err) => Err(err),
1057 },
1058 }
1059 }
1060
1061 #[cold]
1062 #[inline(never)]
1063 pub(crate) fn do_alloc_slice_in_another_chunk<E: ErrorBehavior, T>(&self, len: usize) -> Result<NonNull<u8>, E>
1064 where
1065 MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
1066 {
1067 let Ok(layout) = Layout::array::<T>(len) else {
1068 return Err(E::capacity_overflow());
1069 };
1070
1071 self.alloc_in_another_chunk(layout)
1072 }
1073
1074 /// # Safety
1075 ///
1076 /// `f` on the new chunk created by `RawChunk::append_for` with the layout `layout` must return `Some`.
1077 #[inline(always)]
1078 pub(crate) unsafe fn in_another_chunk<B: ErrorBehavior, R, L: LayoutProps>(
1079 &self,
1080 layout: L,
1081 mut f: impl FnMut(RawChunk<A, UP, true>, L) -> Option<R>,
1082 ) -> Result<R, B> {
1083 unsafe {
1084 let new_chunk: RawChunk<A, UP, true> = if let Some(mut chunk) = self.chunk.get().guaranteed_allocated() {
1085 while let Some(next_chunk) = chunk.next() {
1086 chunk = next_chunk;
1087
1088 // We don't reset the chunk position when we leave a scope, so we need to do it here.
1089 chunk.reset();
1090
1091 self.chunk.set(chunk.coerce_guaranteed_allocated());
1092
1093 if let Some(ptr) = f(chunk, layout) {
1094 return Ok(ptr);
1095 }
1096 }
1097
1098 // there is no chunk that fits, we need a new chunk
1099 chunk.append_for(*layout)
1100 } else {
1101 // When this bump allocator is unallocated, `A` is guaranteed to implement `Default`,
1102 // `default_or_panic` will not panic.
1103 let allocator = A::default_or_panic();
1104
1105 RawChunk::new_in(
1106 ChunkSize::from_capacity(*layout).ok_or_else(B::capacity_overflow)?,
1107 None,
1108 allocator,
1109 )
1110 }?;
1111
1112 self.chunk.set(new_chunk.coerce_guaranteed_allocated());
1113
1114 match f(new_chunk, layout) {
1115 Some(ptr) => Ok(ptr),
1116 _ => {
1117 // SAFETY: We just appended a chunk for that specific layout, it must have enough space.
1118 // We don't panic here so we don't produce any panic code when using `try_` apis.
1119 // We check for that in `test-fallibility`.
1120 core::hint::unreachable_unchecked()
1121 }
1122 }
1123 }
1124 }
1125}
1126
1127impl<A, const MIN_ALIGN: usize, const UP: bool, const GUARANTEED_ALLOCATED: bool, const DEALLOCATES: bool> NoDrop
1128 for BumpScope<'_, A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES>
1129{
1130}
1131
1132/// Methods to allocate. Available as fallible or infallible.
1133impl<'a, A, const MIN_ALIGN: usize, const UP: bool, const GUARANTEED_ALLOCATED: bool, const DEALLOCATES: bool>
1134 BumpScope<'a, A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES>
1135where
1136 MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
1137 A: BaseAllocator<GUARANTEED_ALLOCATED>,
1138{
1139 /// Allocate an object.
1140 ///
1141 /// # Panics
1142 /// Panics if the allocation fails.
1143 ///
1144 /// # Examples
1145 /// ```
1146 /// # use bump_scope::Bump;
1147 /// # let bump: Bump = Bump::new();
1148 /// let allocated = bump.alloc(123);
1149 /// assert_eq!(allocated, 123);
1150 /// ```
1151 #[inline(always)]
1152 #[cfg(feature = "panic-on-alloc")]
1153 pub fn alloc<T>(&self, value: T) -> BumpBox<'a, T> {
1154 panic_on_error(self.generic_alloc(value))
1155 }
1156
1157 /// Allocate an object.
1158 ///
1159 /// # Errors
1160 /// Errors if the allocation fails.
1161 ///
1162 /// # Examples
1163 /// ```
1164 /// # use bump_scope::Bump;
1165 /// # let bump: Bump = Bump::try_new()?;
1166 /// let allocated = bump.try_alloc(123)?;
1167 /// assert_eq!(allocated, 123);
1168 /// # Ok::<(), bump_scope::alloc::AllocError>(())
1169 /// ```
1170 #[inline(always)]
1171 pub fn try_alloc<T>(&self, value: T) -> Result<BumpBox<'a, T>, AllocError> {
1172 self.generic_alloc(value)
1173 }
1174
1175 #[inline(always)]
1176 pub(crate) fn generic_alloc<B: ErrorBehavior, T>(&self, value: T) -> Result<BumpBox<'a, T>, B> {
1177 self.generic_alloc_with(|| value)
1178 }
1179
1180 /// Allocates space for an object, then calls `f` to produce the
1181 /// value to be put in that place.
1182 ///
1183 /// In some cases this could be more performant than `alloc(f())` because it
1184 /// permits the compiler to directly place `T` in the allocated memory instead of
1185 /// constructing it on the stack and copying it over.
1186 ///
1187 /// # Panics
1188 /// Panics if the allocation fails.
1189 ///
1190 /// # Examples
1191 /// ```
1192 /// # use bump_scope::Bump;
1193 /// # let bump: Bump = Bump::new();
1194 /// let allocated = bump.alloc_with(|| 123);
1195 /// assert_eq!(allocated, 123);
1196 /// ```
1197 #[inline(always)]
1198 #[cfg(feature = "panic-on-alloc")]
1199 pub fn alloc_with<T>(&self, f: impl FnOnce() -> T) -> BumpBox<'a, T> {
1200 panic_on_error(self.generic_alloc_with(f))
1201 }
1202
1203 /// Allocates space for an object, then calls `f` to produce the
1204 /// value to be put in that place.
1205 ///
1206 /// In some cases this could be more performant than `try_alloc(f())` because it
1207 /// permits the compiler to directly place `T` in the allocated memory instead of
1208 /// constructing it on the stack and copying it over.
1209 ///
1210 /// # Errors
1211 /// Errors if the allocation fails.
1212 ///
1213 /// # Examples
1214 /// ```
1215 /// # use bump_scope::Bump;
1216 /// # let bump: Bump = Bump::try_new()?;
1217 /// let allocated = bump.try_alloc_with(|| 123)?;
1218 /// assert_eq!(allocated, 123);
1219 /// # Ok::<(), bump_scope::alloc::AllocError>(())
1220 /// ```
1221 #[inline(always)]
1222 pub fn try_alloc_with<T>(&self, f: impl FnOnce() -> T) -> Result<BumpBox<'a, T>, AllocError> {
1223 self.generic_alloc_with(f)
1224 }
1225
1226 #[inline(always)]
1227 pub(crate) fn generic_alloc_with<B: ErrorBehavior, T>(&self, f: impl FnOnce() -> T) -> Result<BumpBox<'a, T>, B> {
1228 Ok(self.generic_alloc_uninit()?.init(f()))
1229 }
1230
1231 /// Allocate an object with its default value.
1232 ///
1233 /// This is equivalent to <code>[alloc_with](Self::alloc_with)(T::default)</code>.
1234 ///
1235 /// # Panics
1236 /// Panics if the allocation fails.
1237 ///
1238 /// # Examples
1239 /// ```
1240 /// # use bump_scope::Bump;
1241 /// # let bump: Bump = Bump::new();
1242 /// let allocated = bump.alloc_default::<i32>();
1243 /// assert_eq!(allocated, 0);
1244 /// ```
1245 #[inline(always)]
1246 #[cfg(feature = "panic-on-alloc")]
1247 pub fn alloc_default<T: Default>(&self) -> BumpBox<'a, T> {
1248 panic_on_error(self.generic_alloc_default())
1249 }
1250
1251 /// Allocate an object with its default value.
1252 ///
1253 /// This is equivalent to <code>[try_alloc_with](Self::try_alloc_with)(T::default)</code>.
1254 ///
1255 /// # Errors
1256 /// Errors if the allocation fails.
1257 ///
1258 /// # Examples
1259 /// ```
1260 /// # use bump_scope::Bump;
1261 /// # let bump: Bump = Bump::try_new()?;
1262 /// let allocated = bump.try_alloc_default()?;
1263 /// assert_eq!(allocated, 0);
1264 /// # Ok::<(), bump_scope::alloc::AllocError>(())
1265 /// ```
1266 #[inline(always)]
1267 pub fn try_alloc_default<T: Default>(&self) -> Result<BumpBox<'a, T>, AllocError> {
1268 self.generic_alloc_default()
1269 }
1270
1271 #[inline(always)]
1272 pub(crate) fn generic_alloc_default<B: ErrorBehavior, T: Default>(&self) -> Result<BumpBox<'a, T>, B> {
1273 self.generic_alloc_with(Default::default)
1274 }
1275
1276 /// Allocate an object by cloning it.
1277 ///
1278 /// Unlike `alloc(value.clone())` this method also works for dynamically-sized types.
1279 ///
1280 /// # Panics
1281 /// Panics if the allocation fails.
1282 ///
1283 /// # Examples
1284 ///
1285 /// Allocate a `slice`, `str`, `CStr`, `Path`:
1286 #[cfg_attr(feature = "nightly-clone-to-uninit", doc = "```")]
1287 #[cfg_attr(not(feature = "nightly-clone-to-uninit"), doc = "```ignore")]
1288 /// #![feature(clone_to_uninit)]
1289 ///
1290 /// use std::path::Path;
1291 /// # use bump_scope::Bump;
1292 /// # let bump: Bump = Bump::new();
1293 ///
1294 /// let cloned = bump.alloc_clone(&[1, 2, 3]);
1295 /// assert_eq!(cloned, &[1, 2, 3]);
1296 ///
1297 /// let cloned = bump.alloc_clone("foo");
1298 /// assert_eq!(cloned, "foo");
1299 ///
1300 /// let cloned = bump.alloc_clone(c"foo");
1301 /// assert_eq!(cloned, c"foo");
1302 ///
1303 /// let cloned = bump.alloc_clone(Path::new("foo"));
1304 /// assert_eq!(cloned, Path::new("foo"));
1305 /// ```
1306 ///
1307 /// Allocate a trait object:
1308 #[cfg_attr(feature = "nightly-clone-to-uninit", doc = "```")]
1309 #[cfg_attr(not(feature = "nightly-clone-to-uninit"), doc = "```ignore")]
1310 /// #![feature(clone_to_uninit)]
1311 ///
1312 /// use core::clone::CloneToUninit;
1313 /// # use bump_scope::Bump;
1314 ///
1315 /// trait FnClone: Fn() -> String + CloneToUninit {}
1316 /// impl<T: ?Sized + Fn() -> String + CloneToUninit> FnClone for T {}
1317 ///
1318 /// // the closure references a local variable
1319 /// let reference = &String::from("Hello,");
1320 ///
1321 /// // and owns a string that it will have to clone
1322 /// let value = String::from("world!");
1323 ///
1324 /// let closure = move || format!("{reference} {value}");
1325 /// let object: &dyn FnClone = &closure;
1326 ///
1327 /// assert_eq!(object(), "Hello, world!");
1328 ///
1329 /// let bump: Bump = Bump::new();
1330 /// let object_clone = bump.alloc_clone(object);
1331 ///
1332 /// assert_eq!(object_clone(), "Hello, world!");
1333 /// ```
1334 #[cfg(feature = "nightly-clone-to-uninit")]
1335 pub fn alloc_clone<T: CloneToUninit + ?Sized>(&self, value: &T) -> BumpBox<'a, T> {
1336 panic_on_error(self.generic_alloc_clone(value))
1337 }
1338
1339 /// Allocate an object by cloning it.
1340 ///
1341 /// Unlike `alloc(value.clone())` this method also works for dynamically-sized types.
1342 ///
1343 /// # Errors
1344 /// Errors if the allocation fails.
1345 ///
1346 /// # Examples
1347 ///
1348 /// Allocate a `slice`, `str`, `CStr`, `Path`:
1349 #[cfg_attr(feature = "nightly-clone-to-uninit", doc = "```")]
1350 #[cfg_attr(not(feature = "nightly-clone-to-uninit"), doc = "```ignore")]
1351 /// #![feature(clone_to_uninit)]
1352 ///
1353 /// use std::path::Path;
1354 /// # use bump_scope::Bump;
1355 /// # let bump: Bump = Bump::try_new()?;
1356 ///
1357 /// let cloned = bump.try_alloc_clone(&[1, 2, 3])?;
1358 /// assert_eq!(cloned, &[1, 2, 3]);
1359 ///
1360 /// let cloned = bump.try_alloc_clone("foo")?;
1361 /// assert_eq!(cloned, "foo");
1362 ///
1363 /// let cloned = bump.try_alloc_clone(c"foo")?;
1364 /// assert_eq!(cloned, c"foo");
1365 ///
1366 /// let cloned = bump.try_alloc_clone(Path::new("foo"))?;
1367 /// assert_eq!(cloned, Path::new("foo"));
1368 /// # Ok::<(), bump_scope::alloc::AllocError>(())
1369 /// ```
1370 ///
1371 /// Allocate a trait object:
1372 #[cfg_attr(feature = "nightly-clone-to-uninit", doc = "```")]
1373 #[cfg_attr(not(feature = "nightly-clone-to-uninit"), doc = "```ignore")]
1374 /// #![feature(clone_to_uninit)]
1375 ///
1376 /// use core::clone::CloneToUninit;
1377 /// # use bump_scope::Bump;
1378 ///
1379 /// trait FnClone: Fn() -> String + CloneToUninit {}
1380 /// impl<T: ?Sized + Fn() -> String + CloneToUninit> FnClone for T {}
1381 ///
1382 /// // the closure references a local variable
1383 /// let reference = &String::from("Hello,");
1384 ///
1385 /// // and owns a string that it will have to clone
1386 /// let value = String::from("world!");
1387 ///
1388 /// let closure = move || format!("{reference} {value}");
1389 /// let object: &dyn FnClone = &closure;
1390 ///
1391 /// assert_eq!(object(), "Hello, world!");
1392 ///
1393 /// let bump: Bump = Bump::try_new()?;
1394 /// let object_clone = bump.try_alloc_clone(object)?;
1395 ///
1396 /// assert_eq!(object_clone(), "Hello, world!");
1397 /// # Ok::<(), bump_scope::alloc::AllocError>(())
1398 /// ```
1399 #[cfg(feature = "nightly-clone-to-uninit")]
1400 pub fn try_alloc_clone<T: CloneToUninit + ?Sized>(&self, value: &T) -> Result<BumpBox<'a, T>, AllocError> {
1401 self.generic_alloc_clone(value)
1402 }
1403
1404 #[cfg(feature = "nightly-clone-to-uninit")]
1405 pub(crate) fn generic_alloc_clone<B: ErrorBehavior, T: CloneToUninit + ?Sized>(
1406 &self,
1407 value: &T,
1408 ) -> Result<BumpBox<'a, T>, B> {
1409 let data = self.generic_alloc_layout(Layout::for_value(value))?;
1410 let metadata = ptr::metadata(value);
1411
1412 unsafe {
1413 value.clone_to_uninit(data.as_ptr());
1414 let ptr = ptr::from_raw_parts_mut(data.as_ptr(), metadata);
1415 let ptr = NonNull::new_unchecked(ptr);
1416 Ok(BumpBox::from_raw(ptr))
1417 }
1418 }
1419
1420 /// Allocate a slice and fill it by moving elements from an existing slice.
1421 ///
1422 /// # Panics
1423 /// Panics if the allocation fails.
1424 ///
1425 /// # Examples
1426 /// ```
1427 /// # use bump_scope::Bump;
1428 /// # let bump: Bump = Bump::new();
1429 /// // by value
1430 /// let a = bump.alloc_slice_move([1, 2]);
1431 /// let b = bump.alloc_slice_move(vec![3, 4]);
1432 /// let c = bump.alloc_slice_move(bump.alloc_iter(5..=6));
1433 ///
1434 /// // by mutable reference
1435 /// let mut other = vec![7, 8];
1436 /// let d = bump.alloc_slice_move(&mut other);
1437 /// assert!(other.is_empty());
1438 ///
1439 /// assert_eq!(a, [1, 2]);
1440 /// assert_eq!(b, [3, 4]);
1441 /// assert_eq!(c, [5, 6]);
1442 /// assert_eq!(d, [7, 8]);
1443 /// ```
1444 #[inline(always)]
1445 #[cfg(feature = "panic-on-alloc")]
1446 pub fn alloc_slice_move<T>(&self, slice: impl OwnedSlice<Item = T>) -> BumpBox<'a, [T]> {
1447 panic_on_error(self.generic_alloc_slice_move(slice))
1448 }
1449
1450 /// Allocate a slice and fill it by moving elements from an existing slice.
1451 ///
1452 /// # Errors
1453 /// Errors if the allocation fails.
1454 ///
1455 /// # Examples
1456 /// ```
1457 /// # use bump_scope::Bump;
1458 /// # let bump: Bump = Bump::try_new()?;
1459 /// // by value
1460 /// let a = bump.try_alloc_slice_move([1, 2])?;
1461 /// let b = bump.try_alloc_slice_move(vec![3, 4])?;
1462 /// let c = bump.try_alloc_slice_move(bump.alloc_iter(5..=6))?;
1463 ///
1464 /// // by mutable reference
1465 /// let mut other = vec![7, 8];
1466 /// let d = bump.try_alloc_slice_move(&mut other)?;
1467 /// assert!(other.is_empty());
1468 ///
1469 /// assert_eq!(a, [1, 2]);
1470 /// assert_eq!(b, [3, 4]);
1471 /// assert_eq!(c, [5, 6]);
1472 /// assert_eq!(d, [7, 8]);
1473 /// # Ok::<(), bump_scope::alloc::AllocError>(())
1474 /// ```
1475 #[inline(always)]
1476 pub fn try_alloc_slice_move<T>(&self, slice: impl OwnedSlice<Item = T>) -> Result<BumpBox<'a, [T]>, AllocError> {
1477 self.generic_alloc_slice_move(slice)
1478 }
1479
1480 #[inline(always)]
1481 pub(crate) fn generic_alloc_slice_move<B: ErrorBehavior, T>(
1482 &self,
1483 slice: impl OwnedSlice<Item = T>,
1484 ) -> Result<BumpBox<'a, [T]>, B> {
1485 Ok(BumpVec::generic_from_owned_slice_in(slice, self)?.into_boxed_slice())
1486 }
1487
1488 /// Allocate a slice and fill it by `Copy`ing elements from an existing slice.
1489 ///
1490 /// # Panics
1491 /// Panics if the allocation fails.
1492 ///
1493 /// # Examples
1494 /// ```
1495 /// # use bump_scope::Bump;
1496 /// # let bump: Bump = Bump::new();
1497 /// let allocated = bump.alloc_slice_copy(&[1, 2, 3]);
1498 /// assert_eq!(allocated, [1, 2, 3]);
1499 /// ```
1500 #[inline(always)]
1501 #[cfg(feature = "panic-on-alloc")]
1502 pub fn alloc_slice_copy<T: Copy>(&self, slice: &[T]) -> BumpBox<'a, [T]> {
1503 panic_on_error(self.generic_alloc_slice_copy(slice))
1504 }
1505
1506 /// Allocate a slice and fill it by `Copy`ing elements from an existing slice.
1507 ///
1508 /// # Errors
1509 /// Errors if the allocation fails.
1510 ///
1511 /// # Examples
1512 /// ```
1513 /// # use bump_scope::Bump;
1514 /// # let bump: Bump = Bump::try_new()?;
1515 /// let allocated = bump.try_alloc_slice_copy(&[1, 2, 3])?;
1516 /// assert_eq!(allocated, [1, 2, 3]);
1517 /// # Ok::<(), bump_scope::alloc::AllocError>(())
1518 /// ```
1519 #[inline(always)]
1520 pub fn try_alloc_slice_copy<T: Copy>(&self, slice: &[T]) -> Result<BumpBox<'a, [T]>, AllocError> {
1521 self.generic_alloc_slice_copy(slice)
1522 }
1523
1524 #[inline(always)]
1525 pub(crate) fn generic_alloc_slice_copy<B: ErrorBehavior, T: Copy>(&self, slice: &[T]) -> Result<BumpBox<'a, [T]>, B> {
1526 if T::IS_ZST {
1527 return Ok(BumpBox::zst_slice_clone(slice));
1528 }
1529
1530 let len = slice.len();
1531 let src = slice.as_ptr();
1532 let dst = self.do_alloc_slice_for(slice)?;
1533
1534 unsafe {
1535 core::ptr::copy_nonoverlapping(src, dst.as_ptr(), len);
1536 Ok(BumpBox::from_raw(NonNull::slice_from_raw_parts(dst, len)))
1537 }
1538 }
1539
1540 /// Allocate a slice and fill it by `Clone`ing elements from an existing slice.
1541 ///
1542 /// # Panics
1543 /// Panics if the allocation fails.
1544 ///
1545 /// # Examples
1546 /// ```
1547 /// # use bump_scope::Bump;
1548 /// # let bump: Bump = Bump::new();
1549 /// let allocated = bump.alloc_slice_clone(&[String::from("a"), String::from("b")]);
1550 /// assert_eq!(allocated, [String::from("a"), String::from("b")]);
1551 /// ```
1552 #[inline(always)]
1553 #[cfg(feature = "panic-on-alloc")]
1554 pub fn alloc_slice_clone<T: Clone>(&self, slice: &[T]) -> BumpBox<'a, [T]> {
1555 panic_on_error(self.generic_alloc_slice_clone(slice))
1556 }
1557
1558 /// Allocate a slice and fill it by `Clone`ing elements from an existing slice.
1559 ///
1560 /// # Errors
1561 /// Errors if the allocation fails.
1562 ///
1563 /// # Examples
1564 /// ```
1565 /// # use bump_scope::Bump;
1566 /// # let bump: Bump = Bump::try_new()?;
1567 /// let allocated = bump.try_alloc_slice_clone(&[String::from("a"), String::from("b")])?;
1568 /// assert_eq!(allocated, [String::from("a"), String::from("b")]);
1569 /// # Ok::<(), bump_scope::alloc::AllocError>(())
1570 /// ```
1571 #[inline(always)]
1572 pub fn try_alloc_slice_clone<T: Clone>(&self, slice: &[T]) -> Result<BumpBox<'a, [T]>, AllocError> {
1573 self.generic_alloc_slice_clone(slice)
1574 }
1575
1576 #[inline(always)]
1577 pub(crate) fn generic_alloc_slice_clone<B: ErrorBehavior, T: Clone>(&self, slice: &[T]) -> Result<BumpBox<'a, [T]>, B> {
1578 if T::IS_ZST {
1579 return Ok(BumpBox::zst_slice_clone(slice));
1580 }
1581
1582 Ok(self.generic_alloc_uninit_slice_for(slice)?.init_clone(slice))
1583 }
1584
1585 /// Allocate a slice and fill it with elements by cloning `value`.
1586 ///
1587 /// # Panics
1588 /// Panics if the allocation fails.
1589 ///
1590 /// # Examples
1591 /// ```
1592 /// # use bump_scope::Bump;
1593 /// # let bump: Bump = Bump::new();
1594 /// let allocated = bump.alloc_slice_fill(3, "ho");
1595 /// assert_eq!(allocated, ["ho", "ho", "ho"]);
1596 /// ```
1597 #[inline(always)]
1598 #[cfg(feature = "panic-on-alloc")]
1599 pub fn alloc_slice_fill<T: Clone>(&self, len: usize, value: T) -> BumpBox<'a, [T]> {
1600 panic_on_error(self.generic_alloc_slice_fill(len, value))
1601 }
1602
1603 /// Allocate a slice and fill it with elements by cloning `value`.
1604 ///
1605 /// # Errors
1606 /// Errors if the allocation fails.
1607 ///
1608 /// # Examples
1609 /// ```
1610 /// # use bump_scope::Bump;
1611 /// # let bump: Bump = Bump::try_new()?;
1612 /// let allocated = bump.try_alloc_slice_fill(3, "ho")?;
1613 /// assert_eq!(allocated, ["ho", "ho", "ho"]);
1614 /// # Ok::<(), bump_scope::alloc::AllocError>(())
1615 /// ```
1616 #[inline(always)]
1617 pub fn try_alloc_slice_fill<T: Clone>(&self, len: usize, value: T) -> Result<BumpBox<'a, [T]>, AllocError> {
1618 self.generic_alloc_slice_fill(len, value)
1619 }
1620
1621 #[inline(always)]
1622 pub(crate) fn generic_alloc_slice_fill<B: ErrorBehavior, T: Clone>(
1623 &self,
1624 len: usize,
1625 value: T,
1626 ) -> Result<BumpBox<'a, [T]>, B> {
1627 if T::IS_ZST {
1628 return Ok(BumpBox::zst_slice_fill(len, value));
1629 }
1630
1631 Ok(self.generic_alloc_uninit_slice(len)?.init_fill(value))
1632 }
1633
1634 /// Allocates a slice by fill it with elements returned by calling a closure repeatedly.
1635 ///
1636 /// This method uses a closure to create new values. If you'd rather
1637 /// [`Clone`] a given value, use [`alloc_slice_fill`](Self::alloc_slice_fill). If you want to use the [`Default`]
1638 /// trait to generate values, you can pass [`Default::default`] as the
1639 /// argument.
1640 ///
1641 /// # Panics
1642 /// Panics if the allocation fails.
1643 ///
1644 /// # Examples
1645 /// ```
1646 /// # use bump_scope::Bump;
1647 /// # let bump: Bump = Bump::new();
1648 /// let allocated = bump.alloc_slice_fill_with::<i32>(3, Default::default);
1649 /// assert_eq!(allocated, [0, 0, 0]);
1650 /// ```
1651 #[inline(always)]
1652 #[cfg(feature = "panic-on-alloc")]
1653 pub fn alloc_slice_fill_with<T>(&self, len: usize, f: impl FnMut() -> T) -> BumpBox<'a, [T]> {
1654 panic_on_error(self.generic_alloc_slice_fill_with(len, f))
1655 }
1656
1657 /// Allocates a slice by fill it with elements returned by calling a closure repeatedly.
1658 ///
1659 /// This method uses a closure to create new values. If you'd rather
1660 /// [`Clone`] a given value, use [`try_alloc_slice_fill`](Self::try_alloc_slice_fill). If you want to use the [`Default`]
1661 /// trait to generate values, you can pass [`Default::default`] as the
1662 /// argument.
1663 ///
1664 /// # Errors
1665 /// Errors if the allocation fails.
1666 ///
1667 /// # Examples
1668 /// ```
1669 /// # use bump_scope::Bump;
1670 /// # let bump: Bump = Bump::try_new()?;
1671 /// let allocated = bump.try_alloc_slice_fill_with::<i32>(3, Default::default)?;
1672 /// assert_eq!(allocated, [0, 0, 0]);
1673 /// # Ok::<(), bump_scope::alloc::AllocError>(())
1674 /// ```
1675 #[inline(always)]
1676 pub fn try_alloc_slice_fill_with<T>(&self, len: usize, f: impl FnMut() -> T) -> Result<BumpBox<'a, [T]>, AllocError> {
1677 self.generic_alloc_slice_fill_with(len, f)
1678 }
1679
1680 #[inline(always)]
1681 pub(crate) fn generic_alloc_slice_fill_with<B: ErrorBehavior, T>(
1682 &self,
1683 len: usize,
1684 f: impl FnMut() -> T,
1685 ) -> Result<BumpBox<'a, [T]>, B> {
1686 if T::IS_ZST {
1687 return Ok(BumpBox::zst_slice_fill_with(len, f));
1688 }
1689
1690 Ok(self.generic_alloc_uninit_slice(len)?.init_fill_with(f))
1691 }
1692
1693 /// Allocate a `str`.
1694 ///
1695 /// # Panics
1696 /// Panics if the allocation fails.
1697 ///
1698 /// # Examples
1699 /// ```
1700 /// # use bump_scope::Bump;
1701 /// # let bump: Bump = Bump::new();
1702 /// let allocated = bump.alloc_str("Hello, world!");
1703 /// assert_eq!(allocated, "Hello, world!");
1704 /// ```
1705 #[inline(always)]
1706 #[cfg(feature = "panic-on-alloc")]
1707 pub fn alloc_str(&self, src: &str) -> BumpBox<'a, str> {
1708 panic_on_error(self.generic_alloc_str(src))
1709 }
1710
1711 /// Allocate a `str`.
1712 ///
1713 /// # Errors
1714 /// Errors if the allocation fails.
1715 ///
1716 /// # Examples
1717 /// ```
1718 /// # use bump_scope::Bump;
1719 /// # let bump: Bump = Bump::try_new()?;
1720 /// let allocated = bump.try_alloc_str("Hello, world!")?;
1721 /// assert_eq!(allocated, "Hello, world!");
1722 /// # Ok::<(), bump_scope::alloc::AllocError>(())
1723 /// ```
1724 #[inline(always)]
1725 pub fn try_alloc_str(&self, src: &str) -> Result<BumpBox<'a, str>, AllocError> {
1726 self.generic_alloc_str(src)
1727 }
1728
1729 #[inline(always)]
1730 pub(crate) fn generic_alloc_str<B: ErrorBehavior>(&self, src: &str) -> Result<BumpBox<'a, str>, B> {
1731 let slice = self.generic_alloc_slice_copy(src.as_bytes())?;
1732
1733 // SAFETY: input is `str` so this is too
1734 Ok(unsafe { BumpBox::from_utf8_unchecked(slice) })
1735 }
1736
1737 /// Allocate a `str` from format arguments.
1738 ///
1739 /// If you have a `&mut self` you can use [`alloc_fmt_mut`](Self::alloc_fmt_mut)
1740 /// instead for better performance.
1741 ///
1742 /// # Panics
1743 /// Panics if the allocation fails.
1744 ///
1745 /// This technically also panics if the `fmt()` implementation returned an Error,
1746 /// but since [`fmt()` implementors should only error when writing to the stream fails](core::fmt::Error),
1747 /// that should be equivalent to an allocation failure.
1748 ///
1749 /// # Examples
1750 /// ```
1751 /// # use bump_scope::Bump;
1752 /// # let bump: Bump = Bump::new();
1753 /// let one = 1;
1754 /// let two = 2;
1755 /// let string = bump.alloc_fmt(format_args!("{one} + {two} = {}", one + two));
1756 ///
1757 /// assert_eq!(string, "1 + 2 = 3");
1758 /// ```
1759 #[inline(always)]
1760 #[cfg(feature = "panic-on-alloc")]
1761 pub fn alloc_fmt(&self, args: fmt::Arguments) -> BumpBox<'a, str> {
1762 panic_on_error(self.generic_alloc_fmt(args))
1763 }
1764
1765 /// Allocate a `str` from format arguments.
1766 ///
1767 /// If you have a `&mut self` you can use [`try_alloc_fmt_mut`](Self::try_alloc_fmt_mut)
1768 /// instead for better performance.
1769 ///
1770 /// # Errors
1771 /// Errors if the allocation fails.
1772 ///
1773 /// This technically also errors if the `fmt()` implementation returned an Error,
1774 /// but since [`fmt()` implementors should only error when writing to the stream fails](core::fmt::Error),
1775 /// that should be equivalent to an allocation failure.
1776 ///
1777 /// # Examples
1778 /// ```
1779 /// # use bump_scope::Bump;
1780 /// # let bump: Bump = Bump::try_new()?;
1781 /// let one = 1;
1782 /// let two = 2;
1783 /// let string = bump.try_alloc_fmt(format_args!("{one} + {two} = {}", one + two))?;
1784 ///
1785 /// assert_eq!(string, "1 + 2 = 3");
1786 /// # Ok::<(), bump_scope::alloc::AllocError>(())
1787 /// ```
1788 #[inline(always)]
1789 pub fn try_alloc_fmt(&self, args: fmt::Arguments) -> Result<BumpBox<'a, str>, AllocError> {
1790 self.generic_alloc_fmt(args)
1791 }
1792
1793 #[inline(always)]
1794 pub(crate) fn generic_alloc_fmt<B: ErrorBehavior>(&self, args: fmt::Arguments) -> Result<BumpBox<'a, str>, B> {
1795 if let Some(string) = args.as_str() {
1796 return self.generic_alloc_str(string);
1797 }
1798
1799 let mut string = BumpString::new_in(self);
1800 string.generic_write_fmt(args)?;
1801 Ok(string.into_boxed_str())
1802 }
1803
1804 /// Allocate a `str` from format arguments.
1805 ///
1806 /// This function is designed as a performance improvement over [`alloc_fmt`](Self::alloc_fmt).
1807 /// By taking `self` as `&mut`, it can use the entire remaining chunk space as the capacity
1808 /// for the temporary string buffer used for the allocation. As a result, that string buffer rarely needs to grow.
1809 ///
1810 /// # Panics
1811 /// Panics if the allocation fails.
1812 ///
1813 /// This technically also panics if the `fmt()` implementation returned an Error,
1814 /// but since [`fmt()` implementors should only error when writing to the stream fails](core::fmt::Error),
1815 /// that should be equivalent to an allocation failure.
1816 ///
1817 /// # Examples
1818 /// ```
1819 /// # use bump_scope::Bump;
1820 /// # let mut bump: Bump = Bump::new();
1821 /// let one = 1;
1822 /// let two = 2;
1823 /// let string = bump.alloc_fmt_mut(format_args!("{one} + {two} = {}", one + two));
1824 ///
1825 /// assert_eq!(string, "1 + 2 = 3");
1826 /// ```
1827 #[inline(always)]
1828 #[cfg(feature = "panic-on-alloc")]
1829 pub fn alloc_fmt_mut(&mut self, args: fmt::Arguments) -> BumpBox<'a, str> {
1830 panic_on_error(self.generic_alloc_fmt_mut(args))
1831 }
1832
1833 /// Allocate a `str` from format arguments.
1834 ///
1835 /// This function is designed as a performance improvement over [`try_alloc_fmt`](Self::try_alloc_fmt).
1836 /// By taking `self` as `&mut`, it can use the entire remaining chunk space as the capacity
1837 /// for the temporary string buffer used for the allocation. As a result, that string buffer rarely needs to grow.
1838 ///
1839 /// # Errors
1840 /// Errors if the allocation fails.
1841 ///
1842 /// This technically also errors if the `fmt()` implementation returned an Error,
1843 /// but since [`fmt()` implementors should only error when writing to the stream fails](core::fmt::Error),
1844 /// that should be equivalent to an allocation failure.
1845 ///
1846 /// # Examples
1847 /// ```
1848 /// # use bump_scope::Bump;
1849 /// # let mut bump: Bump = Bump::try_new()?;
1850 /// let one = 1;
1851 /// let two = 2;
1852 /// let string = bump.try_alloc_fmt_mut(format_args!("{one} + {two} = {}", one + two))?;
1853 ///
1854 /// assert_eq!(string, "1 + 2 = 3");
1855 /// # Ok::<(), bump_scope::alloc::AllocError>(())
1856 /// ```
1857 #[inline(always)]
1858 pub fn try_alloc_fmt_mut(&mut self, args: fmt::Arguments) -> Result<BumpBox<'a, str>, AllocError> {
1859 self.generic_alloc_fmt_mut(args)
1860 }
1861
1862 #[inline(always)]
1863 pub(crate) fn generic_alloc_fmt_mut<B: ErrorBehavior>(&mut self, args: fmt::Arguments) -> Result<BumpBox<'a, str>, B> {
1864 if let Some(string) = args.as_str() {
1865 return self.generic_alloc_str(string);
1866 }
1867
1868 let mut string = MutBumpString::new_in(self);
1869 string.generic_write_fmt(args)?;
1870 Ok(string.into_boxed_str())
1871 }
1872
1873 /// Allocate a `CStr`.
1874 ///
1875 /// # Panics
1876 /// Panics if the allocation fails.
1877 ///
1878 /// # Examples
1879 /// ```
1880 /// # use bump_scope::Bump;
1881 /// # let bump: Bump = Bump::new();
1882 /// let allocated = bump.alloc_cstr(c"Hello, world!");
1883 /// assert_eq!(allocated, c"Hello, world!");
1884 /// ```
1885 #[inline(always)]
1886 #[cfg(feature = "panic-on-alloc")]
1887 pub fn alloc_cstr(&self, src: &CStr) -> &'a CStr {
1888 panic_on_error(self.generic_alloc_cstr(src))
1889 }
1890
1891 /// Allocate a `CStr`.
1892 ///
1893 /// # Errors
1894 /// Errors if the allocation fails.
1895 ///
1896 /// # Examples
1897 /// ```
1898 /// # use bump_scope::Bump;
1899 /// # let bump: Bump = Bump::try_new()?;
1900 /// let allocated = bump.try_alloc_cstr(c"Hello, world!")?;
1901 /// assert_eq!(allocated, c"Hello, world!");
1902 /// # Ok::<(), bump_scope::alloc::AllocError>(())
1903 /// ```
1904 #[inline(always)]
1905 pub fn try_alloc_cstr(&self, src: &CStr) -> Result<&'a CStr, AllocError> {
1906 self.generic_alloc_cstr(src)
1907 }
1908
1909 #[inline(always)]
1910 pub(crate) fn generic_alloc_cstr<B: ErrorBehavior>(&self, src: &CStr) -> Result<&'a CStr, B> {
1911 let slice = self.generic_alloc_slice_copy(src.to_bytes_with_nul())?.into_ref();
1912
1913 // SAFETY: input is `CStr` so this is too
1914 Ok(unsafe { CStr::from_bytes_with_nul_unchecked(slice) })
1915 }
1916
1917 /// Allocate a `CStr` from a `str`.
1918 ///
1919 /// If `src` contains a `'\0'` then the `CStr` will stop at the first `'\0'`.
1920 ///
1921 /// # Panics
1922 /// Panics if the allocation fails.
1923 ///
1924 /// # Examples
1925 /// ```
1926 /// # use bump_scope::Bump;
1927 /// # let bump: Bump = Bump::new();
1928 /// let allocated = bump.alloc_cstr_from_str("Hello, world!");
1929 /// assert_eq!(allocated, c"Hello, world!");
1930 ///
1931 /// let allocated = bump.alloc_cstr_from_str("abc\0def");
1932 /// assert_eq!(allocated, c"abc");
1933 /// ```
1934 #[inline(always)]
1935 #[cfg(feature = "panic-on-alloc")]
1936 pub fn alloc_cstr_from_str(&self, src: &str) -> &'a CStr {
1937 panic_on_error(self.generic_alloc_cstr_from_str(src))
1938 }
1939
1940 /// Allocate a `CStr` from a `str`.
1941 ///
1942 /// If `src` contains a `'\0'` then the `CStr` will stop at the first `'\0'`.
1943 ///
1944 /// # Errors
1945 /// Errors if the allocation fails.
1946 ///
1947 /// # Examples
1948 /// ```
1949 /// # use bump_scope::Bump;
1950 /// # let bump: Bump = Bump::try_new()?;
1951 /// let allocated = bump.try_alloc_cstr_from_str("Hello, world!")?;
1952 /// assert_eq!(allocated, c"Hello, world!");
1953 ///
1954 /// let allocated = bump.try_alloc_cstr_from_str("abc\0def")?;
1955 /// assert_eq!(allocated, c"abc");
1956 /// # Ok::<(), bump_scope::alloc::AllocError>(())
1957 /// ```
1958 #[inline(always)]
1959 pub fn try_alloc_cstr_from_str(&self, src: &str) -> Result<&'a CStr, AllocError> {
1960 self.generic_alloc_cstr_from_str(src)
1961 }
1962
1963 #[inline(always)]
1964 pub(crate) fn generic_alloc_cstr_from_str<B: ErrorBehavior>(&self, src: &str) -> Result<&'a CStr, B> {
1965 let src = src.as_bytes();
1966
1967 if let Some(nul) = src.iter().position(|&c| c == b'\0') {
1968 let bytes_with_nul = unsafe { src.get_unchecked(..nul + 1) };
1969 let cstr = unsafe { CStr::from_bytes_with_nul_unchecked(bytes_with_nul) };
1970 self.generic_alloc_cstr(cstr)
1971 } else {
1972 // `src` contains no null
1973 let dst = self.do_alloc_slice(src.len() + 1)?;
1974
1975 unsafe {
1976 core::ptr::copy_nonoverlapping(src.as_ptr(), dst.as_ptr(), src.len());
1977 dst.as_ptr().add(src.len()).write(0);
1978
1979 let bytes = core::slice::from_raw_parts(dst.as_ptr(), src.len() + 1);
1980 Ok(CStr::from_bytes_with_nul_unchecked(bytes))
1981 }
1982 }
1983 }
1984
1985 /// Allocate a `CStr` from format arguments.
1986 ///
1987 /// If the string contains a `'\0'` then the `CStr` will stop at the first `'\0'`.
1988 ///
1989 /// If you have a `&mut self` you can use [`alloc_cstr_fmt_mut`](Self::alloc_cstr_fmt_mut)
1990 /// instead for better performance.
1991 ///
1992 /// # Panics
1993 /// Panics if the allocation fails.
1994 ///
1995 /// This technically also panics if the `fmt()` implementation returned an Error,
1996 /// but since [`fmt()` implementors should only error when writing to the stream fails](core::fmt::Error),
1997 /// that should be equivalent to an allocation failure.
1998 ///
1999 /// # Examples
2000 /// ```
2001 /// # use bump_scope::Bump;
2002 /// # let bump: Bump = Bump::new();
2003 /// let one = 1;
2004 /// let two = 2;
2005 /// let string = bump.alloc_cstr_fmt(format_args!("{one} + {two} = {}", one + two));
2006 /// assert_eq!(string, c"1 + 2 = 3");
2007 ///
2008 /// let one = bump.alloc_cstr_fmt(format_args!("{one}\0{two}"));
2009 /// assert_eq!(one, c"1");
2010 /// ```
2011 #[inline(always)]
2012 #[cfg(feature = "panic-on-alloc")]
2013 pub fn alloc_cstr_fmt(&self, args: fmt::Arguments) -> &'a CStr {
2014 panic_on_error(self.generic_alloc_cstr_fmt(args))
2015 }
2016
2017 /// Allocate a `CStr` from format arguments.
2018 ///
2019 /// If the string contains a `'\0'` then the `CStr` will stop at the first `'\0'`.
2020 ///
2021 /// If you have a `&mut self` you can use [`try_alloc_cstr_fmt_mut`](Self::try_alloc_cstr_fmt_mut)
2022 /// instead for better performance.
2023 ///
2024 /// # Errors
2025 /// Errors if the allocation fails.
2026 ///
2027 /// This technically also errors if the `fmt()` implementation returned an Error,
2028 /// but since [`fmt()` implementors should only error when writing to the stream fails](core::fmt::Error),
2029 /// that should be equivalent to an allocation failure.
2030 ///
2031 /// # Examples
2032 /// ```
2033 /// # use bump_scope::Bump;
2034 /// # let bump: Bump = Bump::try_new()?;
2035 /// let one = 1;
2036 /// let two = 2;
2037 /// let string = bump.try_alloc_cstr_fmt(format_args!("{one} + {two} = {}", one + two))?;
2038 /// assert_eq!(string, c"1 + 2 = 3");
2039 ///
2040 /// let one = bump.try_alloc_cstr_fmt(format_args!("{one}\0{two}"))?;
2041 /// assert_eq!(one, c"1");
2042 /// # Ok::<(), bump_scope::alloc::AllocError>(())
2043 /// ```
2044 #[inline(always)]
2045 pub fn try_alloc_cstr_fmt(&self, args: fmt::Arguments) -> Result<&'a CStr, AllocError> {
2046 self.generic_alloc_cstr_fmt(args)
2047 }
2048
2049 #[inline(always)]
2050 pub(crate) fn generic_alloc_cstr_fmt<B: ErrorBehavior>(&self, args: fmt::Arguments) -> Result<&'a CStr, B> {
2051 if let Some(string) = args.as_str() {
2052 return self.generic_alloc_cstr_from_str(string);
2053 }
2054
2055 let mut string = BumpString::new_in(self);
2056 string.generic_write_fmt(args)?;
2057 string.generic_into_cstr()
2058 }
2059
2060 /// Allocate a `CStr` from format arguments.
2061 ///
2062 /// If the string contains a `'\0'` then the `CStr` will stop at the first `'\0'`.
2063 ///
2064 /// This function is designed as a performance improvement over [`alloc_cstr_fmt`](Self::alloc_cstr_fmt).
2065 /// By taking `self` as `&mut`, it can use the entire remaining chunk space as the capacity
2066 /// for the temporary string buffer used for the allocation. As a result, that string buffer rarely needs to grow.
2067 ///
2068 /// # Panics
2069 /// Panics if the allocation fails.
2070 ///
2071 /// This technically also panics if the `fmt()` implementation returned an Error,
2072 /// but since [`fmt()` implementors should only error when writing to the stream fails](core::fmt::Error),
2073 /// that should be equivalent to an allocation failure.
2074 ///
2075 /// # Examples
2076 /// ```
2077 /// # use bump_scope::Bump;
2078 /// # let mut bump: Bump = Bump::new();
2079 /// let one = 1;
2080 /// let two = 2;
2081 /// let string = bump.alloc_cstr_fmt_mut(format_args!("{one} + {two} = {}", one + two));
2082 /// assert_eq!(string, c"1 + 2 = 3");
2083 ///
2084 /// let one = bump.alloc_cstr_fmt_mut(format_args!("{one}\0{two}"));
2085 /// assert_eq!(one, c"1");
2086 /// ```
2087 #[inline(always)]
2088 #[cfg(feature = "panic-on-alloc")]
2089 pub fn alloc_cstr_fmt_mut(&mut self, args: fmt::Arguments) -> &'a CStr {
2090 panic_on_error(self.generic_alloc_cstr_fmt_mut(args))
2091 }
2092
2093 /// Allocate a `CStr` from format arguments.
2094 ///
2095 /// If the string contains a `'\0'` then the `CStr` will stop at the first `'\0'`.
2096 ///
2097 /// This function is designed as a performance improvement over [`try_alloc_cstr_fmt`](Self::try_alloc_cstr_fmt).
2098 /// By taking `self` as `&mut`, it can use the entire remaining chunk space as the capacity
2099 /// for the temporary string buffer used for the allocation. As a result, that string buffer rarely needs to grow.
2100 ///
2101 /// # Errors
2102 /// Errors if the allocation fails.
2103 ///
2104 /// This technically also errors if the `fmt()` implementation returned an Error,
2105 /// but since [`fmt()` implementors should only error when writing to the stream fails](core::fmt::Error),
2106 /// that should be equivalent to an allocation failure.
2107 ///
2108 /// # Examples
2109 /// ```
2110 /// # use bump_scope::Bump;
2111 /// # let mut bump: Bump = Bump::try_new()?;
2112 /// let one = 1;
2113 /// let two = 2;
2114 /// let string = bump.try_alloc_cstr_fmt_mut(format_args!("{one} + {two} = {}", one + two))?;
2115 /// assert_eq!(string, c"1 + 2 = 3");
2116 ///
2117 /// let one = bump.try_alloc_cstr_fmt_mut(format_args!("{one}\0{two}"))?;
2118 /// assert_eq!(one, c"1");
2119 /// # Ok::<(), bump_scope::alloc::AllocError>(())
2120 /// ```
2121 #[inline(always)]
2122 pub fn try_alloc_cstr_fmt_mut(&mut self, args: fmt::Arguments) -> Result<&'a CStr, AllocError> {
2123 self.generic_alloc_cstr_fmt_mut(args)
2124 }
2125
2126 #[inline(always)]
2127 pub(crate) fn generic_alloc_cstr_fmt_mut<B: ErrorBehavior>(&mut self, args: fmt::Arguments) -> Result<&'a CStr, B> {
2128 if let Some(string) = args.as_str() {
2129 return self.generic_alloc_cstr_from_str(string);
2130 }
2131
2132 let mut string = MutBumpString::new_in(self);
2133 string.generic_write_fmt(args)?;
2134 string.generic_into_cstr()
2135 }
2136
2137 /// Allocate elements of an iterator into a slice.
2138 ///
2139 /// If you have an `impl ExactSizeIterator` then you can use [`alloc_iter_exact`] instead for better performance.
2140 ///
2141 /// If `iter` is not an `ExactSizeIterator` but you have a `&mut self` you can still get somewhat better performance by using [`alloc_iter_mut`].
2142 ///
2143 /// [`alloc_iter_exact`]: Self::alloc_iter_exact
2144 /// [`alloc_iter_mut`]: Self::alloc_iter_mut
2145 ///
2146 /// # Panics
2147 /// Panics if the allocation fails.
2148 ///
2149 /// # Examples
2150 /// ```
2151 /// # use bump_scope::Bump;
2152 /// # let bump: Bump = Bump::new();
2153 /// let slice = bump.alloc_iter([1, 2, 3]);
2154 /// assert_eq!(slice, [1, 2, 3]);
2155 /// ```
2156 #[inline(always)]
2157 #[cfg(feature = "panic-on-alloc")]
2158 pub fn alloc_iter<T>(&self, iter: impl IntoIterator<Item = T>) -> BumpBox<'a, [T]> {
2159 panic_on_error(self.generic_alloc_iter(iter))
2160 }
2161
2162 /// Allocate elements of an iterator into a slice.
2163 ///
2164 /// If you have an `impl ExactSizeIterator` then you can use [`try_alloc_iter_exact`] instead for better performance.
2165 ///
2166 /// If `iter` is not an `ExactSizeIterator` but you have a `&mut self` you can still get somewhat better performance by using [`try_alloc_iter_mut`].
2167 ///
2168 /// [`try_alloc_iter_exact`]: Self::try_alloc_iter_exact
2169 /// [`try_alloc_iter_mut`]: Self::try_alloc_iter_mut
2170 ///
2171 /// # Errors
2172 /// Errors if the allocation fails.
2173 ///
2174 /// # Examples
2175 /// ```
2176 /// # use bump_scope::Bump;
2177 /// # let bump: Bump = Bump::try_new()?;
2178 /// let slice = bump.try_alloc_iter([1, 2, 3])?;
2179 /// assert_eq!(slice, [1, 2, 3]);
2180 /// # Ok::<(), bump_scope::alloc::AllocError>(())
2181 /// ```
2182 #[inline(always)]
2183 pub fn try_alloc_iter<T>(&self, iter: impl IntoIterator<Item = T>) -> Result<BumpBox<'a, [T]>, AllocError> {
2184 self.generic_alloc_iter(iter)
2185 }
2186
2187 #[inline(always)]
2188 pub(crate) fn generic_alloc_iter<B: ErrorBehavior, T>(
2189 &self,
2190 iter: impl IntoIterator<Item = T>,
2191 ) -> Result<BumpBox<'a, [T]>, B> {
2192 let iter = iter.into_iter();
2193 let capacity = iter.size_hint().0;
2194
2195 let mut vec = BumpVec::<T, &Self>::generic_with_capacity_in(capacity, self)?;
2196
2197 for value in iter {
2198 vec.generic_push(value)?;
2199 }
2200
2201 Ok(vec.into_boxed_slice())
2202 }
2203
2204 /// Allocate elements of an `ExactSizeIterator` into a slice.
2205 ///
2206 /// # Panics
2207 /// Panics if the allocation fails.
2208 ///
2209 /// # Examples
2210 /// ```
2211 /// # use bump_scope::Bump;
2212 /// # let bump: Bump = Bump::new();
2213 /// let slice = bump.alloc_iter_exact([1, 2, 3]);
2214 /// assert_eq!(slice, [1, 2, 3]);
2215 /// ```
2216 #[inline(always)]
2217 #[cfg(feature = "panic-on-alloc")]
2218 pub fn alloc_iter_exact<T, I>(&self, iter: impl IntoIterator<Item = T, IntoIter = I>) -> BumpBox<'a, [T]>
2219 where
2220 I: ExactSizeIterator<Item = T>,
2221 {
2222 panic_on_error(self.generic_alloc_iter_exact(iter))
2223 }
2224
2225 /// Allocate elements of an `ExactSizeIterator` into a slice.
2226 ///
2227 /// # Errors
2228 /// Errors if the allocation fails.
2229 ///
2230 /// # Examples
2231 /// ```
2232 /// # use bump_scope::Bump;
2233 /// # let bump: Bump = Bump::try_new()?;
2234 /// let slice = bump.try_alloc_iter_exact([1, 2, 3])?;
2235 /// assert_eq!(slice, [1, 2, 3]);
2236 /// # Ok::<(), bump_scope::alloc::AllocError>(())
2237 /// ```
2238 #[inline(always)]
2239 pub fn try_alloc_iter_exact<T, I>(
2240 &self,
2241 iter: impl IntoIterator<Item = T, IntoIter = I>,
2242 ) -> Result<BumpBox<'a, [T]>, AllocError>
2243 where
2244 I: ExactSizeIterator<Item = T>,
2245 {
2246 self.generic_alloc_iter_exact(iter)
2247 }
2248
2249 #[inline(always)]
2250 pub(crate) fn generic_alloc_iter_exact<B: ErrorBehavior, T, I>(
2251 &self,
2252 iter: impl IntoIterator<Item = T, IntoIter = I>,
2253 ) -> Result<BumpBox<'a, [T]>, B>
2254 where
2255 I: ExactSizeIterator<Item = T>,
2256 {
2257 let mut iter = iter.into_iter();
2258 let len = iter.len();
2259
2260 let mut vec = BumpVec::<T, &Self>::generic_with_capacity_in(len, self)?;
2261
2262 while vec.len() != vec.capacity() {
2263 match iter.next() {
2264 // SAFETY: we checked above that `len != capacity`, so there is space
2265 Some(value) => unsafe { vec.push_unchecked(value) },
2266 None => break,
2267 }
2268 }
2269
2270 Ok(vec.into_fixed_vec().into_boxed_slice())
2271 }
2272
2273 /// Allocate elements of an iterator into a slice.
2274 ///
2275 /// This function is designed as a performance improvement over [`alloc_iter`](Self::alloc_iter).
2276 /// By taking `self` as `&mut`, it can use the entire remaining chunk space as the capacity
2277 /// for the temporary vector used for the allocation. As a result, that vector rarely needs to grow.
2278 ///
2279 /// When bumping downwards, prefer [`alloc_iter_mut_rev`](Self::alloc_iter_mut_rev) instead.
2280 ///
2281 /// # Panics
2282 /// Panics if the allocation fails.
2283 ///
2284 /// # Examples
2285 /// ```
2286 /// # use bump_scope::Bump;
2287 /// # let mut bump: Bump = Bump::new();
2288 /// let slice = bump.alloc_iter_mut([1, 2, 3]);
2289 /// assert_eq!(slice, [1, 2, 3]);
2290 /// ```
2291 #[inline(always)]
2292 #[cfg(feature = "panic-on-alloc")]
2293 pub fn alloc_iter_mut<T>(&mut self, iter: impl IntoIterator<Item = T>) -> BumpBox<'a, [T]> {
2294 panic_on_error(self.generic_alloc_iter_mut(iter))
2295 }
2296
2297 /// Allocate elements of an iterator into a slice.
2298 ///
2299 /// This function is designed as a performance improvement over [`try_alloc_iter`](Self::try_alloc_iter).
2300 /// By taking `self` as `&mut`, it can use the entire remaining chunk space as the capacity
2301 /// for the temporary vector used for the allocation. As a result, that vector rarely needs to grow.
2302 ///
2303 /// When bumping downwards, prefer [`alloc_iter_mut_rev`](Self::alloc_iter_mut_rev) instead.
2304 ///
2305 /// # Errors
2306 /// Errors if the allocation fails.
2307 ///
2308 /// # Examples
2309 /// ```
2310 /// # use bump_scope::Bump;
2311 /// # let mut bump: Bump = Bump::try_new()?;
2312 /// let slice = bump.try_alloc_iter_mut([1, 2, 3])?;
2313 /// assert_eq!(slice, [1, 2, 3]);
2314 /// # Ok::<(), bump_scope::alloc::AllocError>(())
2315 /// ```
2316 #[inline(always)]
2317 pub fn try_alloc_iter_mut<T>(&mut self, iter: impl IntoIterator<Item = T>) -> Result<BumpBox<'a, [T]>, AllocError> {
2318 self.generic_alloc_iter_mut(iter)
2319 }
2320
2321 #[inline(always)]
2322 pub(crate) fn generic_alloc_iter_mut<B: ErrorBehavior, T>(
2323 &mut self,
2324 iter: impl IntoIterator<Item = T>,
2325 ) -> Result<BumpBox<'a, [T]>, B> {
2326 let iter = iter.into_iter();
2327 let capacity = iter.size_hint().0;
2328
2329 let mut vec = MutBumpVec::<T, &mut Self>::generic_with_capacity_in(capacity, self)?;
2330
2331 for value in iter {
2332 vec.generic_push(value)?;
2333 }
2334
2335 Ok(vec.into_boxed_slice())
2336 }
2337
2338 /// Allocate elements of an iterator into a slice in reverse order.
2339 ///
2340 /// Compared to [`alloc_iter_mut`] this function is more performant
2341 /// for downwards bumping allocators as the allocation for the vector can be shrunk in place
2342 /// without any `ptr::copy`.
2343 ///
2344 /// The reverse is true when upwards allocating. In that case it's better to use [`alloc_iter_mut`] to prevent
2345 /// the `ptr::copy`.
2346 ///
2347 /// [`alloc_iter_mut`]: Self::alloc_iter_mut
2348 ///
2349 /// # Panics
2350 /// Panics if the allocation fails.
2351 ///
2352 /// # Examples
2353 /// ```
2354 /// # use bump_scope::Bump;
2355 /// # let mut bump: Bump = Bump::new();
2356 /// let slice = bump.alloc_iter_mut_rev([1, 2, 3]);
2357 /// assert_eq!(slice, [3, 2, 1]);
2358 /// ```
2359 #[inline(always)]
2360 #[cfg(feature = "panic-on-alloc")]
2361 pub fn alloc_iter_mut_rev<T>(&mut self, iter: impl IntoIterator<Item = T>) -> BumpBox<'a, [T]> {
2362 panic_on_error(self.generic_alloc_iter_mut_rev(iter))
2363 }
2364
2365 /// Allocate elements of an iterator into a slice in reverse order.
2366 ///
2367 /// Compared to [`try_alloc_iter_mut`] this function is more performant
2368 /// for downwards bumping allocators as the allocation for the vector can be shrunk in place
2369 /// without any `ptr::copy`.
2370 ///
2371 /// The reverse is true when upwards allocating. In that case it's better to use [`try_alloc_iter_mut`] to prevent
2372 /// the `ptr::copy`.
2373 ///
2374 /// [`try_alloc_iter_mut`]: Self::try_alloc_iter_mut
2375 ///
2376 /// # Errors
2377 /// Errors if the allocation fails.
2378 ///
2379 /// # Examples
2380 /// ```
2381 /// # use bump_scope::Bump;
2382 /// # let mut bump: Bump = Bump::try_new()?;
2383 /// let slice = bump.try_alloc_iter_mut_rev([1, 2, 3])?;
2384 /// assert_eq!(slice, [3, 2, 1]);
2385 /// # Ok::<(), bump_scope::alloc::AllocError>(())
2386 /// ```
2387 #[inline(always)]
2388 pub fn try_alloc_iter_mut_rev<T>(&mut self, iter: impl IntoIterator<Item = T>) -> Result<BumpBox<'a, [T]>, AllocError> {
2389 self.generic_alloc_iter_mut_rev(iter)
2390 }
2391
2392 #[inline(always)]
2393 pub(crate) fn generic_alloc_iter_mut_rev<B: ErrorBehavior, T>(
2394 &mut self,
2395 iter: impl IntoIterator<Item = T>,
2396 ) -> Result<BumpBox<'a, [T]>, B> {
2397 let iter = iter.into_iter();
2398 let capacity = iter.size_hint().0;
2399
2400 let mut vec = MutBumpVecRev::<T, &mut Self>::generic_with_capacity_in(capacity, self)?;
2401
2402 for value in iter {
2403 vec.generic_push(value)?;
2404 }
2405
2406 Ok(vec.into_boxed_slice())
2407 }
2408
2409 /// Allocate an unitialized object.
2410 ///
2411 /// You can safely initialize the object with [`init`](BumpBox::init) or unsafely with [`assume_init`](BumpBox::assume_init).
2412 ///
2413 /// # Panics
2414 /// Panics if the allocation fails.
2415 ///
2416 /// # Examples
2417 /// Safely:
2418 /// ```
2419 /// # use bump_scope::Bump;
2420 /// # let bump: Bump = Bump::new();
2421 /// let uninit = bump.alloc_uninit();
2422 ///
2423 /// let five = uninit.init(5);
2424 ///
2425 /// assert_eq!(*five, 5)
2426 /// ```
2427 ///
2428 /// Unsafely:
2429 /// ```
2430 /// # use bump_scope::Bump;
2431 /// # let bump: Bump = Bump::new();
2432 /// let mut uninit = bump.alloc_uninit();
2433 ///
2434 /// let five = unsafe {
2435 /// uninit.write(5);
2436 /// uninit.assume_init()
2437 /// };
2438 ///
2439 /// assert_eq!(*five, 5)
2440 /// ```
2441 #[inline(always)]
2442 #[cfg(feature = "panic-on-alloc")]
2443 pub fn alloc_uninit<T>(&self) -> BumpBox<'a, MaybeUninit<T>> {
2444 panic_on_error(self.generic_alloc_uninit())
2445 }
2446
2447 /// Allocate an unitialized object.
2448 ///
2449 /// You can safely initialize the object with [`init`](BumpBox::init) or unsafely with [`assume_init`](BumpBox::assume_init).
2450 ///
2451 /// # Errors
2452 /// Errors if the allocation fails.
2453 ///
2454 /// # Examples
2455 /// Safely:
2456 /// ```
2457 /// # use bump_scope::Bump;
2458 /// # let bump: Bump = Bump::new();
2459 /// let uninit = bump.try_alloc_uninit()?;
2460 ///
2461 /// let five = uninit.init(5);
2462 ///
2463 /// assert_eq!(*five, 5);
2464 /// # Ok::<(), bump_scope::alloc::AllocError>(())
2465 /// ```
2466 ///
2467 /// Unsafely:
2468 /// ```
2469 /// # use bump_scope::Bump;
2470 /// # let bump: Bump = Bump::try_new()?;
2471 /// let mut uninit = bump.try_alloc_uninit()?;
2472 ///
2473 /// let five = unsafe {
2474 /// uninit.write(5);
2475 /// uninit.assume_init()
2476 /// };
2477 ///
2478 /// assert_eq!(*five, 5);
2479 /// # Ok::<(), bump_scope::alloc::AllocError>(())
2480 /// ```
2481 #[inline(always)]
2482 pub fn try_alloc_uninit<T>(&self) -> Result<BumpBox<'a, MaybeUninit<T>>, AllocError> {
2483 self.generic_alloc_uninit()
2484 }
2485
2486 #[inline(always)]
2487 pub(crate) fn generic_alloc_uninit<B: ErrorBehavior, T>(&self) -> Result<BumpBox<'a, MaybeUninit<T>>, B> {
2488 if T::IS_ZST {
2489 return Ok(BumpBox::zst(MaybeUninit::uninit()));
2490 }
2491
2492 let ptr = self.do_alloc_sized::<B, T>()?.cast::<MaybeUninit<T>>();
2493 unsafe { Ok(BumpBox::from_raw(ptr)) }
2494 }
2495
2496 /// Allocate an unitialized object slice.
2497 ///
2498 /// You can safely initialize the object with
2499 /// [`init_fill`](BumpBox::init_fill),
2500 /// [`init_fill_with`](BumpBox::init_fill_with),
2501 /// [`init_copy`](BumpBox::init_copy),
2502 /// [`init_clone`](BumpBox::init_clone),
2503 /// [`init_zeroed`](crate::zerocopy_08::InitZeroed::init_zeroed) or unsafely with
2504 /// [`assume_init`](BumpBox::assume_init).
2505 ///
2506 /// # Panics
2507 /// Panics if the allocation fails.
2508 ///
2509 /// # Examples
2510 /// Safely:
2511 /// ```
2512 /// # use bump_scope::Bump;
2513 /// # let bump: Bump = Bump::new();
2514 /// let uninit = bump.alloc_uninit_slice(3);
2515 ///
2516 /// let values = uninit.init_copy(&[1, 2, 3]);
2517 ///
2518 /// assert_eq!(values, [1, 2, 3])
2519 /// ```
2520 ///
2521 /// Unsafely:
2522 /// ```
2523 /// # use bump_scope::Bump;
2524 /// # let bump: Bump = Bump::new();
2525 /// let mut uninit = bump.alloc_uninit_slice(3);
2526 ///
2527 /// let values = unsafe {
2528 /// uninit[0].write(1);
2529 /// uninit[1].write(2);
2530 /// uninit[2].write(3);
2531 ///
2532 /// uninit.assume_init()
2533 /// };
2534 ///
2535 /// assert_eq!(values, [1, 2, 3]);
2536 /// ```
2537 #[inline(always)]
2538 #[cfg(feature = "panic-on-alloc")]
2539 pub fn alloc_uninit_slice<T>(&self, len: usize) -> BumpBox<'a, [MaybeUninit<T>]> {
2540 panic_on_error(self.generic_alloc_uninit_slice(len))
2541 }
2542
2543 /// Allocate an unitialized object slice.
2544 ///
2545 /// You can safely initialize the object with
2546 /// [`init_fill`](BumpBox::init_fill),
2547 /// [`init_fill_with`](BumpBox::init_fill_with),
2548 /// [`init_copy`](BumpBox::init_copy),
2549 /// [`init_clone`](BumpBox::init_clone),
2550 /// [`init_zeroed`](crate::zerocopy_08::InitZeroed::init_zeroed) or unsafely with
2551 /// [`assume_init`](BumpBox::assume_init).
2552 ///
2553 /// # Errors
2554 /// Errors if the allocation fails.
2555 ///
2556 /// # Examples
2557 /// Safely:
2558 /// ```
2559 /// # use bump_scope::Bump;
2560 /// # let bump: Bump = Bump::new();
2561 /// let uninit = bump.try_alloc_uninit_slice(3)?;
2562 ///
2563 /// let values = uninit.init_copy(&[1, 2, 3]);
2564 ///
2565 /// assert_eq!(values, [1, 2, 3]);
2566 /// # Ok::<(), bump_scope::alloc::AllocError>(())
2567 /// ```
2568 ///
2569 /// Unsafely:
2570 /// ```
2571 /// # use bump_scope::Bump;
2572 /// # let bump: Bump = Bump::try_new()?;
2573 /// let mut uninit = bump.try_alloc_uninit_slice(3)?;
2574 ///
2575 /// let values = unsafe {
2576 /// uninit[0].write(1);
2577 /// uninit[1].write(2);
2578 /// uninit[2].write(3);
2579 ///
2580 /// uninit.assume_init()
2581 /// };
2582 ///
2583 /// assert_eq!(values, [1, 2, 3]);
2584 /// # Ok::<(), bump_scope::alloc::AllocError>(())
2585 /// ```
2586 #[inline(always)]
2587 pub fn try_alloc_uninit_slice<T>(&self, len: usize) -> Result<BumpBox<'a, [MaybeUninit<T>]>, AllocError> {
2588 self.generic_alloc_uninit_slice(len)
2589 }
2590
2591 #[inline(always)]
2592 pub(crate) fn generic_alloc_uninit_slice<B: ErrorBehavior, T>(
2593 &self,
2594 len: usize,
2595 ) -> Result<BumpBox<'a, [MaybeUninit<T>]>, B> {
2596 if T::IS_ZST {
2597 return Ok(BumpBox::uninit_zst_slice(len));
2598 }
2599
2600 let ptr = self.do_alloc_slice::<B, T>(len)?.cast::<MaybeUninit<T>>();
2601
2602 unsafe {
2603 let ptr = NonNull::slice_from_raw_parts(ptr, len);
2604 Ok(BumpBox::from_raw(ptr))
2605 }
2606 }
2607
2608 /// Allocate an unitialized object slice.
2609 ///
2610 /// You can safely initialize the object with
2611 /// [`init_fill`](BumpBox::init_fill),
2612 /// [`init_fill_with`](BumpBox::init_fill_with),
2613 /// [`init_copy`](BumpBox::init_copy),
2614 /// [`init_clone`](BumpBox::init_clone),
2615 /// [`init_zeroed`](crate::zerocopy_08::InitZeroed::init_zeroed) or unsafely with
2616 /// [`assume_init`](BumpBox::assume_init).
2617 ///
2618 /// This is just like [`alloc_uninit_slice`](Self::alloc_uninit_slice) but uses a `slice` to provide the `len`.
2619 /// This avoids a check for a valid layout. The elements of `slice` are irrelevant.
2620 ///
2621 /// # Panics
2622 /// Panics if the allocation fails.
2623 ///
2624 /// # Examples
2625 /// ```
2626 /// # use bump_scope::Bump;
2627 /// # let bump: Bump = Bump::new();
2628 /// let slice = &[1, 2, 3];
2629 /// let uninit_slice = bump.alloc_uninit_slice_for(slice);
2630 /// assert_eq!(uninit_slice.len(), 3);
2631 /// ```
2632 #[inline(always)]
2633 #[cfg(feature = "panic-on-alloc")]
2634 pub fn alloc_uninit_slice_for<T>(&self, slice: &[T]) -> BumpBox<'a, [MaybeUninit<T>]> {
2635 panic_on_error(self.generic_alloc_uninit_slice_for(slice))
2636 }
2637
2638 /// Allocate an unitialized object slice.
2639 ///
2640 /// You can safely initialize the object with
2641 /// [`init_fill`](BumpBox::init_fill),
2642 /// [`init_fill_with`](BumpBox::init_fill_with),
2643 /// [`init_copy`](BumpBox::init_copy),
2644 /// [`init_clone`](BumpBox::init_clone),
2645 /// [`init_zeroed`](crate::zerocopy_08::InitZeroed::init_zeroed) or unsafely with
2646 /// [`assume_init`](BumpBox::assume_init).
2647 ///
2648 /// This is just like [`try_alloc_uninit_slice`](Self::try_alloc_uninit_slice) but uses a `slice` to provide the `len`.
2649 /// This avoids a check for a valid layout. The elements of `slice` are irrelevant.
2650 ///
2651 /// # Errors
2652 /// Errors if the allocation fails.
2653 ///
2654 /// # Examples
2655 /// ```
2656 /// # use bump_scope::Bump;
2657 /// # let bump: Bump = Bump::try_new()?;
2658 /// let slice = &[1, 2, 3];
2659 /// let uninit_slice = bump.try_alloc_uninit_slice_for(slice)?;
2660 /// assert_eq!(uninit_slice.len(), 3);
2661 /// # Ok::<(), bump_scope::alloc::AllocError>(())
2662 /// ```
2663 #[inline(always)]
2664 pub fn try_alloc_uninit_slice_for<T>(&self, slice: &[T]) -> Result<BumpBox<'a, [MaybeUninit<T>]>, AllocError> {
2665 self.generic_alloc_uninit_slice_for(slice)
2666 }
2667
2668 #[inline(always)]
2669 pub(crate) fn generic_alloc_uninit_slice_for<B: ErrorBehavior, T>(
2670 &self,
2671 slice: &[T],
2672 ) -> Result<BumpBox<'a, [MaybeUninit<T>]>, B> {
2673 if T::IS_ZST {
2674 return Ok(BumpBox::uninit_zst_slice(slice.len()));
2675 }
2676
2677 let ptr = self.do_alloc_slice_for::<B, T>(slice)?.cast::<MaybeUninit<T>>();
2678
2679 unsafe {
2680 let ptr = NonNull::slice_from_raw_parts(ptr, slice.len());
2681 Ok(BumpBox::from_raw(ptr))
2682 }
2683 }
2684
2685 /// Allocate a [`FixedBumpVec`] with the given `capacity`.
2686 ///
2687 /// # Panics
2688 /// Panics if the allocation fails.
2689 ///
2690 /// # Examples
2691 /// ```
2692 /// # use bump_scope::Bump;
2693 /// # let bump: Bump = Bump::new();
2694 /// # #[expect(deprecated)]
2695 /// let mut values = bump.alloc_fixed_vec(3);
2696 /// values.push(1);
2697 /// values.push(2);
2698 /// values.push(3);
2699 /// assert_eq!(values, [1, 2, 3])
2700 /// ```
2701 #[doc(hidden)]
2702 #[deprecated = "use `FixedBumpVec::with_capacity_in()` instead"]
2703 #[inline(always)]
2704 #[cfg(feature = "panic-on-alloc")]
2705 pub fn alloc_fixed_vec<T>(&self, capacity: usize) -> FixedBumpVec<'a, T> {
2706 panic_on_error(self.generic_alloc_fixed_vec(capacity))
2707 }
2708
2709 /// Allocate a [`FixedBumpVec`] with the given `capacity`.
2710 ///
2711 /// # Errors
2712 /// Errors if the allocation fails.
2713 ///
2714 /// # Examples
2715 /// ```
2716 /// # use bump_scope::Bump;
2717 /// # let bump: Bump = Bump::try_new()?;
2718 /// # #[expect(deprecated)]
2719 /// let mut values = bump.try_alloc_fixed_vec(3)?;
2720 /// values.push(1);
2721 /// values.push(2);
2722 /// values.push(3);
2723 /// assert_eq!(values, [1, 2, 3]);
2724 /// # Ok::<(), bump_scope::alloc::AllocError>(())
2725 /// ```
2726 #[doc(hidden)]
2727 #[deprecated = "use `FixedBumpVec::try_with_capacity_in()` instead"]
2728 #[inline(always)]
2729 pub fn try_alloc_fixed_vec<T>(&self, capacity: usize) -> Result<FixedBumpVec<'a, T>, AllocError> {
2730 self.generic_alloc_fixed_vec(capacity)
2731 }
2732
2733 #[inline(always)]
2734 pub(crate) fn generic_alloc_fixed_vec<B: ErrorBehavior, T>(&self, capacity: usize) -> Result<FixedBumpVec<'a, T>, B> {
2735 Ok(FixedBumpVec::from_uninit(self.generic_alloc_uninit_slice(capacity)?))
2736 }
2737
2738 /// Allocate a [`FixedBumpString`] with the given `capacity` in bytes.
2739 ///
2740 /// # Panics
2741 /// Panics if the allocation fails.
2742 ///
2743 /// # Examples
2744 /// ```
2745 /// # use bump_scope::Bump;
2746 /// # let bump: Bump = Bump::new();
2747 /// # #[expect(deprecated)]
2748 /// let mut string = bump.alloc_fixed_string(13);
2749 /// string.push_str("Hello,");
2750 /// string.push_str(" world!");
2751 /// assert_eq!(string, "Hello, world!");
2752 /// ```
2753 #[doc(hidden)]
2754 #[deprecated = "use `FixedBumpString::with_capacity_in()` instead"]
2755 #[inline(always)]
2756 #[cfg(feature = "panic-on-alloc")]
2757 pub fn alloc_fixed_string(&self, capacity: usize) -> FixedBumpString<'a> {
2758 panic_on_error(self.generic_alloc_fixed_string(capacity))
2759 }
2760
2761 /// Allocate a [`FixedBumpString`] with the given `capacity` in bytes.
2762 ///
2763 /// # Errors
2764 /// Errors if the allocation fails.
2765 ///
2766 /// # Examples
2767 /// ```
2768 /// # use bump_scope::Bump;
2769 /// # let bump: Bump = Bump::try_new()?;
2770 /// # #[expect(deprecated)]
2771 /// let mut string = bump.try_alloc_fixed_string(13)?;
2772 /// string.push_str("Hello,");
2773 /// string.push_str(" world!");
2774 /// assert_eq!(string, "Hello, world!");
2775 /// # Ok::<(), bump_scope::alloc::AllocError>(())
2776 /// ```
2777 #[doc(hidden)]
2778 #[deprecated = "use `FixedBumpString::try_with_capacity_in()` instead"]
2779 #[inline(always)]
2780 pub fn try_alloc_fixed_string(&self, capacity: usize) -> Result<FixedBumpString<'a>, AllocError> {
2781 self.generic_alloc_fixed_string(capacity)
2782 }
2783
2784 #[inline(always)]
2785 pub(crate) fn generic_alloc_fixed_string<B: ErrorBehavior>(&self, capacity: usize) -> Result<FixedBumpString<'a>, B> {
2786 Ok(FixedBumpString::from_uninit(self.generic_alloc_uninit_slice(capacity)?))
2787 }
2788
2789 /// Allocates memory as described by the given `Layout`.
2790 ///
2791 /// # Panics
2792 /// Panics if the allocation fails.
2793 #[inline(always)]
2794 #[cfg(feature = "panic-on-alloc")]
2795 pub fn alloc_layout(&self, layout: Layout) -> NonNull<u8> {
2796 panic_on_error(self.generic_alloc_layout(layout))
2797 }
2798
2799 /// Allocates memory as described by the given `Layout`.
2800 ///
2801 /// # Errors
2802 /// Errors if the allocation fails.
2803 #[inline(always)]
2804 pub fn try_alloc_layout(&self, layout: Layout) -> Result<NonNull<u8>, AllocError> {
2805 self.generic_alloc_layout(layout)
2806 }
2807
2808 #[inline(always)]
2809 pub(crate) fn generic_alloc_layout<B: ErrorBehavior>(&self, layout: Layout) -> Result<NonNull<u8>, B> {
2810 match self.chunk.get().alloc(MinimumAlignment::<MIN_ALIGN>, CustomLayout(layout)) {
2811 Some(ptr) => Ok(ptr),
2812 None => self.alloc_in_another_chunk(layout),
2813 }
2814 }
2815
2816 /// Drops an allocated value and attempts to free its memory.
2817 ///
2818 /// The memory can only be freed if this is the last allocation.
2819 ///
2820 /// # Examples
2821 /// ```
2822 /// # use bump_scope::Bump;
2823 /// # let bump: Bump = Bump::new();
2824 /// let boxed = bump.alloc(3i32);
2825 /// assert_eq!(bump.stats().allocated(), 4);
2826 /// bump.dealloc(boxed);
2827 /// assert_eq!(bump.stats().allocated(), 0);
2828 /// ```
2829 #[inline(always)]
2830 pub fn dealloc<T: ?Sized>(&self, boxed: BumpBox<T>) {
2831 let layout = Layout::for_value::<T>(&boxed);
2832 let ptr = boxed.into_raw();
2833
2834 unsafe {
2835 ptr.drop_in_place();
2836 self.deallocate(ptr.cast(), layout);
2837 }
2838 }
2839
2840 /// Reserves capacity for at least `additional` more bytes to be bump allocated.
2841 /// The bump allocator may reserve more space to avoid frequent reallocations.
2842 /// After calling `reserve_bytes`, <code>self.[stats](Self::stats)().[remaining](Stats::remaining)()</code> will be greater than or equal to
2843 /// `additional`. Does nothing if the capacity is already sufficient.
2844 ///
2845 /// Note that these additional bytes are not necessarily in one contiguous region but
2846 /// might be spread out among many chunks.
2847 ///
2848 /// # Panics
2849 /// Panics if the allocation fails.
2850 ///
2851 /// # Examples
2852 /// ```
2853 /// # use bump_scope::Bump;
2854 /// let bump: Bump = Bump::new();
2855 /// assert!(bump.stats().capacity() < 4096);
2856 ///
2857 /// bump.reserve_bytes(4096);
2858 /// assert!(bump.stats().capacity() >= 4096);
2859 /// ```
2860 #[inline(always)]
2861 #[cfg(feature = "panic-on-alloc")]
2862 pub fn reserve_bytes(&self, additional: usize) {
2863 panic_on_error(self.generic_reserve_bytes(additional));
2864 }
2865
2866 /// Reserves capacity for at least `additional` more bytes to be bump allocated.
2867 /// The bump allocator may reserve more space to avoid frequent reallocations.
2868 /// After calling `reserve_bytes`, <code>self.[stats](Self::stats)().[remaining](Stats::remaining)()</code> will be greater than or equal to
2869 /// `additional`. Does nothing if the capacity is already sufficient.
2870 ///
2871 /// # Errors
2872 /// Errors if the allocation fails.
2873 ///
2874 /// # Examples
2875 /// ```
2876 /// # use bump_scope::Bump;
2877 /// let bump: Bump = Bump::try_new()?;
2878 /// assert!(bump.stats().capacity() < 4096);
2879 ///
2880 /// bump.try_reserve_bytes(4096)?;
2881 /// assert!(bump.stats().capacity() >= 4096);
2882 /// # Ok::<(), bump_scope::alloc::AllocError>(())
2883 /// ```
2884 #[inline(always)]
2885 pub fn try_reserve_bytes(&self, additional: usize) -> Result<(), AllocError> {
2886 self.generic_reserve_bytes(additional)
2887 }
2888
2889 #[inline(always)]
2890 pub(crate) fn generic_reserve_bytes<B: ErrorBehavior>(&self, additional: usize) -> Result<(), B> {
2891 let Ok(layout) = Layout::from_size_align(additional, 1) else {
2892 return Err(B::capacity_overflow());
2893 };
2894
2895 if let Some(mut chunk) = self.chunk.get().guaranteed_allocated() {
2896 let mut additional = additional;
2897
2898 loop {
2899 if let Some(rest) = additional.checked_sub(chunk.remaining()) {
2900 additional = rest;
2901 } else {
2902 return Ok(());
2903 }
2904
2905 if let Some(next) = chunk.next() {
2906 chunk = next;
2907 } else {
2908 break;
2909 }
2910 }
2911
2912 chunk.append_for(layout).map(drop)
2913 } else {
2914 let allocator = A::default_or_panic();
2915 let new_chunk = RawChunk::new_in(
2916 ChunkSize::from_capacity(layout).ok_or_else(B::capacity_overflow)?,
2917 None,
2918 allocator,
2919 )?;
2920 self.chunk.set(new_chunk.coerce_guaranteed_allocated());
2921 Ok(())
2922 }
2923 }
2924
2925 /// Allocates the result of `f` in the bump allocator, then moves `E` out of it and deallocates the space it took up.
2926 ///
2927 /// 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.
2928 ///
2929 /// There is also [`alloc_try_with_mut`](Self::alloc_try_with_mut), optimized for a mutable reference.
2930 ///
2931 /// # Panics
2932 /// Panics if the allocation fails.
2933 ///
2934 /// # Examples
2935 #[cfg_attr(feature = "nightly-tests", doc = "```")]
2936 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
2937 /// # #![feature(offset_of_enum)]
2938 /// # use core::mem::offset_of;
2939 /// # use bump_scope::Bump;
2940 /// # let bump: Bump = Bump::new();
2941 /// let result = bump.alloc_try_with(|| -> Result<i32, i32> { Ok(123) });
2942 /// assert_eq!(result.unwrap(), 123);
2943 /// assert_eq!(bump.stats().allocated(), offset_of!(Result<i32, i32>, Ok.0) + size_of::<i32>());
2944 /// ```
2945 #[cfg_attr(feature = "nightly-tests", doc = "```")]
2946 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
2947 /// # use bump_scope::Bump;
2948 /// # let bump: Bump = Bump::new();
2949 /// let result = bump.alloc_try_with(|| -> Result<i32, i32> { Err(123) });
2950 /// assert_eq!(result.unwrap_err(), 123);
2951 /// assert_eq!(bump.stats().allocated(), 0);
2952 /// ```
2953 #[inline(always)]
2954 #[cfg(feature = "panic-on-alloc")]
2955 #[expect(clippy::missing_errors_doc)]
2956 pub fn alloc_try_with<T, E>(&self, f: impl FnOnce() -> Result<T, E>) -> Result<BumpBox<'a, T>, E> {
2957 panic_on_error(self.generic_alloc_try_with(f))
2958 }
2959
2960 /// Allocates the result of `f` in the bump allocator, then moves `E` out of it and deallocates the space it took up.
2961 ///
2962 /// 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.
2963 ///
2964 /// There is also [`try_alloc_try_with_mut`](Self::try_alloc_try_with_mut), optimized for a mutable reference.
2965 ///
2966 /// # Errors
2967 /// Errors if the allocation fails.
2968 ///
2969 /// # Examples
2970 #[cfg_attr(feature = "nightly-tests", doc = "```")]
2971 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
2972 /// # #![feature(offset_of_enum)]
2973 /// # use core::mem::offset_of;
2974 /// # use bump_scope::Bump;
2975 /// # let bump: Bump = Bump::try_new()?;
2976 /// let result = bump.try_alloc_try_with(|| -> Result<i32, i32> { Ok(123) })?;
2977 /// assert_eq!(result.unwrap(), 123);
2978 /// assert_eq!(bump.stats().allocated(), offset_of!(Result<i32, i32>, Ok.0) + size_of::<i32>());
2979 /// # Ok::<(), bump_scope::alloc::AllocError>(())
2980 /// ```
2981 #[cfg_attr(feature = "nightly-tests", doc = "```")]
2982 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
2983 /// # use bump_scope::Bump;
2984 /// # let bump: Bump = Bump::try_new()?;
2985 /// let result = bump.try_alloc_try_with(|| -> Result<i32, i32> { Err(123) })?;
2986 /// assert_eq!(result.unwrap_err(), 123);
2987 /// assert_eq!(bump.stats().allocated(), 0);
2988 /// # Ok::<(), bump_scope::alloc::AllocError>(())
2989 /// ```
2990 #[inline(always)]
2991 pub fn try_alloc_try_with<T, E>(
2992 &self,
2993 f: impl FnOnce() -> Result<T, E>,
2994 ) -> Result<Result<BumpBox<'a, T>, E>, AllocError> {
2995 self.generic_alloc_try_with(f)
2996 }
2997
2998 #[inline(always)]
2999 pub(crate) fn generic_alloc_try_with<B: ErrorBehavior, T, E>(
3000 &self,
3001 f: impl FnOnce() -> Result<T, E>,
3002 ) -> Result<Result<BumpBox<'a, T>, E>, B> {
3003 if T::IS_ZST {
3004 return match f() {
3005 Ok(value) => Ok(Ok(BumpBox::zst(value))),
3006 Err(error) => Ok(Err(error)),
3007 };
3008 }
3009
3010 let checkpoint_before_alloc = self.checkpoint();
3011 let uninit = self.generic_alloc_uninit::<B, Result<T, E>>()?;
3012 let ptr = BumpBox::into_raw(uninit).cast::<Result<T, E>>();
3013
3014 // When bumping downwards the chunk's position is the same as `ptr`.
3015 // Using `ptr` is faster so we use that.
3016 let pos = if UP { self.chunk.get().pos() } else { ptr.cast() };
3017
3018 Ok(unsafe {
3019 non_null::write_with(ptr, f);
3020
3021 // If `f` made allocations on this bump allocator we can't shrink the allocation.
3022 let can_shrink = pos == self.chunk.get().pos();
3023
3024 match non_null::result(ptr) {
3025 Ok(value) => Ok({
3026 if can_shrink {
3027 let new_pos = if UP {
3028 let pos = value.add(1).addr().get();
3029 up_align_usize_unchecked(pos, MIN_ALIGN)
3030 } else {
3031 let pos = value.addr().get();
3032 down_align_usize(pos, MIN_ALIGN)
3033 };
3034
3035 // The allocation of a non-ZST was successful, so our chunk must be allocated.
3036 let chunk = self.chunk.get().guaranteed_allocated_unchecked();
3037 chunk.set_pos_addr(new_pos);
3038 }
3039
3040 BumpBox::from_raw(value)
3041 }),
3042 Err(error) => Err({
3043 let error = error.read();
3044
3045 if can_shrink {
3046 self.reset_to(checkpoint_before_alloc);
3047 }
3048
3049 error
3050 }),
3051 }
3052 })
3053 }
3054
3055 /// Allocates the result of `f` in the bump allocator, then moves `E` out of it and deallocates the space it took up.
3056 ///
3057 /// 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.
3058 ///
3059 /// This is just like [`alloc_try_with`](Self::alloc_try_with), but optimized for a mutable reference.
3060 ///
3061 /// # Panics
3062 /// Panics if the allocation fails.
3063 ///
3064 /// # Examples
3065 #[cfg_attr(feature = "nightly-tests", doc = "```")]
3066 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
3067 /// # #![feature(offset_of_enum)]
3068 /// # use core::mem::offset_of;
3069 /// # use bump_scope::Bump;
3070 /// # let mut bump: Bump = Bump::new();
3071 /// let result = bump.alloc_try_with_mut(|| -> Result<i32, i32> { Ok(123) });
3072 /// assert_eq!(result.unwrap(), 123);
3073 /// assert_eq!(bump.stats().allocated(), offset_of!(Result<i32, i32>, Ok.0) + size_of::<i32>());
3074 /// ```
3075 #[cfg_attr(feature = "nightly-tests", doc = "```")]
3076 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
3077 /// # use bump_scope::Bump;
3078 /// # let mut bump: Bump = Bump::new();
3079 /// let result = bump.alloc_try_with_mut(|| -> Result<i32, i32> { Err(123) });
3080 /// assert_eq!(result.unwrap_err(), 123);
3081 /// assert_eq!(bump.stats().allocated(), 0);
3082 /// ```
3083 #[inline(always)]
3084 #[cfg(feature = "panic-on-alloc")]
3085 #[expect(clippy::missing_errors_doc)]
3086 pub fn alloc_try_with_mut<T, E>(&mut self, f: impl FnOnce() -> Result<T, E>) -> Result<BumpBox<'a, T>, E> {
3087 panic_on_error(self.generic_alloc_try_with_mut(f))
3088 }
3089
3090 /// Allocates the result of `f` in the bump allocator, then moves `E` out of it and deallocates the space it took up.
3091 ///
3092 /// 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.
3093 ///
3094 /// This is just like [`try_alloc_try_with`](Self::try_alloc_try_with), but optimized for a mutable reference.
3095 ///
3096 /// # Errors
3097 /// Errors if the allocation fails.
3098 ///
3099 /// # Examples
3100 #[cfg_attr(feature = "nightly-tests", doc = "```")]
3101 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
3102 /// # #![feature(offset_of_enum)]
3103 /// # use core::mem::offset_of;
3104 /// # use bump_scope::Bump;
3105 /// # let mut bump: Bump = Bump::try_new()?;
3106 /// let result = bump.try_alloc_try_with_mut(|| -> Result<i32, i32> { Ok(123) })?;
3107 /// assert_eq!(result.unwrap(), 123);
3108 /// assert_eq!(bump.stats().allocated(), offset_of!(Result<i32, i32>, Ok.0) + size_of::<i32>());
3109 /// # Ok::<(), bump_scope::alloc::AllocError>(())
3110 /// ```
3111 #[cfg_attr(feature = "nightly-tests", doc = "```")]
3112 #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
3113 /// # use bump_scope::Bump;
3114 /// # let mut bump: Bump = Bump::try_new()?;
3115 /// let result = bump.try_alloc_try_with_mut(|| -> Result<i32, i32> { Err(123) })?;
3116 /// assert_eq!(result.unwrap_err(), 123);
3117 /// assert_eq!(bump.stats().allocated(), 0);
3118 /// # Ok::<(), bump_scope::alloc::AllocError>(())
3119 /// ```
3120 #[inline(always)]
3121 pub fn try_alloc_try_with_mut<T, E>(
3122 &mut self,
3123 f: impl FnOnce() -> Result<T, E>,
3124 ) -> Result<Result<BumpBox<'a, T>, E>, AllocError> {
3125 self.generic_alloc_try_with_mut(f)
3126 }
3127
3128 #[inline(always)]
3129 pub(crate) fn generic_alloc_try_with_mut<B: ErrorBehavior, T, E>(
3130 &mut self,
3131 f: impl FnOnce() -> Result<T, E>,
3132 ) -> Result<Result<BumpBox<'a, T>, E>, B> {
3133 if T::IS_ZST {
3134 return match f() {
3135 Ok(value) => Ok(Ok(BumpBox::zst(value))),
3136 Err(error) => Ok(Err(error)),
3137 };
3138 }
3139
3140 let checkpoint = self.checkpoint();
3141 let ptr = self.generic_prepare_allocation::<B, Result<T, E>>()?;
3142
3143 Ok(unsafe {
3144 non_null::write_with(ptr, f);
3145
3146 // There is no need for `can_shrink` checks, because we have a mutable reference
3147 // so there's no way anyone else has allocated in `f`.
3148 match non_null::result(ptr) {
3149 Ok(value) => Ok({
3150 let new_pos = if UP {
3151 let pos = value.add(1).addr().get();
3152 up_align_usize_unchecked(pos, MIN_ALIGN)
3153 } else {
3154 let pos = value.addr().get();
3155 down_align_usize(pos, MIN_ALIGN)
3156 };
3157
3158 // The allocation of a non-ZST was successful, so our chunk must be allocated.
3159 let chunk = self.chunk.get().guaranteed_allocated_unchecked();
3160 chunk.set_pos_addr(new_pos);
3161
3162 BumpBox::from_raw(value)
3163 }),
3164 Err(error) => Err({
3165 let error = error.read();
3166 self.reset_to(checkpoint);
3167 error
3168 }),
3169 }
3170 })
3171 }
3172}