static_alloc/bump.rs
1//! The bump allocator.
2//!
3//! Basics of usage and the connection between the structs is discussed in the documentation of the
4//! [`Bump`] itself.
5//!
6//! [`Bump`]: struct.Bump.html
7use core::alloc::{GlobalAlloc, Layout};
8use core::cell::UnsafeCell;
9use core::mem::{self, MaybeUninit};
10use core::ptr::{NonNull, null_mut};
11
12#[cfg(not(feature = "polyfill"))]
13use core::sync::atomic::{AtomicUsize, Ordering};
14
15#[cfg(feature = "polyfill")]
16use portable_atomic::{AtomicUsize, Ordering};
17
18use crate::leaked::LeakBox;
19use alloc_traits::{AllocTime, LocalAlloc, NonZeroLayout};
20
21/// Allocator drawing from an inner, statically sized memory resource.
22///
23/// The type parameter `T` is used only to annotate the required size and alignment of the region
24/// and has no futher use. Note that in particular there is no safe way to retrieve or unwrap an
25/// inner instance even if the `Bump` was not constructed as a shared global static. Nevertheless,
26/// the choice of type makes it easier to reason about potentially required extra space due to
27/// alignment padding.
28///
29/// This type is *always* `Sync` to allow creating `static` instances. This works only because
30/// there is no actual instance of `T` contained inside.
31///
32/// ## Usage as global allocator
33///
34/// You can use the stable rust attribute to use an instance of this type as the global allocator.
35///
36/// ```rust,no_run
37/// use static_alloc::Bump;
38///
39/// #[global_allocator]
40/// static A: Bump<[u8; 1 << 16]> = Bump::uninit();
41///
42/// fn main() { }
43/// ```
44///
45/// Take care, some runtime features of Rust will allocate some memory before or after your own
46/// code. In particular, it was found to be be tricky to predict the usage of the builtin test
47/// framework which seemingly allocates some structures per test.
48///
49/// ## Usage as a non-dropping local allocator
50///
51/// It is also possible to use a `Bump` as a stack local allocator or a specialized allocator. The
52/// interface offers some utilities for allocating values from references to shared or unshared
53/// instances directly. **Note**: this will never call the `Drop` implementation of the allocated
54/// type. In particular, it would almost surely not be safe to `Pin` the values, except if there is
55/// a guarantee for the `Bump` itself to not be deallocated either.
56///
57/// ```rust
58/// use static_alloc::Bump;
59///
60/// let local: Bump<[u64; 3]> = Bump::uninit();
61///
62/// let one = local.leak(0_u64).unwrap();
63/// let two = local.leak(1_u64).unwrap();
64/// let three = local.leak(2_u64).unwrap();
65///
66/// // Exhausted the space.
67/// assert!(local.leak(3_u64).is_err());
68/// ```
69///
70/// Mind that the supplied type parameter influenced *both* size and alignment and a `[u8; 24]`
71/// does not guarantee being able to allocation three `u64` even though most targets have a minimum
72/// alignment requirement of 16 and it works fine on those.
73///
74/// ```rust
75/// # use static_alloc::Bump;
76/// // Just enough space for `u128` but no alignment requirement.
77/// let local: Bump<[u8; 16]> = Bump::uninit();
78///
79/// // May or may not return an err.
80/// let _ = local.leak(0_u128);
81/// ```
82///
83/// Instead use the type parameter to `Bump` as a hint for the best alignment.
84///
85/// ```rust
86/// # use static_alloc::Bump;
87/// // Enough space and align for `u128`.
88/// let local: Bump<[u128; 1]> = Bump::uninit();
89///
90/// assert!(local.leak(0_u128).is_ok());
91/// ```
92///
93/// ## Usage as a (local) bag of bits
94///
95/// It is of course entirely possible to use a local instance instead of a single global allocator.
96/// For example you could utilize the pointer interface directly to build a `#[no_std]` dynamic
97/// data structure in an environment without `extern lib alloc`. This feature was the original
98/// motivation behind the crate but no such data structures are provided here so a quick sketch of
99/// the idea must do:
100///
101/// ```
102/// use core::alloc;
103/// use static_alloc::Bump;
104///
105/// #[repr(align(4096))]
106/// struct PageTable {
107/// // some non-trivial type.
108/// # _private: [u8; 4096],
109/// }
110///
111/// impl PageTable {
112/// /// Avoid stack allocation of the full struct.
113/// pub unsafe fn new(into: *mut u8) -> &'static mut Self {
114/// // ...
115/// # &mut *(into as *mut Self)
116/// }
117/// }
118///
119/// // Allocator for pages for page tables. Provides 64 pages. When the
120/// // program/kernel is provided as an ELF the bootloader reserves
121/// // memory for us as part of the loading process that we can use
122/// // purely for page tables. Replaces asm `paging: .BYTE <size>;`
123/// static Paging: Bump<[u8; 1 << 18]> = Bump::uninit();
124///
125/// fn main() {
126/// let layout = alloc::Layout::new::<PageTable>();
127/// let memory = Paging.alloc(layout).unwrap();
128/// let table = unsafe {
129/// PageTable::new(memory.as_ptr())
130/// };
131/// }
132/// ```
133///
134/// A similar structure would of course work to allocate some non-`'static' objects from a
135/// temporary `Bump`.
136///
137/// ## More insights
138///
139/// The ordering used is currently `SeqCst`. This enforces a single global sequence of observed
140/// effects on the slab level. The author is fully aware that this is not strictly necessary. In
141/// fact, even `AcqRel` may not be required as the monotonic bump allocator does not synchronize
142/// other memory itself. If you bring forward a PR with a formalized reasoning for relaxing the
143/// requirements to `Relaxed` (llvm `Monotonic`) it will be greatly appreciated (even more if you
144/// demonstrate performance gains).
145///
146/// WIP: slices.
147#[repr(C)]
148pub struct Bump<T> {
149 /// While in shared state, an monotonic atomic counter of consumed bytes.
150 ///
151 /// While shared it is only mutated in `bump` which guarantees its invariants. In the mutable
152 /// reference state it is modified arbitrarily.
153 header: Header,
154
155 /// Outer unsafe cell due to thread safety.
156 /// Inner MaybeUninit because we padding may destroy initialization invariant
157 /// on the bytes themselves, and hence drop etc must not assumed inited.
158 storage: UnsafeCell<MaybeUninit<T>>,
159}
160
161/// An unsized bump allocator arena.
162///
163/// This does not enforce any particular alignment on its storage. You can, in general, expect that
164/// it is at least 4-byte aligned but should not rely on it for soundness purposes.
165#[repr(C)]
166pub struct BumpSlice {
167 /// While in shared state, an monotonic atomic counter of consumed bytes.
168 ///
169 /// While shared it is only mutated in `bump` which guarantees its invariants. In the mutable
170 /// reference state it is modified arbitrarily.
171 header: Header,
172
173 /// See [`Bump::storage`], same function but with a concrete type.
174 storage: UnsafeCell<[MaybeUninit<u8>]>,
175}
176
177/// A view of a bump allocator over an unsized arena.
178///
179/// The primary way of constructing this is a by [`Bump`] with some chosen layout descriptor type.
180/// It maintains the invariant of a tracking header being an accurate ledger for the use of its
181/// associated memory region. This implies you must not be allowed to combine any header and data.
182/// This strong association is protected by an area such as [`Bump`].
183///
184/// Note: You might think that we can
185#[derive(Clone, Copy)]
186struct BumpView<'lt> {
187 header: &'lt Header,
188 storage: &'lt UnsafeCell<[MaybeUninit<u8>]>,
189}
190
191#[repr(C)]
192struct Header {
193 consumed: AtomicUsize,
194}
195
196/// A value could not be moved into a slab allocation.
197///
198/// The error contains the value for which the allocation failed. Storing the value in the error
199/// keeps it alive in all cases. This prevents the `Drop` implementation from running and preserves
200/// resources which may otherwise not be trivial to restore.
201#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
202pub struct LeakError<T> {
203 val: T,
204 failure: Failure,
205}
206
207/// Specifies an amount of consumed space of a slab.
208///
209/// Each allocation of the `Bump` increases the current level as they must not be empty. By
210/// ensuring that an allocation is performed at a specific level it is thus possible to check that
211/// multiple allocations happened in succession without other intermediate allocations. This
212/// ability in turns makes it possible to group allocations together, for example to initialize a
213/// `#[repr(C)]` struct member-by-member or to extend a slice.
214///
215/// ## Usage
216///
217/// The main use is successively allocating a slice without requiring all data to be present at
218/// once. Other similar interface often require an internal locking mechanism but `Level` leaves
219/// the choice to the user. This is not yet encapsulate in a safe API yet `Level` makes it easy to
220/// reason about.
221///
222/// See [`MemBump::get_unchecked`][crate::unsync::MemBump] for redeeming a value.
223///
224/// ## Unsound usage.
225///
226/// FIXME: the below is UB because we don't gain provenance over the complete array, only each
227/// individual element. Instead, we must derive a new pointer from the allocator!
228///
229/// ```
230/// # use core::slice;
231/// # use static_alloc::bump::{Level, Bump};
232/// static BUMP: Bump<[u64; 4]> = Bump::uninit();
233///
234/// /// Gathers as much data as possible.
235/// ///
236/// /// An arbitrary amount of data, can't stack allocate!
237/// fn gather_data(mut iter: impl Iterator<Item=u64>) -> &'static mut [u64] {
238/// let first = match iter.next() {
239/// Some(item) => item,
240/// None => return &mut [],
241/// };
242///
243/// let mut level: Level = BUMP.level();
244/// let mut start: Level = BUMP.level();
245/// let mut count;
246///
247/// match BUMP.leak_at(first, level) {
248/// Ok((_first, first_level)) => {
249/// // Note we must throw away the first pointer. Its provenance does not
250/// // cover the other fields. Only its level can be used.
251/// level = first_level;
252/// count = 1;
253/// },
254/// _ => return &mut [],
255/// }
256///
257/// let _ = iter.try_for_each(|value: u64| {
258/// match BUMP.leak_at(value, level) {
259/// Err(err) => return Err(err),
260/// Ok((_, new_level)) => level = new_level,
261/// };
262/// count += 1;
263/// Ok(())
264/// });
265///
266/// unsafe {
267/// // Safety: we have an allocation here
268/// let begin = BUMP.get_unchecked(start);
269/// // SAFETY: all `count` allocations are contiguous, begin is well aligned and no
270/// // reference is currently pointing at any of the values. The lifetime is `'static` as
271/// // the BUMP itself is static.
272/// slice::from_raw_parts_mut(begin.ptr.as_ptr(), count)
273/// }
274/// }
275///
276/// fn main() {
277/// // There is no other thread running, so this succeeds.
278/// let slice = gather_data(0..=3);
279/// assert_eq!(slice, [0, 1, 2, 3]);
280/// }
281/// ```
282#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
283pub struct Level(pub(crate) usize);
284
285/// A successful allocation and current [`Level`].
286///
287/// [`Level`]: struct.Level.html
288#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
289pub struct Allocation<'a, T: ?Sized = u8> {
290 /// Pointer to the uninitialized region with specified layout.
291 pub ptr: NonNull<T>,
292
293 /// The lifetime of the allocation.
294 pub lifetime: AllocTime<'a>,
295
296 /// The observed amount of consumed bytes after the allocation.
297 pub level: Level,
298}
299
300/// Reason for a failed allocation at an exact [`Level`].
301///
302/// [`Level`]: struct.Level.html
303#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
304pub enum Failure {
305 /// No space left for that allocation.
306 Exhausted,
307
308 /// The allocation would not have used the expected base location.
309 ///
310 /// Reports the location that was observed. When only levels from the same slab are used (which
311 /// should normally be the case) then the observed level is monotonically increasing.
312 Mismatch {
313 /// The observed level that was different from the requested one.
314 observed: Level,
315 },
316}
317
318impl<T> Bump<T> {
319 /// Make a new allocatable slab of certain byte size and alignment.
320 ///
321 /// The storage will contain uninitialized bytes.
322 pub const fn uninit() -> Self {
323 Bump {
324 header: Header::empty(),
325 storage: UnsafeCell::new(MaybeUninit::uninit()),
326 }
327 }
328
329 /// Make a new allocatable slab of certain byte size and alignment.
330 ///
331 /// The storage will contain zeroed bytes. This is not *yet* available
332 /// as a `const fn` which currently limits its potential usefulness
333 /// but there is no good reason not to provide it regardless.
334 pub fn zeroed() -> Self {
335 Bump {
336 header: Header::empty(),
337 storage: UnsafeCell::new(MaybeUninit::zeroed()),
338 }
339 }
340
341 /// Make a new allocatable slab provided with some bytes it can hand out.
342 ///
343 /// Note that `storage` will never be dropped and there is no way to get it back.
344 pub const fn new(storage: T) -> Self {
345 Bump {
346 header: Header::empty(),
347 storage: UnsafeCell::new(MaybeUninit::new(storage)),
348 }
349 }
350
351 /// Convert this into a type-erased byte-slice bump allocator.
352 ///
353 /// This returns `None` if the layout of `T` causes the layout of `self` to not be compatible
354 /// with the layout of [`BumpSlice`]. The criteria is that `T` must have an alignment not greater
355 /// than that of `usize` (which is used internally for accounting the used portion).
356 ///
357 /// For instance, this is guaranteed to work:
358 ///
359 /// ```
360 /// use static_alloc::Bump;
361 ///
362 /// let byte_array: Bump<[u8; 128]> = Bump::uninit();
363 /// assert!(byte_array.as_bump_slice().is_some());
364 /// let usize_array: Bump<[usize; 128]> = Bump::uninit();
365 /// assert!(usize_array.as_bump_slice().is_some());
366 /// ```
367 ///
368 /// On the other hand, this is very unlikely to work on any platform:
369 ///
370 /// ```
371 /// # if core::mem::size_of::<usize>() < 32 {
372 /// use static_alloc::Bump;
373 ///
374 /// #[repr(C, align(32))]
375 /// struct WhyAlignSoHigh([u8; 128]);
376 ///
377 /// let oof: Bump<WhyAlignSoHigh> = Bump::uninit();
378 /// assert!(oof.as_bump_slice().is_none());
379 /// # }
380 /// ```
381 pub const fn as_bump_slice(&self) -> Option<&BumpSlice> {
382 // Safety:
383 if mem::offset_of!(Self, storage) != mem::size_of::<Header>() {
384 return None;
385 }
386
387 let data_len = mem::size_of::<T>();
388 // Construct a point with the meta data of a slice to `data`, but pointing to the whole
389 // struct instead. This meta data is later copied to the meta data of `bump` when cast.
390 let ptr = (self as *const Self).cast::<MaybeUninit<u8>>();
391 let mem: *const [MaybeUninit<u8>] = core::ptr::slice_from_raw_parts(ptr, data_len);
392
393 // Safety: The layout of this type is compatible with ours. Both are `repr(C)`, so we can go
394 // field-by-field and the total layout.
395 //
396 // - Firstly, they share a `Header` field.
397 // - Secondly, `data` is located immediately behind `Header`. In `self` we verify this
398 // above, in `BumpSlice` that follows directly from `u8` being 1-aligned.
399 // - The alignment requirement of `MemBump`, exactly that of `Header`, is fulfilled as that
400 // is also a field of `Self`.
401 // - The size of both values is compatible. We construct the metadata such that the return
402 // value covers exactly the length of the `storage` field. What follows is padding to
403 // cover the alignment requirement. The `Self` type has the same alignment and same offset
404 // past-the-field and hence will receive the same padding.
405 Some(unsafe { &*(mem as *const BumpSlice) })
406 }
407
408 /// Mutable variant of [`Self::as_bump_slice`].
409 pub const fn as_mut_bump_slice(&mut self) -> Option<&mut BumpSlice> {
410 // Safety:
411 if mem::offset_of!(Self, storage) != mem::size_of::<Header>() {
412 return None;
413 }
414
415 let data_len = mem::size_of::<T>();
416 // Construct a point with the meta data of a slice to `data`, but pointing to the whole
417 // struct instead. This meta data is later copied to the meta data of `bump` when cast.
418 let ptr = (self as *mut Self).cast::<MaybeUninit<u8>>();
419 let mem: *mut [MaybeUninit<u8>] = core::ptr::slice_from_raw_parts_mut(ptr, data_len);
420
421 // Safety: The layout of this type is compatible with ours. Both are `repr(C)`, so we can go
422 // field-by-field and the total layout.
423 //
424 // - Firstly, they share a `Header` field.
425 // - Secondly, `data` is located immediately behind `Header`. In `self` we verify this
426 // above, in `MemBump` that follows directly from `u8` being 1-aligned.
427 // - The alignment requirement of `MemBump`, exactly that of `Header`, is fulfilled as that
428 // is also a field of `Self`.
429 // - The size of both values is compatible. We construct the metadata such that the return
430 // value covers exactly the length of the `storage` field. What follows is padding to
431 // cover the alignment requirement. The `Self` type has the same alignment and same offset
432 // past-the-field and hence will receive the same padding.
433 Some(unsafe { &mut *(mem as *mut BumpSlice) })
434 }
435
436 /// Reset the bump allocator.
437 ///
438 /// Requires a mutable reference, as no allocations can be active when doing it. This behaves
439 /// as if a fresh instance was assigned but it does not overwrite the bytes in the backing
440 /// storage. (You can unsafely rely on this).
441 ///
442 /// ## Usage
443 ///
444 /// ```
445 /// # use static_alloc::Bump;
446 /// let mut stack_buf = Bump::<usize>::uninit();
447 ///
448 /// let bytes = stack_buf.leak(0usize.to_be_bytes()).unwrap();
449 /// // Now the bump allocator is full.
450 /// assert!(stack_buf.leak(0u8).is_err());
451 ///
452 /// // We can reuse if we are okay with forgetting the previous value.
453 /// stack_buf.reset();
454 /// let val = stack_buf.leak(0usize).unwrap();
455 /// ```
456 ///
457 /// Trying to use the previous value does not work, as the stack is still borrowed. Note that
458 /// any user unsafely tracking the lifetime must also ensure this through proper lifetimes that
459 /// guarantee that borrows are alive for appropriate times.
460 ///
461 /// ```compile_fail
462 /// // error[E0502]: cannot borrow `stack_buf` as mutable because it is also borrowed as immutable
463 /// # use static_alloc::Bump;
464 /// let mut stack_buf = Bump::<usize>::uninit();
465 ///
466 /// let bytes = stack_buf.leak(0usize).unwrap();
467 /// // --------- immutably borrow occurs here
468 /// stack_buf.reset();
469 /// // ^^^^^^^ mutable borrow occurs here.
470 /// let other = stack_buf.leak(0usize).unwrap();
471 ///
472 /// *bytes += *other;
473 /// // ------------- immutable borrow later used here
474 /// ```
475 pub fn reset(&mut self) {
476 self.header = Header::empty();
477 }
478
479 fn as_view(&self) -> BumpView<'_> {
480 BumpView {
481 header: &self.header,
482 storage: {
483 let base = self.storage.get();
484 let len = mem::size_of::<T>();
485 let data = core::ptr::slice_from_raw_parts(base as *const _, len);
486 // Safety: covers exactly the memory of `storage`, which is a `MaybeUninit`.
487 unsafe { &*(data as *const UnsafeCell<[_]>) }
488 },
489 }
490 }
491
492 /// Allocate a region of memory.
493 ///
494 /// This is a safe alternative to [GlobalAlloc::alloc](#impl-GlobalAlloc).
495 ///
496 /// # Panics
497 /// This function will panic if the requested layout has a size of `0`. For the use in a
498 /// `GlobalAlloc` this is explicitely forbidden to request and would allow any behaviour but we
499 /// instead strictly check it.
500 pub fn alloc(&self, layout: Layout) -> Option<NonNull<u8>> {
501 self.as_view().alloc(layout)
502 }
503
504 /// Try to allocate some layout with a precise base location.
505 ///
506 /// The base location is the currently consumed byte count, without correction for the
507 /// alignment of the allocation. This will succeed if it can be allocate exactly at the
508 /// expected location.
509 ///
510 /// # Panics
511 /// This function may panic if the provided `level` is from a different slab.
512 pub fn alloc_at(&self, layout: Layout, level: Level) -> Result<Allocation<'_>, Failure> {
513 self.as_view().alloc_at(layout, level)
514 }
515
516 /// Get an allocation with detailed layout.
517 ///
518 /// Provides an [`Uninit`] wrapping several aspects of initialization in a safe interface,
519 /// bound by the lifetime of the reference to the allocator.
520 ///
521 /// [`Uninit`]: ../uninit/struct.Uninit.html
522 pub fn get_layout(&self, layout: Layout) -> Option<Allocation<'_>> {
523 self.as_view().get_layout(layout)
524 }
525
526 /// Get an allocation with detailed layout at a specific level.
527 ///
528 /// Provides an [`Uninit`] wrapping several aspects of initialization in a safe interface,
529 /// bound by the lifetime of the reference to the allocator.
530 ///
531 /// Since the underlying allocation is the same, it would be `unsafe` but justified to fuse
532 /// this allocation with the preceding or succeeding one.
533 ///
534 /// [`Uninit`]: ../uninit/struct.Uninit.html
535 pub fn get_layout_at(&self, layout: Layout, at: Level) -> Result<Allocation<'_>, Failure> {
536 self.as_view().get_layout_at(layout, at)
537 }
538
539 /// Get an allocation for a specific type.
540 ///
541 /// It is not yet initialized but provides a safe interface for that initialization.
542 ///
543 /// ## Usage
544 ///
545 /// ```
546 /// # use static_alloc::Bump;
547 /// use core::cell::{Ref, RefCell};
548 ///
549 /// let slab: Bump<[Ref<'static, usize>; 1]> = Bump::uninit();
550 /// let data = RefCell::new(0xff);
551 ///
552 /// // We can place a `Ref` here but we did not yet.
553 /// let alloc = slab.get::<Ref<usize>>().unwrap();
554 /// let cell_ref = unsafe {
555 /// alloc.leak(data.borrow())
556 /// };
557 ///
558 /// assert_eq!(**cell_ref, 0xff);
559 /// ```
560 pub fn get<V>(&self) -> Option<Allocation<'_, V>> {
561 self.as_view().get()
562 }
563
564 /// Get an allocation for a specific type at a specific level.
565 ///
566 /// See [`get`] for usage.
567 ///
568 /// [`get`]: #method.get
569 pub fn get_at<V>(&self, level: Level) -> Result<Allocation<'_, V>, Failure> {
570 self.as_view().get_at(level)
571 }
572
573 /// Get an allocation for a slice of a type.
574 ///
575 /// Returns `None` if the allocation fails (see [`Self::get`]) or if the slice layout can not be
576 /// computed due to an overflow with this size.
577 ///
578 /// # Examples
579 ///
580 /// ```
581 /// # use static_alloc::bump::Bump;
582 ///
583 /// let slab: Bump<[usize; 6]> = Bump::uninit();
584 ///
585 /// let first = slab.get_slice::<usize>(4).unwrap();
586 /// let second = slab.get_slice::<usize>(2).unwrap();
587 /// assert!(slab.get_slice::<usize>(1).is_none());
588 ///
589 /// assert_eq!(first.ptr.len(), 4);
590 /// assert_eq!(second.ptr.len(), 2);
591 /// ```
592 ///
593 /// ```
594 /// # use static_alloc::bump::Bump;
595 ///
596 /// let slab: Bump<[usize; 1]> = Bump::uninit();
597 ///
598 /// let lots_of_empty = slab.get_slice::<()>(usize::MAX).unwrap();
599 /// assert_eq!(lots_of_empty.ptr.len(), usize::MAX);
600 /// ```
601 ///
602 /// ```
603 /// # use static_alloc::bump::Bump;
604 ///
605 /// let slab: Bump<[usize; 1]> = Bump::uninit();
606 ///
607 /// let _exhaust = slab.get_slice::<usize>(1).unwrap();
608 /// assert!(slab.get_slice::<usize>(1).is_none());
609 /// let empty_slice = slab.get_slice::<usize>(0).unwrap();
610 /// ```
611 pub fn get_slice<V>(&self, len: usize) -> Option<Allocation<'_, [V]>> {
612 self.as_view().get_slice(len)
613 }
614
615 /// Move a value into an owned allocation.
616 ///
617 /// For safely initializing a value _after_ a successful allocation, see [`LeakBox::write`].
618 ///
619 /// [`LeakBox::write`]: ../leaked/struct.LeakBox.html#method.write
620 ///
621 /// ## Usage
622 ///
623 /// This can be used to push the value into a caller provided stack buffer where it lives
624 /// longer than the current stack frame. For example, you might create a linked list with a
625 /// dynamic number of values living in the frame below while still being dropped properly. This
626 /// is impossible to do with a return value.
627 ///
628 /// ```
629 /// # use static_alloc::Bump;
630 /// # use static_alloc::leaked::LeakBox;
631 /// fn rand() -> usize { 4 }
632 ///
633 /// enum Chain<'buf, T> {
634 /// Tail,
635 /// Link(T, LeakBox<'buf, Self>),
636 /// }
637 ///
638 /// fn make_chain<Buf, T>(buf: &Bump<Buf>, mut new_node: impl FnMut() -> T)
639 /// -> Option<Chain<'_, T>>
640 /// {
641 /// let count = rand();
642 /// let mut chain = Chain::Tail;
643 /// for _ in 0..count {
644 /// let node = new_node();
645 /// chain = Chain::Link(node, buf.leak_box(chain)?);
646 /// }
647 /// Some(chain)
648 /// }
649 ///
650 /// struct Node (usize);
651 /// impl Drop for Node {
652 /// fn drop(&mut self) {
653 /// println!("Dropped {}", self.0);
654 /// }
655 /// }
656 /// let mut counter = 0..;
657 /// let new_node = || Node(counter.next().unwrap());
658 ///
659 /// let buffer: Bump<[u8; 128]> = Bump::uninit();
660 /// let head = make_chain(&buffer, new_node).unwrap();
661 ///
662 /// // Prints the message in reverse order.
663 /// // Dropped 3
664 /// // Dropped 2
665 /// // Dropped 1
666 /// // Dropped 0
667 /// drop(head);
668 /// ```
669 pub fn leak_box<V>(&self, val: V) -> Option<LeakBox<'_, V>> {
670 self.as_view().leak_box(val)
671 }
672
673 /// Move a value into an owned allocation.
674 ///
675 /// See [`leak_box`] for usage.
676 ///
677 /// [`leak_box`]: #method.leak_box
678 pub fn leak_box_at<V>(&self, val: V, level: Level) -> Result<LeakBox<'_, V>, Failure> {
679 self.as_view().leak_box_at(val, level)
680 }
681
682 /// Observe the current level.
683 ///
684 /// Keep in mind that concurrent usage of the same slab may modify the level before you are
685 /// able to use it in `alloc_at`. Calling this method provides also no other guarantees on
686 /// synchronization of memory accesses, only that the values observed by the caller are a
687 /// monotonically increasing seequence while a shared reference exists.
688 pub fn level(&self) -> Level {
689 self.as_view().level()
690 }
691
692 /// Get a pointer to an existing allocation at a specific level.
693 ///
694 /// The resulting pointer may be used to access an arbitrary allocation starting at the pointer
695 /// (i.e. including additional allocations immediately afterwards) but the caller is
696 /// responsible for ensuring that these accesses do not overlap other accesses. There must be
697 /// no more life [`LeakBox`] to any allocation being accessed this way.
698 ///
699 /// # Safety
700 ///
701 /// - The level must refer to an existing allocation, i.e. it must previously have been
702 /// returned in [`Allocation::level`].
703 /// - As a corollary, particular it must be in-bounds of the allocator's memory.
704 /// - Another consequence, the result pointer must be aligned for the requested type.
705 pub unsafe fn get_unchecked<V>(&self, level: Level) -> Allocation<'_, V> {
706 // Safety: forwarding requirements.
707 unsafe { self.as_view().get_unchecked(level) }
708 }
709
710 /// Allocate a value for the lifetime of the allocator.
711 ///
712 /// The value is leaked in the sense that
713 ///
714 /// 1. the drop implementation of the allocated value is never called;
715 /// 2. reusing the memory for another allocation in the same `Bump` requires manual unsafe code
716 /// to handle dropping and reinitialization.
717 ///
718 /// However, it does not mean that the underlying memory used for the allocated value is never
719 /// reclaimed. If the `Bump` itself is a stack value then it will get reclaimed together with
720 /// it.
721 ///
722 /// ## Safety notice
723 ///
724 /// It is important to understand that it is undefined behaviour to reuse the allocation for
725 /// the *whole lifetime* of the returned reference. That is, dropping the allocation in-place
726 /// while the reference is still within its lifetime comes with the exact same unsafety caveats
727 /// as [`ManuallyDrop::drop`].
728 ///
729 /// ```
730 /// # use static_alloc::Bump;
731 /// #[derive(Debug, Default)]
732 /// struct FooBar {
733 /// // ...
734 /// # _private: [u8; 1],
735 /// }
736 ///
737 /// let local: Bump<[FooBar; 3]> = Bump::uninit();
738 /// let one = local.leak(FooBar::default()).unwrap();
739 ///
740 /// // Dangerous but justifiable.
741 /// let one = unsafe {
742 /// // Ensures there is no current mutable borrow.
743 /// core::ptr::drop_in_place(&mut *one);
744 /// };
745 /// ```
746 ///
747 /// ## Usage
748 ///
749 /// ```
750 /// use static_alloc::Bump;
751 ///
752 /// let local: Bump<[u64; 3]> = Bump::uninit();
753 ///
754 /// let one = local.leak(0_u64).unwrap();
755 /// assert_eq!(*one, 0);
756 /// *one = 42;
757 /// ```
758 ///
759 /// ## Limitations
760 ///
761 /// Only sized values can be allocated in this manner for now, unsized values are blocked on
762 /// stabilization of [`ptr::slice_from_raw_parts`]. We can not otherwise get a fat pointer to
763 /// the allocated region.
764 ///
765 /// [`ptr::slice_from_raw_parts`]: https://github.com/rust-lang/rust/issues/36925
766 /// [`ManuallyDrop::drop`]: https://doc.rust-lang.org/beta/std/mem/struct.ManuallyDrop.html#method.drop
767 ///
768 /// TODO: will be deprecated sooner or later in favor of a method that does not move the
769 /// resource on failure.
770 // #[deprecated = "Use leak_box and initialize it with the value. This does not move the value in the failure case."]
771 #[expect(clippy::mut_from_ref)] // This is an allocator.
772 pub fn leak<V>(&self, val: V) -> Result<&mut V, LeakError<V>> {
773 match self.get::<V>() {
774 // SAFETY: Just allocated this for a `V`.
775 Some(alloc) => Ok(unsafe { alloc.leak(val) }),
776 None => Err(LeakError::new(val, Failure::Exhausted)),
777 }
778 }
779
780 /// Allocate a value with a precise location.
781 ///
782 /// See [`leak`] for basics on allocation of values.
783 ///
784 /// The level is an identifer for a base location (more at [`level`]). This will succeed if it
785 /// can be allocate exactly at the expected location.
786 ///
787 /// This method will return the new level of the slab allocator. A next allocation at the
788 /// returned level will be placed next to this allocation, only separated by necessary padding
789 /// from alignment. In particular, this is the same strategy as applied for the placement of
790 /// `#[repr(C)]` struct members. (Except for the final padding at the last member to the full
791 /// struct alignment.)
792 ///
793 /// ## Usage
794 ///
795 /// ```
796 /// use static_alloc::Bump;
797 ///
798 /// let local: Bump<[u64; 3]> = Bump::uninit();
799 ///
800 /// let base = local.level();
801 /// let (one, level) = local.leak_at(1_u64, base).unwrap();
802 /// // Will panic when an allocation happens in between.
803 /// let (two, _) = local.leak_at(2_u64, level).unwrap();
804 ///
805 /// assert_eq!((one as *const u64).wrapping_offset(1), two);
806 /// ```
807 ///
808 /// [`leak`]: #method.leak
809 /// [`level`]: #method.level
810 ///
811 /// TODO: will be deprecated sooner or later in favor of a method that does not move the
812 /// resource on failure.
813 ///
814 // #[deprecated = "Use leak_box_at and initialize it with the value. This does not move the value in the failure case."]
815 #[expect(clippy::mut_from_ref)] // This is an allocator.
816 pub fn leak_at<V>(&self, val: V, level: Level) -> Result<(&mut V, Level), LeakError<V>> {
817 let alloc = match self.get_at::<V>(level) {
818 Ok(alloc) => alloc,
819 Err(err) => return Err(LeakError::new(val, err)),
820 };
821
822 // SAFETY: Just allocated this for a `V`.
823 let level = alloc.level;
824 let mutref = unsafe { alloc.leak(val) };
825 Ok((mutref, level))
826 }
827}
828
829impl BumpSlice {
830 /// Reset the bump allocator.
831 ///
832 /// Requires a mutable reference, as no allocations can be active when doing it. This behaves
833 /// as if a fresh instance was assigned but it does not overwrite the bytes in the backing
834 /// storage. (You can unsafely rely on this).
835 ///
836 /// ## Usage
837 ///
838 /// ```
839 /// # use static_alloc::bump::{Bump, BumpSlice};
840 /// let mut stack_buf = Bump::<usize>::uninit();
841 /// let stack_buf = stack_buf.as_mut_bump_slice().unwrap();
842 ///
843 /// let bytes = stack_buf.leak(0usize.to_be_bytes()).unwrap();
844 /// // Now the bump allocator is full.
845 /// assert!(stack_buf.leak(0u8).is_err());
846 ///
847 /// // We can reuse if we are okay with forgetting the previous value.
848 /// stack_buf.reset();
849 /// let val = stack_buf.leak(0usize).unwrap();
850 /// ```
851 ///
852 /// Trying to use the previous value does not work, as the stack is still borrowed. Note that
853 /// any user unsafely tracking the lifetime must also ensure this through proper lifetimes that
854 /// guarantee that borrows are alive for appropriate times.
855 ///
856 /// ```compile_fail
857 /// // error[E0502]: cannot borrow `stack_buf` as mutable because it is also borrowed as immutable
858 /// # use static_alloc::bump::{Bump, BumpSlice};
859 /// let mut stack_buf = Bump::<usize>::uninit();
860 /// let stack_buf = stack_buf.as_mut_bump_slice().unwrap();
861 ///
862 /// let bytes = stack_buf.leak(0usize).unwrap();
863 /// // --------- immutably borrow occurs here
864 /// stack_buf.reset();
865 /// // ^^^^^^^ mutable borrow occurs here.
866 /// let other = stack_buf.leak(0usize).unwrap();
867 ///
868 /// *bytes += *other;
869 /// // ------------- immutable borrow later used here
870 /// ```
871 pub fn reset(&mut self) {
872 self.header = Header::empty();
873 }
874
875 fn as_view(&self) -> BumpView<'_> {
876 BumpView {
877 header: &self.header,
878 storage: &self.storage,
879 }
880 }
881
882 /// Allocate a region of memory.
883 ///
884 /// This is a safe alternative to [GlobalAlloc::alloc](#impl-GlobalAlloc).
885 ///
886 /// # Panics
887 /// This function will panic if the requested layout has a size of `0`. For the use in a
888 /// `GlobalAlloc` this is explicitely forbidden to request and would allow any behaviour but we
889 /// instead strictly check it.
890 pub fn alloc(&self, layout: Layout) -> Option<NonNull<u8>> {
891 self.as_view().alloc(layout)
892 }
893
894 /// Try to allocate some layout with a precise base location.
895 ///
896 /// The base location is the currently consumed byte count, without correction for the
897 /// alignment of the allocation. This will succeed if it can be allocate exactly at the
898 /// expected location.
899 ///
900 /// # Panics
901 /// This function may panic if the provided `level` is from a different slab.
902 pub fn alloc_at(&self, layout: Layout, level: Level) -> Result<Allocation<'_>, Failure> {
903 self.as_view().alloc_at(layout, level)
904 }
905
906 /// Get an allocation with detailed layout.
907 ///
908 /// Provides an [`Uninit`] wrapping several aspects of initialization in a safe interface,
909 /// bound by the lifetime of the reference to the allocator.
910 ///
911 /// [`Uninit`]: ../uninit/struct.Uninit.html
912 pub fn get_layout(&self, layout: Layout) -> Option<Allocation<'_>> {
913 self.as_view().get_layout(layout)
914 }
915
916 /// Get an allocation with detailed layout at a specific level.
917 ///
918 /// Provides an [`Uninit`] wrapping several aspects of initialization in a safe interface,
919 /// bound by the lifetime of the reference to the allocator.
920 ///
921 /// Since the underlying allocation is the same, it would be `unsafe` but justified to fuse
922 /// this allocation with the preceding or succeeding one.
923 ///
924 /// [`Uninit`]: ../uninit/struct.Uninit.html
925 pub fn get_layout_at(&self, layout: Layout, at: Level) -> Result<Allocation<'_>, Failure> {
926 self.as_view().get_layout_at(layout, at)
927 }
928
929 /// Get an allocation for a specific type.
930 ///
931 /// It is not yet initialized but provides a safe interface for that initialization.
932 ///
933 /// ## Usage
934 ///
935 /// ```
936 /// # use static_alloc::bump::{Bump, BumpSlice};
937 /// use core::cell::{Ref, RefCell};
938 ///
939 /// let backing: Bump<[Ref<'static, usize>; 1]> = Bump::uninit();
940 /// let slab = backing.as_bump_slice().unwrap();
941 ///
942 /// let data = RefCell::new(0xff);
943 ///
944 /// // We can place a `Ref` here but we did not yet.
945 /// let alloc = slab.get::<Ref<usize>>().unwrap();
946 /// let cell_ref = unsafe {
947 /// alloc.leak(data.borrow())
948 /// };
949 ///
950 /// assert_eq!(**cell_ref, 0xff);
951 /// ```
952 pub fn get<V>(&self) -> Option<Allocation<'_, V>> {
953 self.as_view().get()
954 }
955
956 /// Get an allocation for a specific type at a specific level.
957 ///
958 /// See [`get`] for usage.
959 ///
960 /// [`get`]: #method.get
961 pub fn get_at<V>(&self, level: Level) -> Result<Allocation<'_, V>, Failure> {
962 self.as_view().get_at(level)
963 }
964
965 /// Get an allocation for a slice of a type.
966 ///
967 /// Returns `None` if the allocation fails (see [`Self::get`]) or if the slice layout can not be
968 /// computed due to an overflow with this size.
969 ///
970 /// # Examples
971 ///
972 /// ```
973 /// # use static_alloc::bump::{Bump, BumpSlice};
974 ///
975 /// let backing: Bump<[usize; 6]> = Bump::uninit();
976 /// let slab = backing.as_bump_slice().unwrap();
977 ///
978 /// let first = slab.get_slice::<usize>(4).unwrap();
979 /// let second = slab.get_slice::<usize>(2).unwrap();
980 /// assert!(slab.get_slice::<usize>(1).is_none());
981 ///
982 /// assert_eq!(first.ptr.len(), 4);
983 /// assert_eq!(second.ptr.len(), 2);
984 /// ```
985 ///
986 /// ```
987 /// # use static_alloc::bump::{Bump, BumpSlice};
988 ///
989 /// let backing: Bump<[usize; 1]> = Bump::uninit();
990 /// let slab = backing.as_bump_slice().unwrap();
991 ///
992 /// let lots_of_empty = slab.get_slice::<()>(usize::MAX).unwrap();
993 /// assert_eq!(lots_of_empty.ptr.len(), usize::MAX);
994 /// ```
995 ///
996 /// ```
997 /// # use static_alloc::bump::{Bump, BumpSlice};
998 ///
999 /// let backing: Bump<[usize; 1]> = Bump::uninit();
1000 /// let slab = backing.as_bump_slice().unwrap();
1001 ///
1002 /// let _exhaust = slab.get_slice::<usize>(1).unwrap();
1003 /// assert!(slab.get_slice::<usize>(1).is_none());
1004 /// let empty_slice = slab.get_slice::<usize>(0).unwrap();
1005 /// ```
1006 pub fn get_slice<V>(&self, len: usize) -> Option<Allocation<'_, [V]>> {
1007 self.as_view().get_slice(len)
1008 }
1009
1010 /// Move a value into an owned allocation.
1011 ///
1012 /// For safely initializing a value _after_ a successful allocation, see [`LeakBox::write`].
1013 ///
1014 /// [`LeakBox::write`]: ../leaked/struct.LeakBox.html#method.write
1015 ///
1016 /// ## Usage
1017 ///
1018 /// This can be used to push the value into a caller provided stack buffer where it lives
1019 /// longer than the current stack frame. For example, you might create a linked list with a
1020 /// dynamic number of values living in the frame below while still being dropped properly. This
1021 /// is impossible to do with a return value.
1022 ///
1023 /// ```
1024 /// # use static_alloc::bump::{Bump, BumpSlice};
1025 /// # use static_alloc::leaked::LeakBox;
1026 /// fn rand() -> usize { 4 }
1027 ///
1028 /// enum Chain<'buf, T> {
1029 /// Tail,
1030 /// Link(T, LeakBox<'buf, Self>),
1031 /// }
1032 ///
1033 /// fn make_chain<T>(buf: &BumpSlice, mut new_node: impl FnMut() -> T)
1034 /// -> Option<Chain<'_, T>>
1035 /// {
1036 /// let count = rand();
1037 /// let mut chain = Chain::Tail;
1038 /// for _ in 0..count {
1039 /// let node = new_node();
1040 /// chain = Chain::Link(node, buf.leak_box(chain)?);
1041 /// }
1042 /// Some(chain)
1043 /// }
1044 ///
1045 /// struct Node (usize);
1046 /// impl Drop for Node {
1047 /// fn drop(&mut self) {
1048 /// println!("Dropped {}", self.0);
1049 /// }
1050 /// }
1051 /// let mut counter = 0..;
1052 /// let new_node = || Node(counter.next().unwrap());
1053 ///
1054 /// let buffer: Bump<[u8; 128]> = Bump::uninit();
1055 /// let buffer = buffer.as_bump_slice().unwrap();
1056 /// let head = make_chain(buffer, new_node).unwrap();
1057 ///
1058 /// // Prints the message in reverse order.
1059 /// // Dropped 3
1060 /// // Dropped 2
1061 /// // Dropped 1
1062 /// // Dropped 0
1063 /// drop(head);
1064 /// ```
1065 pub fn leak_box<V>(&self, val: V) -> Option<LeakBox<'_, V>> {
1066 self.as_view().leak_box(val)
1067 }
1068
1069 /// Move a value into an owned allocation.
1070 ///
1071 /// See [`leak_box`] for usage.
1072 ///
1073 /// [`leak_box`]: #method.leak_box
1074 pub fn leak_box_at<V>(&self, val: V, level: Level) -> Result<LeakBox<'_, V>, Failure> {
1075 self.as_view().leak_box_at(val, level)
1076 }
1077
1078 /// Observe the current level.
1079 ///
1080 /// Keep in mind that concurrent usage of the same slab may modify the level before you are
1081 /// able to use it in `alloc_at`. Calling this method provides also no other guarantees on
1082 /// synchronization of memory accesses, only that the values observed by the caller are a
1083 /// monotonically increasing seequence while a shared reference exists.
1084 pub fn level(&self) -> Level {
1085 self.as_view().level()
1086 }
1087
1088 /// Get a pointer to an existing allocation at a specific level.
1089 ///
1090 /// The resulting pointer may be used to access an arbitrary allocation starting at the pointer
1091 /// (i.e. including additional allocations immediately afterwards) but the caller is
1092 /// responsible for ensuring that these accesses do not overlap other accesses. There must be
1093 /// no more life [`LeakBox`] to any allocation being accessed this way.
1094 ///
1095 /// # Safety
1096 ///
1097 /// - The level must refer to an existing allocation, i.e. it must previously have been
1098 /// returned in [`Allocation::level`].
1099 /// - As a corollary, particular it must be in-bounds of the allocator's memory.
1100 /// - Another consequence, the result pointer must be aligned for the requested type.
1101 pub unsafe fn get_unchecked<V>(&self, level: Level) -> Allocation<'_, V> {
1102 // Safety: forwarding requirements.
1103 unsafe { self.as_view().get_unchecked(level) }
1104 }
1105
1106 /// Allocate a value for the lifetime of the allocator.
1107 ///
1108 /// The value is leaked in the sense that
1109 ///
1110 /// 1. the drop implementation of the allocated value is never called;
1111 /// 2. reusing the memory for another allocation in the same `Bump` requires manual unsafe code
1112 /// to handle dropping and reinitialization.
1113 ///
1114 /// However, it does not mean that the underlying memory used for the allocated value is never
1115 /// reclaimed. If the `Bump` itself is a stack value then it will get reclaimed together with
1116 /// it.
1117 ///
1118 /// ## Safety notice
1119 ///
1120 /// It is important to understand that it is undefined behaviour to reuse the allocation for
1121 /// the *whole lifetime* of the returned reference. That is, dropping the allocation in-place
1122 /// while the reference is still within its lifetime comes with the exact same unsafety caveats
1123 /// as [`ManuallyDrop::drop`].
1124 ///
1125 /// ```
1126 /// # use static_alloc::bump::{Bump, BumpSlice};
1127 /// #[derive(Debug, Default)]
1128 /// struct FooBar {
1129 /// // ...
1130 /// # _private: [u8; 1],
1131 /// }
1132 ///
1133 /// let local: Bump<[FooBar; 3]> = Bump::uninit();
1134 /// let local = local.as_bump_slice().unwrap();
1135 /// let one = local.leak(FooBar::default()).unwrap();
1136 ///
1137 /// // Dangerous but justifiable.
1138 /// let one = unsafe {
1139 /// // Ensures there is no current mutable borrow.
1140 /// core::ptr::drop_in_place(&mut *one);
1141 /// };
1142 /// ```
1143 ///
1144 /// ## Usage
1145 ///
1146 /// ```
1147 /// use static_alloc::bump::{Bump, BumpSlice};
1148 ///
1149 /// let local: Bump<[u64; 3]> = Bump::uninit();
1150 /// let local = local.as_bump_slice().unwrap();
1151 ///
1152 /// let one = local.leak(0_u64).unwrap();
1153 /// assert_eq!(*one, 0);
1154 /// *one = 42;
1155 /// ```
1156 ///
1157 /// ## Limitations
1158 ///
1159 /// Only sized values can be allocated in this manner for now, unsized values are blocked on
1160 /// stabilization of [`ptr::slice_from_raw_parts`]. We can not otherwise get a fat pointer to
1161 /// the allocated region.
1162 ///
1163 /// [`ptr::slice_from_raw_parts`]: https://github.com/rust-lang/rust/issues/36925
1164 /// [`ManuallyDrop::drop`]: https://doc.rust-lang.org/beta/std/mem/struct.ManuallyDrop.html#method.drop
1165 ///
1166 /// TODO: will be deprecated sooner or later in favor of a method that does not move the
1167 /// resource on failure.
1168 // #[deprecated = "Use leak_box and initialize it with the value. This does not move the value in the failure case."]
1169 #[expect(clippy::mut_from_ref)] // This is an allocator.
1170 pub fn leak<V>(&self, val: V) -> Result<&mut V, LeakError<V>> {
1171 match self.get::<V>() {
1172 // SAFETY: Just allocated this for a `V`.
1173 Some(alloc) => Ok(unsafe { alloc.leak(val) }),
1174 None => Err(LeakError::new(val, Failure::Exhausted)),
1175 }
1176 }
1177
1178 /// Allocate a value with a precise location.
1179 ///
1180 /// See [`leak`] for basics on allocation of values.
1181 ///
1182 /// The level is an identifer for a base location (more at [`level`]). This will succeed if it
1183 /// can be allocate exactly at the expected location.
1184 ///
1185 /// This method will return the new level of the slab allocator. A next allocation at the
1186 /// returned level will be placed next to this allocation, only separated by necessary padding
1187 /// from alignment. In particular, this is the same strategy as applied for the placement of
1188 /// `#[repr(C)]` struct members. (Except for the final padding at the last member to the full
1189 /// struct alignment.)
1190 ///
1191 /// ## Usage
1192 ///
1193 /// ```
1194 /// use static_alloc::bump::{Bump, BumpSlice};
1195 ///
1196 /// let local: Bump<[u64; 3]> = Bump::uninit();
1197 /// let local = local.as_bump_slice().unwrap();
1198 ///
1199 /// let base = local.level();
1200 /// let (one, level) = local.leak_at(1_u64, base).unwrap();
1201 /// // Will panic when an allocation happens in between.
1202 /// let (two, _) = local.leak_at(2_u64, level).unwrap();
1203 ///
1204 /// assert_eq!((one as *const u64).wrapping_offset(1), two);
1205 /// ```
1206 ///
1207 /// [`leak`]: #method.leak
1208 /// [`level`]: #method.level
1209 ///
1210 /// TODO: will be deprecated sooner or later in favor of a method that does not move the
1211 /// resource on failure.
1212 ///
1213 // #[deprecated = "Use leak_box_at and initialize it with the value. This does not move the value in the failure case."]
1214 #[expect(clippy::mut_from_ref)] // This is an allocator.
1215 pub fn leak_at<V>(&self, val: V, level: Level) -> Result<(&mut V, Level), LeakError<V>> {
1216 let alloc = match self.get_at::<V>(level) {
1217 Ok(alloc) => alloc,
1218 Err(err) => return Err(LeakError::new(val, err)),
1219 };
1220
1221 // SAFETY: Just allocated this for a `V`.
1222 let level = alloc.level;
1223 let mutref = unsafe { alloc.leak(val) };
1224 Ok((mutref, level))
1225 }
1226}
1227
1228impl<'lt> BumpView<'lt> {
1229 pub fn alloc(self, layout: Layout) -> Option<NonNull<u8>> {
1230 Some(self.try_alloc(layout)?.ptr)
1231 }
1232
1233 pub fn alloc_at(self, layout: Layout, level: Level) -> Result<Allocation<'lt>, Failure> {
1234 let Allocation {
1235 ptr,
1236 lifetime,
1237 level,
1238 } = self.try_alloc_at(layout, level.0)?;
1239
1240 Ok(Allocation {
1241 ptr: ptr.cast(),
1242 lifetime,
1243 level,
1244 })
1245 }
1246
1247 pub fn get_layout(self, layout: Layout) -> Option<Allocation<'lt>> {
1248 self.try_alloc(layout)
1249 }
1250
1251 pub fn get_layout_at(self, layout: Layout, at: Level) -> Result<Allocation<'lt>, Failure> {
1252 self.try_alloc_at(layout, at.0)
1253 }
1254
1255 pub fn get<V>(self) -> Option<Allocation<'lt, V>> {
1256 if mem::size_of::<V>() == 0 {
1257 return Some(self.zst_fake_alloc());
1258 }
1259
1260 let layout = Layout::new::<V>();
1261 let Allocation {
1262 ptr,
1263 lifetime,
1264 level,
1265 } = self.try_alloc(layout)?;
1266
1267 Some(Allocation {
1268 ptr: ptr.cast(),
1269 lifetime,
1270 level,
1271 })
1272 }
1273
1274 pub fn get_at<V>(self, level: Level) -> Result<Allocation<'lt, V>, Failure> {
1275 if mem::size_of::<V>() == 0 {
1276 let fake = self.zst_fake_alloc();
1277 // Note: zst_fake_alloc is a noop on the level, we may as well check after.
1278 if fake.level != level {
1279 return Err(Failure::Mismatch {
1280 observed: fake.level,
1281 });
1282 }
1283 return Ok(fake);
1284 }
1285
1286 let layout = Layout::new::<V>();
1287 let Allocation {
1288 ptr,
1289 lifetime,
1290 level,
1291 } = self.try_alloc_at(layout, level.0)?;
1292
1293 Ok(Allocation {
1294 // It has exactly size and alignment for `V` as requested.
1295 ptr: ptr.cast(),
1296 lifetime,
1297 level,
1298 })
1299 }
1300
1301 pub fn get_slice<V>(&self, len: usize) -> Option<Allocation<'lt, [V]>> {
1302 if len == 0 {
1303 return Some(Allocation::for_empty_slice(self.level()));
1304 }
1305
1306 let (layout, _) = Layout::new::<V>().repeat(len).ok()?;
1307
1308 if layout.size() == 0 {
1309 // Synthesize the slice for this ZST.
1310 return Some(Allocation::for_zst_slice(len, self.level()));
1311 };
1312
1313 let alloc = self.get_layout(layout)?;
1314
1315 Some(Allocation {
1316 ptr: NonNull::slice_from_raw_parts(alloc.ptr.cast(), len),
1317 lifetime: alloc.lifetime,
1318 level: alloc.level,
1319 })
1320 }
1321
1322 pub fn leak_box<V>(self, val: V) -> Option<LeakBox<'lt, V>> {
1323 let Allocation { ptr, lifetime, .. } = self.get::<V>()?;
1324 Some(unsafe { LeakBox::new_from_raw_non_null(ptr, val, lifetime) })
1325 }
1326
1327 pub fn leak_box_at<V>(self, val: V, level: Level) -> Result<LeakBox<'lt, V>, Failure> {
1328 let Allocation { ptr, lifetime, .. } = self.get_at::<V>(level)?;
1329 Ok(unsafe { LeakBox::new_from_raw_non_null(ptr, val, lifetime) })
1330 }
1331
1332 pub fn level(&self) -> Level {
1333 Level(self.header.consumed.load(Ordering::SeqCst))
1334 }
1335
1336 /// # Safety
1337 ///
1338 /// - The level must refer to an existing allocation, i.e. it must previously have been
1339 /// returned in [`Allocation::level`].
1340 /// - As a corollary, particular it must be in-bounds of the allocator's memory.
1341 /// - Another consequence, the result pointer must be aligned for the requested type.
1342 pub unsafe fn get_unchecked<V>(self, level: Level) -> Allocation<'lt, V> {
1343 debug_assert!(level.0 <= mem::size_of_val(self.storage));
1344
1345 debug_assert!(
1346 level <= self.level(),
1347 "Tried to access an allocation that does not yet exist"
1348 );
1349
1350 let base_ptr = self.storage.get().cast::<u8>();
1351 // SAFETY: `level.0` is in bounds as assert above, or by the caller by having provided an
1352 // existing allocation—all allocations we hand out are in bounds.
1353 let alloc = unsafe { base_ptr.add(level.0) };
1354 let ptr = NonNull::new(alloc).unwrap().cast::<V>();
1355
1356 debug_assert!(
1357 ptr.as_ptr().is_aligned(),
1358 "Tried to access an allocation with improper type"
1359 );
1360
1361 Allocation {
1362 level,
1363 lifetime: AllocTime::default(),
1364 ptr,
1365 }
1366 }
1367
1368 // FIXME: should take `NonZeroLayout`.
1369 fn try_alloc(self, layout: Layout) -> Option<Allocation<'lt>> {
1370 // Guess zero, this will fail when we try to access it and it isn't.
1371 let mut consumed = 0;
1372 loop {
1373 match self.try_alloc_at(layout, consumed) {
1374 Ok(alloc) => return Some(alloc),
1375 Err(Failure::Exhausted) => return None,
1376 Err(Failure::Mismatch { observed }) => consumed = observed.0,
1377 }
1378 }
1379 }
1380
1381 /// Try to allocate some layout with a precise base location.
1382 ///
1383 /// The base location is the currently consumed byte count, without correction for the
1384 /// alignment of the allocation. This will succeed if it can be allocate exactly at the
1385 /// expected location.
1386 ///
1387 /// # Panics
1388 /// This function panics if `expect_consumed` is larger than `length`.
1389 /// FIXME: should take `NonZeroLayout`.
1390 fn try_alloc_at(
1391 self,
1392 layout: Layout,
1393 expect_consumed: usize,
1394 ) -> Result<Allocation<'lt>, Failure> {
1395 assert!(layout.size() > 0);
1396 let length = self.storage.get().len();
1397 let base_ptr = self.storage.get().cast::<u8>();
1398
1399 let alignment = layout.align();
1400 let requested = layout.size();
1401
1402 // Ensure no overflows when calculating offets within.
1403 assert!(expect_consumed <= length);
1404
1405 let available = length.checked_sub(expect_consumed).unwrap();
1406 let ptr_to = base_ptr.wrapping_add(expect_consumed);
1407 let offset = ptr_to.align_offset(alignment);
1408
1409 if requested > available.saturating_sub(offset) {
1410 return Err(Failure::Exhausted); // exhausted
1411 }
1412
1413 // `size` can not be zero, saturation will thus always make this true.
1414 assert!(offset < available);
1415 let at_aligned = expect_consumed.checked_add(offset).unwrap();
1416 let new_consumed = at_aligned.checked_add(requested).unwrap();
1417 // new_consumed
1418 // = consumed + offset + requested [lines above]
1419 // <= consumed + available [bail out: exhausted]
1420 // <= length [first line of loop]
1421 // So it's ok to store `allocated` into `consumed`.
1422 assert!(new_consumed <= length);
1423 assert!(at_aligned < length);
1424
1425 // Try to actually allocate.
1426 match self.bump(expect_consumed, new_consumed) {
1427 Ok(()) => (),
1428 Err(observed) => {
1429 // Someone else was faster, if you want it then recalculate again.
1430 return Err(Failure::Mismatch {
1431 observed: Level(observed),
1432 });
1433 }
1434 }
1435
1436 let aligned = unsafe {
1437 // SAFETY:
1438 // * `0 <= at_aligned < length` in bounds as checked above.
1439 base_ptr.byte_add(at_aligned)
1440 };
1441
1442 Ok(Allocation {
1443 ptr: NonNull::new(aligned).unwrap(),
1444 lifetime: AllocTime::default(),
1445 level: Level(new_consumed),
1446 })
1447 }
1448
1449 /// 'Allocate' a ZST.
1450 fn zst_fake_alloc<Z>(&self) -> Allocation<'lt, Z> {
1451 Allocation::for_zst(self.level())
1452 }
1453
1454 /// Try to bump the monotonic, atomic consume counter.
1455 ///
1456 /// This is the only place doing shared modification to `self.consumed`.
1457 ///
1458 /// Returns `Ok` if the consume counter was as expected. Monotonicty and atomicity guarantees
1459 /// to the caller that no overlapping range can succeed as well. This allocates the range to
1460 /// the caller.
1461 ///
1462 /// Returns the observed consume counter in an `Err` if it was not as expected.
1463 ///
1464 /// ## Panics
1465 /// This function panics if either argument exceeds the byte length of the underlying memory.
1466 /// It also panics if the expected value is larger than the new value.
1467 fn bump(&self, expect_consumed: usize, new_consumed: usize) -> Result<(), usize> {
1468 assert!(expect_consumed <= new_consumed);
1469 assert!(new_consumed <= self.storage.get().len());
1470 self.header.bump(expect_consumed, new_consumed)
1471 }
1472}
1473
1474impl Header {
1475 const fn empty() -> Self {
1476 Header {
1477 consumed: AtomicUsize::new(0),
1478 }
1479 }
1480
1481 fn bump(&self, expect_consumed: usize, new_consumed: usize) -> Result<(), usize> {
1482 self.consumed
1483 .compare_exchange(
1484 expect_consumed,
1485 new_consumed,
1486 Ordering::SeqCst,
1487 Ordering::SeqCst,
1488 )
1489 .map(drop)
1490 }
1491}
1492
1493impl<'alloc, T> Allocation<'alloc, T> {
1494 /// Write a value into the allocation and leak it.
1495 ///
1496 /// ## Safety
1497 ///
1498 /// Must have been allocated for a layout that fits the layout of T previously. The pointer
1499 /// must not be aliased.
1500 ///
1501 /// ## Usage
1502 ///
1503 /// Consider the alternative [`Bump::leak`] to safely allocate and directly leak a value.
1504 ///
1505 /// [`Bump::leak`]: struct.Bump.html#method.leak
1506 pub unsafe fn leak(self, val: T) -> &'alloc mut T {
1507 // Safety: The pointer is valid for a write as per caller.
1508 unsafe { core::ptr::write(self.ptr.as_ptr(), val) };
1509 // Safety: The pointer is not borrowed and valid as guaranteed by the caller.
1510 unsafe { &mut *self.ptr.as_ptr() }
1511 }
1512
1513 /// Write a value into the allocation and own it.
1514 ///
1515 /// ## Safety
1516 ///
1517 /// Must have been allocated for a layout that fits the layout of T previously. The pointer
1518 /// must not be aliased.
1519 ///
1520 /// ## Usage
1521 ///
1522 /// Consider the alternative [`Bump::leak`] to safely allocate and directly leak a value.
1523 ///
1524 /// [`Bump::leak`]: struct.Bump.html#method.leak
1525 pub unsafe fn boxed(self, val: T) -> LeakBox<'alloc, T> {
1526 // The pointer is not aliased and valid as guaranteed by the caller.
1527 unsafe { core::ptr::write(self.ptr.as_ptr(), val) };
1528 // Safety: the instance is valid, was just initialized.
1529 unsafe { LeakBox::from_raw(self.ptr.as_ptr()) }
1530 }
1531
1532 /// Convert this into a mutable reference to an uninitialized slot.
1533 ///
1534 /// ## Safety
1535 ///
1536 /// Must have been allocated for a layout that fits the layout of T previously.
1537 pub unsafe fn uninit(self) -> &'alloc mut MaybeUninit<T> {
1538 unsafe { &mut *self.ptr.cast().as_ptr() }
1539 }
1540
1541 /// An 'allocation' for an arbitrary ZST, at some arbitrary level.
1542 pub(crate) fn for_zst(level: Level) -> Self {
1543 assert!(mem::size_of::<T>() == 0);
1544 // If `Z` is a ZST, then the stride of any array is equal to 0. Thus, all arrays and slices
1545 // havee the same layout which only depends on the alignment. If we need a storage for this
1546 // ZST we just take one of those as our base 'allocation' which can also never be aliased.
1547 let alloc: &[T; 0] = &[];
1548
1549 Allocation {
1550 ptr: NonNull::from(alloc).cast(),
1551 lifetime: AllocTime::default(),
1552 level,
1553 }
1554 }
1555
1556 pub(crate) fn for_zst_slice(len: usize, level: Level) -> Allocation<'alloc, [T]> {
1557 assert!(mem::size_of::<T>() == 0);
1558 let alloc: &[T; 0] = &[];
1559
1560 Allocation {
1561 ptr: NonNull::slice_from_raw_parts(NonNull::from(alloc).cast(), len),
1562 lifetime: AllocTime::default(),
1563 level,
1564 }
1565 }
1566
1567 pub(crate) fn for_empty_slice(level: Level) -> Allocation<'alloc, [T]> {
1568 let alloc: &[T; 0] = &[];
1569
1570 Allocation {
1571 ptr: NonNull::from(alloc),
1572 lifetime: AllocTime::default(),
1573 level,
1574 }
1575 }
1576}
1577
1578impl<T> LeakError<T> {
1579 fn new(val: T, failure: Failure) -> Self {
1580 LeakError { val, failure }
1581 }
1582
1583 /// Inspect the cause of this error.
1584 pub fn kind(&self) -> Failure {
1585 self.failure
1586 }
1587
1588 /// Retrieve the value that could not be allocated.
1589 pub fn into_inner(self) -> T {
1590 self.val
1591 }
1592}
1593
1594// SAFETY: at most one thread gets a pointer to each chunk of data.
1595unsafe impl<T> Sync for Bump<T> {}
1596
1597// SAFETY: at most one thread gets a pointer to each chunk of data.
1598unsafe impl Sync for BumpView<'_> {}
1599unsafe impl Send for BumpView<'_> {}
1600
1601unsafe impl<T> GlobalAlloc for Bump<T> {
1602 unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
1603 // Safety: just handing over arguments exactly as is. These two allocators are 'compatible'
1604 // in the sense they hold onto the same value handles.
1605 unsafe { GlobalAlloc::alloc(&self.as_view(), layout) }
1606 }
1607
1608 unsafe fn realloc(&self, ptr: *mut u8, current: Layout, new_size: usize) -> *mut u8 {
1609 // Safety: just handing over arguments exactly as is. These two allocators are 'compatible'
1610 // in the sense they hold onto the same value handles.
1611 unsafe { GlobalAlloc::realloc(&self.as_view(), ptr, current, new_size) }
1612 }
1613
1614 unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
1615 // We are a slab allocator and do not deallocate.
1616 }
1617}
1618
1619unsafe impl GlobalAlloc for &'static BumpSlice {
1620 unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
1621 // Safety: just handing over arguments exactly as is. These two allocators are 'compatible'
1622 // in the sense they hold onto the same value handles.
1623 unsafe { GlobalAlloc::alloc(&self.as_view(), layout) }
1624 }
1625
1626 unsafe fn realloc(&self, ptr: *mut u8, current: Layout, new_size: usize) -> *mut u8 {
1627 // Safety: just handing over arguments exactly as is. These two allocators are 'compatible'
1628 // in the sense they hold onto the same value handles.
1629 unsafe { GlobalAlloc::realloc(&self.as_view(), ptr, current, new_size) }
1630 }
1631
1632 unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
1633 // We are a slab allocator and do not deallocate.
1634 }
1635}
1636
1637unsafe impl GlobalAlloc for BumpView<'_> {
1638 unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
1639 BumpView::alloc(*self, layout)
1640 .map(NonNull::as_ptr)
1641 .unwrap_or_else(null_mut)
1642 }
1643
1644 unsafe fn realloc(&self, ptr: *mut u8, current: Layout, new_size: usize) -> *mut u8 {
1645 let current = NonZeroLayout::from_layout(current.into()).unwrap();
1646 // Safety: As required of the caller, `new_size` is greater than 0.
1647 let new_size = unsafe { core::num::NonZeroUsize::new_unchecked(new_size) };
1648
1649 let target = match layout_reallocated(current, new_size) {
1650 Some(target) => target,
1651 None => return core::ptr::null_mut(),
1652 };
1653
1654 // Construct an allocation. This is not safe in general but the lifetime is not important.
1655 let reconstructed = alloc_traits::Allocation {
1656 // Safety: `ptr` is currently allocated via this allocator, i.e. non-null.
1657 ptr: unsafe { NonNull::new_unchecked(ptr) },
1658 layout: current,
1659 lifetime: AllocTime::default(),
1660 };
1661
1662 // Safety: satisfies our own invariants.
1663 unsafe { alloc_traits::LocalAlloc::realloc(self, reconstructed, target) }
1664 .map(|alloc| alloc.ptr.as_ptr())
1665 .unwrap_or_else(core::ptr::null_mut)
1666 }
1667
1668 unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
1669 // We are a slab allocator and do not deallocate.
1670 }
1671}
1672
1673fn layout_reallocated(
1674 layout: NonZeroLayout,
1675 target: core::num::NonZeroUsize,
1676) -> Option<NonZeroLayout> {
1677 // This may not be a valid layout.
1678 let layout = Layout::from_size_align(target.get(), layout.align()).ok()?;
1679 // This must succeed though, as the size was non-zero.
1680 Some(NonZeroLayout::from_layout(layout.into()).unwrap())
1681}
1682
1683unsafe impl<'alloc, T> LocalAlloc<'alloc> for Bump<T> {
1684 fn alloc(&'alloc self, layout: NonZeroLayout) -> Option<alloc_traits::Allocation<'alloc>> {
1685 let raw_alloc = self.get_layout(layout.into())?;
1686 Some(alloc_traits::Allocation {
1687 ptr: raw_alloc.ptr,
1688 layout,
1689 lifetime: AllocTime::default(),
1690 })
1691 }
1692
1693 unsafe fn realloc(
1694 &'alloc self,
1695 alloc: alloc_traits::Allocation<'alloc>,
1696 layout: NonZeroLayout,
1697 ) -> Option<alloc_traits::Allocation<'alloc>> {
1698 if alloc.ptr.as_ptr() as usize % layout.align() == 0 && alloc.layout.size() >= layout.size()
1699 {
1700 // Obvious fit, nothing to do.
1701 return Some(alloc_traits::Allocation {
1702 ptr: alloc.ptr,
1703 layout,
1704 lifetime: alloc.lifetime,
1705 });
1706 }
1707
1708 // TODO: we could try to allocate at the exact level that the allocation ends. If this
1709 // succeeds, there is no copying necessary. This was the point of `Level` anyways.
1710
1711 let new_alloc = LocalAlloc::alloc(self, layout)?;
1712
1713 // Safety:
1714 // - the old allocation is valid for the old size, as required of the caller.
1715 // - the old allocation is valid for reads as it is an allocation of the allocator.
1716 // - the new allocation is valid for the new size.
1717 // - the new allocation is valid for writes as it was successful.
1718 // - our effective copy is at most the old and new size.
1719 unsafe {
1720 core::ptr::copy_nonoverlapping(
1721 alloc.ptr.as_ptr(),
1722 new_alloc.ptr.as_ptr(),
1723 layout.size().min(alloc.layout.size()).into(),
1724 );
1725 }
1726
1727 // No dealloc.
1728 Some(new_alloc)
1729 }
1730
1731 unsafe fn dealloc(&'alloc self, _: alloc_traits::Allocation<'alloc>) {
1732 // We are a slab allocator and do not deallocate.
1733 }
1734}
1735
1736unsafe impl<'alloc> LocalAlloc<'alloc> for BumpView<'alloc> {
1737 fn alloc(&'alloc self, layout: NonZeroLayout) -> Option<alloc_traits::Allocation<'alloc>> {
1738 let raw_alloc = self.get_layout(layout.into())?;
1739 Some(alloc_traits::Allocation {
1740 ptr: raw_alloc.ptr,
1741 layout,
1742 lifetime: AllocTime::default(),
1743 })
1744 }
1745
1746 // TODO: alloc zeroed if the constructor was `Self::zeroed()`
1747
1748 /// Reallocates if the layout is strictly smaller and the allocation aligned.
1749 ///
1750 /// Note that this may succeed spuriously if the previous allocation is incidentally aligned to
1751 /// a larger alignment than had been request.
1752 ///
1753 /// Also not, reallocating to a smaller layout is NOT useless.
1754 ///
1755 /// It confirms that this allocator does not need the allocated layout to re/deallocate.
1756 /// Otherwise, even reallocating to a strictly smaller layout would be impossible without
1757 /// storing the prior layout.
1758 unsafe fn realloc(
1759 &'alloc self,
1760 alloc: alloc_traits::Allocation<'alloc>,
1761 layout: NonZeroLayout,
1762 ) -> Option<alloc_traits::Allocation<'alloc>> {
1763 if alloc.ptr.as_ptr() as usize % layout.align() == 0 && alloc.layout.size() >= layout.size()
1764 {
1765 // Obvious fit, nothing to do.
1766 return Some(alloc_traits::Allocation {
1767 ptr: alloc.ptr,
1768 layout,
1769 lifetime: alloc.lifetime,
1770 });
1771 }
1772
1773 // TODO: we could try to allocate at the exact level that the allocation ends. If this
1774 // succeeds, there is no copying necessary. This was the point of `Level` anyways.
1775
1776 let new_alloc = LocalAlloc::alloc(self, layout)?;
1777
1778 // Safety:
1779 // - the old allocation is valid for the old size, as required of the caller.
1780 // - the old allocation is valid for reads as it is an allocation of the allocator.
1781 // - the new allocation is valid for the new size.
1782 // - the new allocation is valid for writes as it was successful.
1783 // - our effective copy is at most the old and new size.
1784 unsafe {
1785 core::ptr::copy_nonoverlapping(
1786 alloc.ptr.as_ptr(),
1787 new_alloc.ptr.as_ptr(),
1788 layout.size().min(alloc.layout.size()).into(),
1789 );
1790 }
1791
1792 // No dealloc.
1793 Some(new_alloc)
1794 }
1795
1796 unsafe fn dealloc(&'alloc self, _: alloc_traits::Allocation<'alloc>) {
1797 // We are a slab allocator and do not deallocate.
1798 }
1799}
1800
1801#[cfg(test)]
1802mod tests {
1803 use super::*;
1804
1805 #[test]
1806 fn zst_no_drop() {
1807 #[derive(Debug)]
1808 struct PanicOnDrop;
1809
1810 impl Drop for PanicOnDrop {
1811 fn drop(&mut self) {
1812 panic!("No instance of this should ever get dropped");
1813 }
1814 }
1815
1816 let alloc = Bump::<()>::uninit();
1817 let _ = alloc.leak(PanicOnDrop).unwrap();
1818 }
1819}