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)]
186pub(crate) struct BumpView<'lt> {
187 header: &'lt Header,
188 storage: &'lt UnsafeCell<[MaybeUninit<u8>]>,
189}
190
191/// NOTE: see the problem of freely dereferencing a `Bump<T>` into `BumpSlice` where the offset of
192/// `storage` must not be affected. This is caused by the align of `T` exceeding that of the header.
193/// If instead we included such information into the header we could fully support this
194/// dereferencing again, at the cost of a few bits. There is no need to actually read those bits
195/// when we're using it in a `Bump` as we only need to reconstruct the right `storage` slice when
196/// used as a `BumpSlice`. The extra struct padding will only appear as more MaybeUninit data in the
197/// unsized type.
198#[repr(C)]
199struct Header {
200 consumed: AtomicUsize,
201}
202
203/// A value could not be moved into a slab allocation.
204///
205/// The error contains the value for which the allocation failed. Storing the value in the error
206/// keeps it alive in all cases. This prevents the `Drop` implementation from running and preserves
207/// resources which may otherwise not be trivial to restore.
208#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
209pub struct LeakError<T> {
210 val: T,
211 failure: Failure,
212}
213
214/// Specifies an amount of consumed space of a slab.
215///
216/// Each allocation of the `Bump` increases the current level as they must not be empty. By
217/// ensuring that an allocation is performed at a specific level it is thus possible to check that
218/// multiple allocations happened in succession without other intermediate allocations. This
219/// ability in turns makes it possible to group allocations together, for example to initialize a
220/// `#[repr(C)]` struct member-by-member or to extend a slice.
221///
222/// ## Usage
223///
224/// The main use is successively allocating a slice without requiring all data to be present at
225/// once. Other similar interface often require an internal locking mechanism but `Level` leaves
226/// the choice to the user. This is not yet encapsulate in a safe API yet `Level` makes it easy to
227/// reason about.
228///
229/// See [`MemBump::get_unchecked`](`crate::bump::BumpSlice`) for redeeming a value.
230///
231/// ## Unsound usage.
232///
233/// FIXME: the below is UB because we don't gain provenance over the complete array, only each
234/// individual element. Instead, we must derive a new pointer from the allocator!
235///
236/// ```
237/// # use core::slice;
238/// # use static_alloc::bump::{Level, Bump};
239/// static BUMP: Bump<[u64; 4]> = Bump::uninit();
240///
241/// /// Gathers as much data as possible.
242/// ///
243/// /// An arbitrary amount of data, can't stack allocate!
244/// fn gather_data(mut iter: impl Iterator<Item=u64>) -> &'static mut [u64] {
245/// let first = match iter.next() {
246/// Some(item) => item,
247/// None => return &mut [],
248/// };
249///
250/// let mut level: Level = BUMP.level();
251/// let mut start: Level = BUMP.level();
252/// let mut count;
253///
254/// match BUMP.leak_at(first, level) {
255/// Ok((_first, first_level)) => {
256/// // Note we must throw away the first pointer. Its provenance does not
257/// // cover the other fields. Only its level can be used.
258/// level = first_level;
259/// count = 1;
260/// },
261/// _ => return &mut [],
262/// }
263///
264/// let _ = iter.try_for_each(|value: u64| {
265/// match BUMP.leak_at(value, level) {
266/// Err(err) => return Err(err),
267/// Ok((_, new_level)) => level = new_level,
268/// };
269/// count += 1;
270/// Ok(())
271/// });
272///
273/// unsafe {
274/// // Safety: we have an allocation here
275/// let begin = BUMP.get_unchecked(start);
276/// // SAFETY: all `count` allocations are contiguous, begin is well aligned and no
277/// // reference is currently pointing at any of the values. The lifetime is `'static` as
278/// // the BUMP itself is static.
279/// slice::from_raw_parts_mut(begin.ptr.as_ptr(), count)
280/// }
281/// }
282///
283/// fn main() {
284/// // There is no other thread running, so this succeeds.
285/// let slice = gather_data(0..=3);
286/// assert_eq!(slice, [0, 1, 2, 3]);
287/// }
288/// ```
289#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
290pub struct Level(pub(crate) usize);
291
292impl Level {
293 /// Get the byte offset with respect to the arena [`data_ptr`](`Bump::data_ptr`).
294 pub fn byte_offset(&self) -> usize {
295 self.0
296 }
297}
298
299/// A successful allocation and current [`Level`].
300///
301/// [`Level`]: struct.Level.html
302///
303/// ## Design notes
304///
305/// The `ptr` field is, when returned by an allocator, always a valid pointer. However, we can not
306/// express this as a mutable reference to `MaybeUninit` for unsized types. Instead, a pointer is
307/// needed to provide address, provenance, and pointer metadata. The cost of this is that we discard
308/// the validity information which has to be unsafely re-applied by the user (of course, verifying
309/// that the point actually is valid since this type is fully public).
310#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
311pub struct Allocation<'a, T: ?Sized = u8> {
312 /// Pointer to the uninitialized region with specified layout.
313 pub ptr: NonNull<T>,
314
315 /// The lifetime of the allocation.
316 pub lifetime: AllocTime<'a>,
317
318 /// The observed amount of consumed bytes after the allocation.
319 ///
320 /// For `Bump` this is precise, i.e. the offset of the `ptr` in the arena data is the level's
321 /// byte offset minus the layout size.
322 pub level: Level,
323}
324
325impl<T> Allocation<'_, T> {
326 /// Get the `Level` at which the allocation starts.
327 ///
328 /// This can be used as the level of [`Bump::get_unchecked`] with the arena it as allocated
329 /// from. There is an equivalent method for some unsized types.
330 ///
331 /// # Usage
332 ///
333 /// ```
334 /// use static_alloc::Bump;
335 ///
336 /// let arena = Bump::<[u32; 4]>::uninit();
337 /// let alloc = arena.get::<u32>().unwrap();
338 ///
339 /// assert_eq!(alloc.level.byte_offset(), 4);
340 /// assert_eq!(alloc.level_start().byte_offset(), 0);
341 /// ```
342 pub fn level_start(&self) -> Level {
343 Level(self.level.byte_offset() - mem::size_of::<T>())
344 }
345}
346
347impl<T> Allocation<'_, [T]> {
348 /// Get the `Level` at which the allocation starts.
349 ///
350 /// This can be used as the level of [`Bump::get_unchecked`] with the arena it as allocated
351 /// from. There is an equivalent method for some unsized types.
352 ///
353 /// See the sized [`Allocation::level_start`].
354 pub fn level_start(&self) -> Level {
355 Level(self.level.byte_offset() - mem::size_of::<T>() * self.ptr.len())
356 }
357}
358
359/// Reason for a failed allocation at an exact [`Level`].
360///
361/// [`Level`]: struct.Level.html
362#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
363pub enum Failure {
364 /// No space left for that allocation.
365 Exhausted,
366
367 /// The allocation would not have used the expected base location.
368 ///
369 /// Reports the location that was observed. When only levels from the same slab are used (which
370 /// should normally be the case) then the observed level is monotonically increasing.
371 Mismatch {
372 /// The observed level that was different from the requested one.
373 observed: Level,
374 },
375}
376
377impl<T> Bump<T> {
378 /// Make a new allocatable slab of certain byte size and alignment.
379 ///
380 /// The storage will contain uninitialized bytes.
381 pub const fn uninit() -> Self {
382 Bump {
383 header: Header::empty(),
384 storage: UnsafeCell::new(MaybeUninit::uninit()),
385 }
386 }
387
388 /// Make a new allocatable slab of certain byte size and alignment.
389 ///
390 /// The storage will contain zeroed bytes. This is not *yet* available
391 /// as a `const fn` which currently limits its potential usefulness
392 /// but there is no good reason not to provide it regardless.
393 pub fn zeroed() -> Self {
394 Bump {
395 header: Header::empty(),
396 storage: UnsafeCell::new(MaybeUninit::zeroed()),
397 }
398 }
399
400 /// Make a new allocatable slab provided with some bytes it can hand out.
401 ///
402 /// Note that `storage` will never be dropped and there is no way to get it back.
403 pub const fn new(storage: T) -> Self {
404 Bump {
405 header: Header::empty(),
406 storage: UnsafeCell::new(MaybeUninit::new(storage)),
407 }
408 }
409
410 /// Convert this into a type-erased byte-slice bump allocator.
411 ///
412 /// This returns `None` if the layout of `T` causes the layout of `self` to not be compatible
413 /// with the layout of [`BumpSlice`]. The criteria is that `T` must have an alignment not greater
414 /// than that of `usize` (which is used internally for accounting the used portion).
415 ///
416 /// For instance, this is guaranteed to work:
417 ///
418 /// ```
419 /// use static_alloc::Bump;
420 ///
421 /// let byte_array: Bump<[u8; 128]> = Bump::uninit();
422 /// assert!(byte_array.as_bump_slice().is_some());
423 /// let usize_array: Bump<[usize; 128]> = Bump::uninit();
424 /// assert!(usize_array.as_bump_slice().is_some());
425 /// ```
426 ///
427 /// On the other hand, this is very unlikely to work on any platform:
428 ///
429 /// ```
430 /// # if core::mem::size_of::<usize>() < 32 {
431 /// use static_alloc::Bump;
432 ///
433 /// #[repr(C, align(32))]
434 /// struct WhyAlignSoHigh([u8; 128]);
435 ///
436 /// let oof: Bump<WhyAlignSoHigh> = Bump::uninit();
437 /// assert!(oof.as_bump_slice().is_none());
438 /// # }
439 /// ```
440 pub const fn as_bump_slice(&self) -> Option<&BumpSlice> {
441 // Safety:
442 if mem::offset_of!(Self, storage) != mem::size_of::<Header>() {
443 return None;
444 }
445
446 let data_len = mem::size_of::<T>();
447 // Construct a point with the meta data of a slice to `data`, but pointing to the whole
448 // struct instead. This meta data is later copied to the meta data of `bump` when cast.
449 let ptr = (self as *const Self).cast::<MaybeUninit<u8>>();
450 let mem: *const [MaybeUninit<u8>] = core::ptr::slice_from_raw_parts(ptr, data_len);
451
452 // Safety: The layout of this type is compatible with ours. Both are `repr(C)`, so we can go
453 // field-by-field and the total layout.
454 //
455 // - Firstly, they share a `Header` field.
456 // - Secondly, `data` is located immediately behind `Header`. In `self` we verify this
457 // above, in `BumpSlice` that follows directly from `u8` being 1-aligned.
458 // - The alignment requirement of `MemBump`, exactly that of `Header`, is fulfilled as that
459 // is also a field of `Self`.
460 // - The size of both values is compatible. We construct the metadata such that the return
461 // value covers exactly the length of the `storage` field. What follows is padding to
462 // cover the alignment requirement. The `Self` type has the same alignment and same offset
463 // past-the-field and hence will receive the same padding.
464 Some(unsafe { &*(mem as *const BumpSlice) })
465 }
466
467 /// Mutable variant of [`Self::as_bump_slice`].
468 pub const fn as_mut_bump_slice(&mut self) -> Option<&mut BumpSlice> {
469 // Safety:
470 if mem::offset_of!(Self, storage) != mem::size_of::<Header>() {
471 return None;
472 }
473
474 let data_len = mem::size_of::<T>();
475 // Construct a point with the meta data of a slice to `data`, but pointing to the whole
476 // struct instead. This meta data is later copied to the meta data of `bump` when cast.
477 let ptr = (self as *mut Self).cast::<MaybeUninit<u8>>();
478 let mem: *mut [MaybeUninit<u8>] = core::ptr::slice_from_raw_parts_mut(ptr, data_len);
479
480 // Safety: The layout of this type is compatible with ours. Both are `repr(C)`, so we can go
481 // field-by-field and the total layout.
482 //
483 // - Firstly, they share a `Header` field.
484 // - Secondly, `data` is located immediately behind `Header`. In `self` we verify this
485 // above, in `MemBump` that follows directly from `u8` being 1-aligned.
486 // - The alignment requirement of `MemBump`, exactly that of `Header`, is fulfilled as that
487 // is also a field of `Self`.
488 // - The size of both values is compatible. We construct the metadata such that the return
489 // value covers exactly the length of the `storage` field. What follows is padding to
490 // cover the alignment requirement. The `Self` type has the same alignment and same offset
491 // past-the-field and hence will receive the same padding.
492 Some(unsafe { &mut *(mem as *mut BumpSlice) })
493 }
494
495 /// Construct a bump allocator into an uninitialized memory location.
496 ///
497 /// This fills in only a constant sized header. The rest of the allocation is left-as, i.e. if
498 /// remains initialized exactly in those spots the caller may have initialized with external
499 /// means.
500 ///
501 /// Note that this method is `const` (though this is not particularly useful yet as of `0.3.0`).
502 ///
503 /// # Usage
504 ///
505 /// This method allows `Bump` to be used together with interfaces that require an outer
506 /// `MaybeUninit` for their safety proofs, e.g. [`Box::new_uninit_slice`].
507 ///
508 /// ```
509 /// # use static_alloc::bump::Bump;
510 /// type Allocator = Bump<[u32; 128]>;
511 ///
512 /// # let num_components = 4;
513 /// // 4 independent allocators, e.g. for four components of your software.
514 /// // Still guaranteed to live in consecutive memory.
515 /// let mut allocators = Box::<[Allocator]>::new_uninit_slice(num_components);
516 ///
517 /// // The index here might be a runtime address.
518 /// // Now this arena can be used without initializing the others already.
519 /// let c0 = Bump::from_maybe_uninit(&mut allocators[0]);
520 /// // Etc. Use this temporary stack allocator.
521 /// let _ = c0.leak_box(0xdead_beefusize);
522 /// ```
523 pub const fn from_maybe_uninit(data: &mut MaybeUninit<Self>) -> &'_ mut Self {
524 // Safety: dereferencing a pointer into a `&mut MaybeUninit`.
525 let header = unsafe { &raw mut (*data.as_mut_ptr()).header };
526 // Safety: pointer points into a `MaybeUninit` which we have derived a mutable provenance
527 // pointer into.
528 unsafe { core::ptr::write(header, Header::empty()) };
529 // Safety: only the header field requires initialization. The storage is a no-op.
530 unsafe { data.assume_init_mut() }
531 }
532
533 /// Construct a bump allocator into an existing dynamically sized arena of memory.
534 ///
535 /// Note that this method also exists for a dynamically sized
536 /// [`BumpSlice`][`BumpSlice::from_memory`] which can make use of almost arbitrarily sized
537 /// blocks of data. In comparison, this method requires that at least `size_of::<Self>` data at
538 /// an aligned location in the slice is available.
539 ///
540 /// Returns `None` if there are not enough bytes beyond the first aligned offset to hold a value
541 /// of `Self` type.
542 ///
543 /// # Usage
544 ///
545 /// This way you may re-use storage from some arbitrary existing span of memory, provided it has
546 /// at least enough room to hold an aligned header.
547 ///
548 /// ```
549 /// use core::mem::MaybeUninit;
550 /// use static_alloc::bump::Bump;
551 /// # fn example() -> Option<()> {
552 ///
553 /// let mut buffer = MaybeUninit::<[u8; 256]>::uninit();
554 /// let bump = Bump::<[u8; 200]>::from_memory(buffer.as_mut())?;
555 ///
556 /// // Slightly less than 256 free bytes of memory to use.
557 /// // Exact number is unstable and depends on the align of `buffer`.
558 /// let allocated_slice = bump.get_slice::<u32>(50)?;
559 ///
560 /// # Some(()) }
561 /// ```
562 pub fn from_memory(data: &mut [MaybeUninit<u8>]) -> Option<&'_ mut Self> {
563 // Safety: `MaybeUninit<Self>` is always valid.
564 let (_, usable, _) = unsafe { data.align_to_mut::<MaybeUninit<Self>>() };
565 usable.first_mut().map(Self::from_maybe_uninit)
566 }
567
568 /// Reset the bump allocator.
569 ///
570 /// Requires a mutable reference, as no allocations can be active when doing it. This behaves
571 /// as if a fresh instance was assigned but it does not overwrite the bytes in the backing
572 /// storage. (You can unsafely rely on this).
573 ///
574 /// ## Usage
575 ///
576 /// ```
577 /// # use static_alloc::Bump;
578 /// let mut stack_buf = Bump::<usize>::uninit();
579 ///
580 /// let bytes = stack_buf.leak(0usize.to_be_bytes()).unwrap();
581 /// // Now the bump allocator is full.
582 /// assert!(stack_buf.leak(0u8).is_err());
583 ///
584 /// // We can reuse if we are okay with forgetting the previous value.
585 /// stack_buf.reset();
586 /// let val = stack_buf.leak(0usize).unwrap();
587 /// ```
588 ///
589 /// Trying to use the previous value does not work, as the stack is still borrowed. Note that
590 /// any user unsafely tracking the lifetime must also ensure this through proper lifetimes that
591 /// guarantee that borrows are alive for appropriate times.
592 ///
593 /// ```compile_fail
594 /// // error[E0502]: cannot borrow `stack_buf` as mutable because it is also borrowed as immutable
595 /// # use static_alloc::Bump;
596 /// let mut stack_buf = Bump::<usize>::uninit();
597 ///
598 /// let bytes = stack_buf.leak(0usize).unwrap();
599 /// // --------- immutably borrow occurs here
600 /// stack_buf.reset();
601 /// // ^^^^^^^ mutable borrow occurs here.
602 /// let other = stack_buf.leak(0usize).unwrap();
603 ///
604 /// *bytes += *other;
605 /// // ------------- immutable borrow later used here
606 /// ```
607 pub fn reset(&mut self) {
608 self.header = Header::empty();
609 }
610
611 pub(crate) fn as_view(&self) -> BumpView<'_> {
612 BumpView {
613 header: &self.header,
614 storage: {
615 let base = self.storage.get();
616 let len = mem::size_of::<T>();
617 let data = core::ptr::slice_from_raw_parts(base as *const _, len);
618 // Safety: covers exactly the memory of `storage`, which is a `MaybeUninit`.
619 unsafe { &*(data as *const UnsafeCell<[_]>) }
620 },
621 }
622 }
623
624 /// Returns capacity of this allocator.
625 ///
626 /// This is how many *bytes* can be allocated within this allocator in total, with no
627 /// information about the currently consumed count.
628 pub const fn capacity(&self) -> usize {
629 mem::size_of::<T>()
630 }
631
632 /// Get a raw pointer to the data.
633 ///
634 /// Note that *any* use of the pointer must be done with extreme care as it may invalidate
635 /// existing references into the allocated region. Furthermore, bytes may not be initialized.
636 /// The length of the valid region is [`BumpSlice::capacity`].
637 ///
638 /// Prefer [`Self::get_unchecked`] for reconstructing a prior allocation.
639 pub fn data_ptr(&self) -> NonNull<u8> {
640 NonNull::from(&self.storage).cast()
641 }
642
643 /// Allocate a region of memory.
644 ///
645 /// This is a safe alternative to [GlobalAlloc::alloc](#impl-GlobalAlloc).
646 ///
647 /// # Panics
648 /// This function will panic if the requested layout has a size of `0`. For the use in a
649 /// `GlobalAlloc` this is explicitely forbidden to request and would allow any behaviour but we
650 /// instead strictly check it.
651 pub fn alloc(&self, layout: Layout) -> Option<NonNull<u8>> {
652 self.as_view().alloc(layout)
653 }
654
655 /// Try to allocate some layout with a precise base location.
656 ///
657 /// The base location is the currently consumed byte count, without correction for the
658 /// alignment of the allocation. This will succeed if it can be allocate exactly at the
659 /// expected location.
660 ///
661 /// # Panics
662 /// This function may panic if the provided `level` is from a different slab.
663 pub fn alloc_at(&self, layout: Layout, level: Level) -> Result<Allocation<'_>, Failure> {
664 self.as_view().alloc_at(layout, level)
665 }
666
667 /// Get an allocation with detailed layout.
668 ///
669 /// Provides an [`Uninit`] wrapping several aspects of initialization in a safe interface,
670 /// bound by the lifetime of the reference to the allocator.
671 ///
672 /// [`Uninit`]: ../uninit/struct.Uninit.html
673 pub fn get_layout(&self, layout: Layout) -> Option<Allocation<'_>> {
674 self.as_view().get_layout(layout)
675 }
676
677 /// Get an allocation with detailed layout at a specific level.
678 ///
679 /// Provides an [`Uninit`] wrapping several aspects of initialization in a safe interface,
680 /// bound by the lifetime of the reference to the allocator.
681 ///
682 /// Since the underlying allocation is the same, it would be `unsafe` but justified to fuse
683 /// this allocation with the preceding or succeeding one.
684 ///
685 /// [`Uninit`]: ../uninit/struct.Uninit.html
686 pub fn get_layout_at(&self, layout: Layout, at: Level) -> Result<Allocation<'_>, Failure> {
687 self.as_view().get_layout_at(layout, at)
688 }
689
690 /// Get an allocation for a specific type.
691 ///
692 /// It is not yet initialized but provides a safe interface for that initialization.
693 ///
694 /// ## Usage
695 ///
696 /// ```
697 /// # use static_alloc::Bump;
698 /// use core::cell::{Ref, RefCell};
699 ///
700 /// let slab: Bump<[Ref<'static, usize>; 1]> = Bump::uninit();
701 /// let data = RefCell::new(0xff);
702 ///
703 /// // We can place a `Ref` here but we did not yet.
704 /// let alloc = slab.get::<Ref<usize>>().unwrap();
705 /// let cell_ref = unsafe {
706 /// alloc.leak(data.borrow())
707 /// };
708 ///
709 /// assert_eq!(**cell_ref, 0xff);
710 /// ```
711 pub fn get<V>(&self) -> Option<Allocation<'_, V>> {
712 self.as_view().get()
713 }
714
715 /// Get an allocation for a specific type at a specific level.
716 ///
717 /// See [`get`](`Self::get`) for usage.
718 pub fn get_at<V>(&self, level: Level) -> Result<Allocation<'_, V>, Failure> {
719 self.as_view().get_at(level)
720 }
721
722 /// Get an allocation for a slice of a type.
723 ///
724 /// Returns `None` if the allocation fails (see [`Self::get`]) or if the slice layout can not be
725 /// computed due to an overflow with this size.
726 ///
727 /// # Examples
728 ///
729 /// ```
730 /// # use static_alloc::bump::Bump;
731 ///
732 /// let slab: Bump<[usize; 6]> = Bump::uninit();
733 ///
734 /// let first = slab.get_slice::<usize>(4).unwrap();
735 /// let second = slab.get_slice::<usize>(2).unwrap();
736 /// assert!(slab.get_slice::<usize>(1).is_none());
737 ///
738 /// assert_eq!(first.ptr.len(), 4);
739 /// assert_eq!(second.ptr.len(), 2);
740 /// ```
741 ///
742 /// ```
743 /// # use static_alloc::bump::Bump;
744 ///
745 /// let slab: Bump<[usize; 1]> = Bump::uninit();
746 ///
747 /// let lots_of_empty = slab.get_slice::<()>(usize::MAX).unwrap();
748 /// assert_eq!(lots_of_empty.ptr.len(), usize::MAX);
749 /// ```
750 ///
751 /// ```
752 /// # use static_alloc::bump::Bump;
753 ///
754 /// let slab: Bump<[usize; 1]> = Bump::uninit();
755 ///
756 /// let _exhaust = slab.get_slice::<usize>(1).unwrap();
757 /// assert!(slab.get_slice::<usize>(1).is_none());
758 /// let empty_slice = slab.get_slice::<usize>(0).unwrap();
759 /// ```
760 pub fn get_slice<V>(&self, len: usize) -> Option<Allocation<'_, [V]>> {
761 self.as_view().get_slice(len)
762 }
763
764 /// Move a value into an owned allocation.
765 ///
766 /// For safely initializing a value _after_ a successful allocation, see [`LeakBox::write`].
767 ///
768 /// [`LeakBox::write`]: ../leaked/struct.LeakBox.html#method.write
769 ///
770 /// ## Usage
771 ///
772 /// This can be used to push the value into a caller provided stack buffer where it lives
773 /// longer than the current stack frame. For example, you might create a linked list with a
774 /// dynamic number of values living in the frame below while still being dropped properly. This
775 /// is impossible to do with a return value.
776 ///
777 /// ```
778 /// # use static_alloc::Bump;
779 /// # use static_alloc::leaked::LeakBox;
780 /// fn rand() -> usize { 4 }
781 ///
782 /// enum Chain<'buf, T> {
783 /// Tail,
784 /// Link(T, LeakBox<'buf, Self>),
785 /// }
786 ///
787 /// fn make_chain<Buf, T>(buf: &Bump<Buf>, mut new_node: impl FnMut() -> T)
788 /// -> Option<Chain<'_, T>>
789 /// {
790 /// let count = rand();
791 /// let mut chain = Chain::Tail;
792 /// for _ in 0..count {
793 /// let node = new_node();
794 /// chain = Chain::Link(node, buf.leak_box(chain)?);
795 /// }
796 /// Some(chain)
797 /// }
798 ///
799 /// struct Node (usize);
800 /// impl Drop for Node {
801 /// fn drop(&mut self) {
802 /// println!("Dropped {}", self.0);
803 /// }
804 /// }
805 /// let mut counter = 0..;
806 /// let new_node = || Node(counter.next().unwrap());
807 ///
808 /// let buffer: Bump<[u8; 128]> = Bump::uninit();
809 /// let head = make_chain(&buffer, new_node).unwrap();
810 ///
811 /// // Prints the message in reverse order.
812 /// // Dropped 3
813 /// // Dropped 2
814 /// // Dropped 1
815 /// // Dropped 0
816 /// drop(head);
817 /// ```
818 pub fn leak_box<V>(&self, val: V) -> Option<LeakBox<'_, V>> {
819 self.as_view().leak_box(val)
820 }
821
822 /// Move a value into an owned allocation.
823 ///
824 /// See [`leak_box`] for usage.
825 ///
826 /// [`leak_box`]: #method.leak_box
827 pub fn leak_box_at<V>(&self, val: V, level: Level) -> Result<LeakBox<'_, V>, Failure> {
828 self.as_view().leak_box_at(val, level)
829 }
830
831 /// Observe the current level.
832 ///
833 /// Keep in mind that concurrent usage of the same slab may modify the level before you are
834 /// able to use it in `alloc_at`. Calling this method provides also no other guarantees on
835 /// synchronization of memory accesses, only that the values observed by the caller are a
836 /// monotonically increasing seequence while a shared reference exists.
837 pub fn level(&self) -> Level {
838 self.as_view().level()
839 }
840
841 /// Get a pointer to an existing allocation at a specific level.
842 ///
843 /// The resulting pointer may be used to access an arbitrary allocation starting at the pointer
844 /// (i.e. including additional allocations immediately afterwards) but the caller is
845 /// responsible for ensuring that these accesses do not overlap other accesses. There must be
846 /// no more life [`LeakBox`] to any allocation being accessed this way.
847 ///
848 /// # Safety
849 ///
850 /// - The level must refer to an existing allocation, i.e. it must previously have been
851 /// returned in [`Allocation::level_start`].
852 /// - As a corollary, particular it must be in-bounds of the allocator's memory.
853 /// - Another consequence, the result pointer must be aligned for the requested type.
854 pub unsafe fn get_unchecked<V>(&self, level: Level) -> Allocation<'_, V> {
855 // Safety: forwarding requirements.
856 unsafe { self.as_view().get_unchecked(level) }
857 }
858
859 /// Allocate a value for the lifetime of the allocator.
860 ///
861 /// The value is leaked in the sense that
862 ///
863 /// 1. the drop implementation of the allocated value is never called;
864 /// 2. reusing the memory for another allocation in the same `Bump` requires manual unsafe code
865 /// to handle dropping and reinitialization.
866 ///
867 /// However, it does not mean that the underlying memory used for the allocated value is never
868 /// reclaimed. If the `Bump` itself is a stack value then it will get reclaimed together with
869 /// it.
870 ///
871 /// ## Safety notice
872 ///
873 /// It is important to understand that it is undefined behaviour to reuse the allocation for
874 /// the *whole lifetime* of the returned reference. That is, dropping the allocation in-place
875 /// while the reference is still within its lifetime comes with the exact same unsafety caveats
876 /// as [`ManuallyDrop::drop`](`core::mem::ManuallyDrop::drop`).
877 ///
878 /// ```
879 /// # use static_alloc::Bump;
880 /// #[derive(Debug, Default)]
881 /// struct FooBar {
882 /// // ...
883 /// # _private: [u8; 1],
884 /// }
885 ///
886 /// let local: Bump<[FooBar; 3]> = Bump::uninit();
887 /// let one = local.leak(FooBar::default()).unwrap();
888 ///
889 /// // Dangerous but justifiable.
890 /// let one = unsafe {
891 /// // Ensures there is no current mutable borrow.
892 /// core::ptr::drop_in_place(&mut *one);
893 /// };
894 /// ```
895 ///
896 /// ## Usage
897 ///
898 /// ```
899 /// use static_alloc::Bump;
900 ///
901 /// let local: Bump<[u64; 3]> = Bump::uninit();
902 ///
903 /// let one = local.leak(0_u64).unwrap();
904 /// assert_eq!(*one, 0);
905 /// *one = 42;
906 /// ```
907 ///
908 /// ## Limitations
909 ///
910 /// Only sized values can be allocated in this manner for now, unsized values are blocked on
911 /// stabilization of [`ptr::slice_from_raw_parts`]. We can not otherwise get a fat pointer to
912 /// the allocated region.
913 ///
914 /// [`ptr::slice_from_raw_parts`]: https://github.com/rust-lang/rust/issues/36925
915 ///
916 /// TODO: will be deprecated sooner or later in favor of a method that does not move the
917 /// resource on failure.
918 // #[deprecated = "Use leak_box and initialize it with the value. This does not move the value in the failure case."]
919 #[expect(clippy::mut_from_ref)] // This is an allocator.
920 pub fn leak<V>(&self, val: V) -> Result<&mut V, LeakError<V>> {
921 match self.get::<V>() {
922 // SAFETY: Just allocated this for a `V`.
923 Some(alloc) => Ok(unsafe { alloc.leak(val) }),
924 None => Err(LeakError::new(val, Failure::Exhausted)),
925 }
926 }
927
928 /// Allocate a value with a precise location.
929 ///
930 /// See [`leak`] for basics on allocation of values.
931 ///
932 /// The level is an identifer for a base location (more at [`level`]). This will succeed if it
933 /// can be allocate exactly at the expected location.
934 ///
935 /// This method will return the new level of the slab allocator. A next allocation at the
936 /// returned level will be placed next to this allocation, only separated by necessary padding
937 /// from alignment. In particular, this is the same strategy as applied for the placement of
938 /// `#[repr(C)]` struct members. (Except for the final padding at the last member to the full
939 /// struct alignment.)
940 ///
941 /// ## Usage
942 ///
943 /// ```
944 /// use static_alloc::Bump;
945 ///
946 /// let local: Bump<[u64; 3]> = Bump::uninit();
947 ///
948 /// let base = local.level();
949 /// let (one, level) = local.leak_at(1_u64, base).unwrap();
950 /// // Will panic when an allocation happens in between.
951 /// let (two, _) = local.leak_at(2_u64, level).unwrap();
952 ///
953 /// assert_eq!((one as *const u64).wrapping_offset(1), two);
954 /// ```
955 ///
956 /// [`leak`]: #method.leak
957 /// [`level`]: #method.level
958 ///
959 /// TODO: will be deprecated sooner or later in favor of a method that does not move the
960 /// resource on failure.
961 ///
962 // #[deprecated = "Use leak_box_at and initialize it with the value. This does not move the value in the failure case."]
963 #[expect(clippy::mut_from_ref)] // This is an allocator.
964 pub fn leak_at<V>(&self, val: V, level: Level) -> Result<(&mut V, Level), LeakError<V>> {
965 let alloc = match self.get_at::<V>(level) {
966 Ok(alloc) => alloc,
967 Err(err) => return Err(LeakError::new(val, err)),
968 };
969
970 // SAFETY: Just allocated this for a `V`.
971 let level = alloc.level;
972 let mutref = unsafe { alloc.leak(val) };
973 Ok((mutref, level))
974 }
975}
976
977impl BumpSlice {
978 /// Construct a bump allocator into an existing dynamically sized arena of memory.
979 ///
980 /// # Usage
981 ///
982 /// This way you may re-use storage from some arbitrary existing span of memory, provided it has
983 /// at least enough room to hold an aligned header.
984 ///
985 /// ```
986 /// use core::mem::MaybeUninit;
987 /// use static_alloc::bump::BumpSlice;
988 /// # fn example() -> Option<()> {
989 ///
990 /// let mut buffer = MaybeUninit::<[u8; 256]>::uninit();
991 /// let bump = BumpSlice::from_memory(buffer.as_mut())?;
992 ///
993 /// // Slightly less than 256 free bytes of memory to use.
994 /// // Exact number is unstable and depends on the align of `buffer`.
995 /// let allocated_slice = bump.get_slice::<u32>(50)?;
996 ///
997 /// # Some(()) }
998 /// ```
999 pub fn from_memory(data: &mut [MaybeUninit<u8>]) -> Option<&'_ mut Self> {
1000 // First we must write a `Header` structure, the available storage then follows it. To do
1001 // this we create a temporary bump allocator with an external header.
1002 let start_addr = {
1003 let tmp_header = Header::empty();
1004 let data = UnsafeCell::from_mut(data);
1005
1006 let alloc = BumpView {
1007 header: &tmp_header,
1008 storage: &*data,
1009 };
1010
1011 // Initialize a header at some valid location in this data.
1012 let mut initialized_header = alloc.leak_box::<Header>(Header::empty())?;
1013 <*mut Header>::addr(&mut *initialized_header)
1014 };
1015
1016 // Time to drop the temporary allocator.
1017 let offset = start_addr - <*mut [_]>::addr(data);
1018 // This has the right address and provenance, but wrong len metadata for a `BumpSlice`.
1019 let bump_slice = &mut data[offset..];
1020
1021 let len = bump_slice.len() - core::mem::size_of::<Header>();
1022 let data = core::ptr::slice_from_raw_parts_mut(bump_slice.as_mut_ptr(), len);
1023
1024 Some(unsafe { &mut *(data as *mut BumpSlice) })
1025 }
1026
1027 /// Reset the bump allocator.
1028 ///
1029 /// Requires a mutable reference, as no allocations can be active when doing it. This behaves
1030 /// as if a fresh instance was assigned but it does not overwrite the bytes in the backing
1031 /// storage. (You can unsafely rely on this).
1032 ///
1033 /// ## Usage
1034 ///
1035 /// ```
1036 /// # use static_alloc::bump::{Bump, BumpSlice};
1037 /// let mut stack_buf = Bump::<usize>::uninit();
1038 /// let stack_buf = stack_buf.as_mut_bump_slice().unwrap();
1039 ///
1040 /// let bytes = stack_buf.leak(0usize.to_be_bytes()).unwrap();
1041 /// // Now the bump allocator is full.
1042 /// assert!(stack_buf.leak(0u8).is_err());
1043 ///
1044 /// // We can reuse if we are okay with forgetting the previous value.
1045 /// stack_buf.reset();
1046 /// let val = stack_buf.leak(0usize).unwrap();
1047 /// ```
1048 ///
1049 /// Trying to use the previous value does not work, as the stack is still borrowed. Note that
1050 /// any user unsafely tracking the lifetime must also ensure this through proper lifetimes that
1051 /// guarantee that borrows are alive for appropriate times.
1052 ///
1053 /// ```compile_fail
1054 /// // error[E0502]: cannot borrow `stack_buf` as mutable because it is also borrowed as immutable
1055 /// # use static_alloc::bump::{Bump, BumpSlice};
1056 /// let mut stack_buf = Bump::<usize>::uninit();
1057 /// let stack_buf = stack_buf.as_mut_bump_slice().unwrap();
1058 ///
1059 /// let bytes = stack_buf.leak(0usize).unwrap();
1060 /// // --------- immutably borrow occurs here
1061 /// stack_buf.reset();
1062 /// // ^^^^^^^ mutable borrow occurs here.
1063 /// let other = stack_buf.leak(0usize).unwrap();
1064 ///
1065 /// *bytes += *other;
1066 /// // ------------- immutable borrow later used here
1067 /// ```
1068 pub fn reset(&mut self) {
1069 self.header = Header::empty();
1070 }
1071
1072 pub(crate) fn as_view(&self) -> BumpView<'_> {
1073 BumpView {
1074 header: &self.header,
1075 storage: &self.storage,
1076 }
1077 }
1078
1079 /// Returns capacity of this allocator.
1080 ///
1081 /// This is how many *bytes* can be allocated within this allocator in total, with no
1082 /// information about the currently consumed count.
1083 pub const fn capacity(&self) -> usize {
1084 self.storage.get().len()
1085 }
1086
1087 /// Get a raw pointer to the data.
1088 ///
1089 /// Note that *any* use of the pointer must be done with extreme care as it may invalidate
1090 /// existing references into the allocated region. Furthermore, bytes may not be initialized.
1091 /// The length of the valid region is [`BumpSlice::capacity`].
1092 ///
1093 /// Prefer [`Self::get_unchecked`] for reconstructing a prior allocation.
1094 pub fn data_ptr(&self) -> NonNull<u8> {
1095 NonNull::from(&self.storage).cast()
1096 }
1097
1098 /// Allocate a region of memory.
1099 ///
1100 /// This is a safe alternative to [GlobalAlloc::alloc](#impl-GlobalAlloc).
1101 ///
1102 /// # Panics
1103 /// This function will panic if the requested layout has a size of `0`. For the use in a
1104 /// `GlobalAlloc` this is explicitely forbidden to request and would allow any behaviour but we
1105 /// instead strictly check it.
1106 pub fn alloc(&self, layout: Layout) -> Option<NonNull<u8>> {
1107 self.as_view().alloc(layout)
1108 }
1109
1110 /// Try to allocate some layout with a precise base location.
1111 ///
1112 /// The base location is the currently consumed byte count, without correction for the
1113 /// alignment of the allocation. This will succeed if it can be allocate exactly at the
1114 /// expected location.
1115 ///
1116 /// # Panics
1117 /// This function may panic if the provided `level` is from a different slab.
1118 pub fn alloc_at(&self, layout: Layout, level: Level) -> Result<Allocation<'_>, Failure> {
1119 self.as_view().alloc_at(layout, level)
1120 }
1121
1122 /// Get an allocation with detailed layout.
1123 ///
1124 /// Provides an [`Uninit`] wrapping several aspects of initialization in a safe interface,
1125 /// bound by the lifetime of the reference to the allocator.
1126 ///
1127 /// [`Uninit`]: ../uninit/struct.Uninit.html
1128 pub fn get_layout(&self, layout: Layout) -> Option<Allocation<'_>> {
1129 self.as_view().get_layout(layout)
1130 }
1131
1132 /// Get an allocation with detailed layout at a specific level.
1133 ///
1134 /// Provides an [`Uninit`] wrapping several aspects of initialization in a safe interface,
1135 /// bound by the lifetime of the reference to the allocator.
1136 ///
1137 /// Since the underlying allocation is the same, it would be `unsafe` but justified to fuse
1138 /// this allocation with the preceding or succeeding one.
1139 ///
1140 /// [`Uninit`]: ../uninit/struct.Uninit.html
1141 pub fn get_layout_at(&self, layout: Layout, at: Level) -> Result<Allocation<'_>, Failure> {
1142 self.as_view().get_layout_at(layout, at)
1143 }
1144
1145 /// Get an allocation for a specific type.
1146 ///
1147 /// It is not yet initialized but provides a safe interface for that initialization.
1148 ///
1149 /// ## Usage
1150 ///
1151 /// ```
1152 /// # use static_alloc::bump::{Bump, BumpSlice};
1153 /// use core::cell::{Ref, RefCell};
1154 ///
1155 /// let backing: Bump<[Ref<'static, usize>; 1]> = Bump::uninit();
1156 /// let slab = backing.as_bump_slice().unwrap();
1157 ///
1158 /// let data = RefCell::new(0xff);
1159 ///
1160 /// // We can place a `Ref` here but we did not yet.
1161 /// let alloc = slab.get::<Ref<usize>>().unwrap();
1162 /// let cell_ref = unsafe {
1163 /// alloc.leak(data.borrow())
1164 /// };
1165 ///
1166 /// assert_eq!(**cell_ref, 0xff);
1167 /// ```
1168 pub fn get<V>(&self) -> Option<Allocation<'_, V>> {
1169 self.as_view().get()
1170 }
1171
1172 /// Get an allocation for a specific type at a specific level.
1173 ///
1174 /// See [`get`] for usage.
1175 ///
1176 /// [`get`]: #method.get
1177 pub fn get_at<V>(&self, level: Level) -> Result<Allocation<'_, V>, Failure> {
1178 self.as_view().get_at(level)
1179 }
1180
1181 /// Get an allocation for a slice of a type.
1182 ///
1183 /// Returns `None` if the allocation fails (see [`Self::get`]) or if the slice layout can not be
1184 /// computed due to an overflow with this size.
1185 ///
1186 /// # Examples
1187 ///
1188 /// ```
1189 /// # use static_alloc::bump::{Bump, BumpSlice};
1190 ///
1191 /// let backing: Bump<[usize; 6]> = Bump::uninit();
1192 /// let slab = backing.as_bump_slice().unwrap();
1193 ///
1194 /// let first = slab.get_slice::<usize>(4).unwrap();
1195 /// let second = slab.get_slice::<usize>(2).unwrap();
1196 /// assert!(slab.get_slice::<usize>(1).is_none());
1197 ///
1198 /// assert_eq!(first.ptr.len(), 4);
1199 /// assert_eq!(second.ptr.len(), 2);
1200 /// ```
1201 ///
1202 /// ```
1203 /// # use static_alloc::bump::{Bump, BumpSlice};
1204 ///
1205 /// let backing: Bump<[usize; 1]> = Bump::uninit();
1206 /// let slab = backing.as_bump_slice().unwrap();
1207 ///
1208 /// let lots_of_empty = slab.get_slice::<()>(usize::MAX).unwrap();
1209 /// assert_eq!(lots_of_empty.ptr.len(), usize::MAX);
1210 /// ```
1211 ///
1212 /// ```
1213 /// # use static_alloc::bump::{Bump, BumpSlice};
1214 ///
1215 /// let backing: Bump<[usize; 1]> = Bump::uninit();
1216 /// let slab = backing.as_bump_slice().unwrap();
1217 ///
1218 /// let _exhaust = slab.get_slice::<usize>(1).unwrap();
1219 /// assert!(slab.get_slice::<usize>(1).is_none());
1220 /// let empty_slice = slab.get_slice::<usize>(0).unwrap();
1221 /// ```
1222 pub fn get_slice<V>(&self, len: usize) -> Option<Allocation<'_, [V]>> {
1223 self.as_view().get_slice(len)
1224 }
1225
1226 /// Move a value into an owned allocation.
1227 ///
1228 /// For safely initializing a value _after_ a successful allocation, see [`LeakBox::write`].
1229 ///
1230 /// [`LeakBox::write`]: ../leaked/struct.LeakBox.html#method.write
1231 ///
1232 /// ## Usage
1233 ///
1234 /// This can be used to push the value into a caller provided stack buffer where it lives
1235 /// longer than the current stack frame. For example, you might create a linked list with a
1236 /// dynamic number of values living in the frame below while still being dropped properly. This
1237 /// is impossible to do with a return value.
1238 ///
1239 /// ```
1240 /// # use static_alloc::bump::{Bump, BumpSlice};
1241 /// # use static_alloc::leaked::LeakBox;
1242 /// fn rand() -> usize { 4 }
1243 ///
1244 /// enum Chain<'buf, T> {
1245 /// Tail,
1246 /// Link(T, LeakBox<'buf, Self>),
1247 /// }
1248 ///
1249 /// fn make_chain<T>(buf: &BumpSlice, mut new_node: impl FnMut() -> T)
1250 /// -> Option<Chain<'_, T>>
1251 /// {
1252 /// let count = rand();
1253 /// let mut chain = Chain::Tail;
1254 /// for _ in 0..count {
1255 /// let node = new_node();
1256 /// chain = Chain::Link(node, buf.leak_box(chain)?);
1257 /// }
1258 /// Some(chain)
1259 /// }
1260 ///
1261 /// struct Node (usize);
1262 /// impl Drop for Node {
1263 /// fn drop(&mut self) {
1264 /// println!("Dropped {}", self.0);
1265 /// }
1266 /// }
1267 /// let mut counter = 0..;
1268 /// let new_node = || Node(counter.next().unwrap());
1269 ///
1270 /// let buffer: Bump<[u8; 128]> = Bump::uninit();
1271 /// let buffer = buffer.as_bump_slice().unwrap();
1272 /// let head = make_chain(buffer, new_node).unwrap();
1273 ///
1274 /// // Prints the message in reverse order.
1275 /// // Dropped 3
1276 /// // Dropped 2
1277 /// // Dropped 1
1278 /// // Dropped 0
1279 /// drop(head);
1280 /// ```
1281 pub fn leak_box<V>(&self, val: V) -> Option<LeakBox<'_, V>> {
1282 self.as_view().leak_box(val)
1283 }
1284
1285 /// Move a value into an owned allocation.
1286 ///
1287 /// See [`leak_box`] for usage.
1288 ///
1289 /// [`leak_box`]: #method.leak_box
1290 pub fn leak_box_at<V>(&self, val: V, level: Level) -> Result<LeakBox<'_, V>, Failure> {
1291 self.as_view().leak_box_at(val, level)
1292 }
1293
1294 /// Observe the current level.
1295 ///
1296 /// Keep in mind that concurrent usage of the same slab may modify the level before you are
1297 /// able to use it in `alloc_at`. Calling this method provides also no other guarantees on
1298 /// synchronization of memory accesses, only that the values observed by the caller are a
1299 /// monotonically increasing seequence while a shared reference exists.
1300 pub fn level(&self) -> Level {
1301 self.as_view().level()
1302 }
1303
1304 /// Get a pointer to an existing allocation at a specific level.
1305 ///
1306 /// The resulting pointer may be used to access an arbitrary allocation starting at the pointer
1307 /// (i.e. including additional allocations immediately afterwards) but the caller is
1308 /// responsible for ensuring that these accesses do not overlap other accesses. There must be
1309 /// no more life [`LeakBox`] to any allocation being accessed this way.
1310 ///
1311 /// # Safety
1312 ///
1313 /// - The level must refer to an existing allocation, i.e. it must previously have been
1314 /// returned in [`Allocation::level`].
1315 /// - As a corollary, particular it must be in-bounds of the allocator's memory.
1316 /// - Another consequence, the result pointer must be aligned for the requested type.
1317 pub unsafe fn get_unchecked<V>(&self, level: Level) -> Allocation<'_, V> {
1318 // Safety: forwarding requirements.
1319 unsafe { self.as_view().get_unchecked(level) }
1320 }
1321
1322 /// Allocate a value for the lifetime of the allocator.
1323 ///
1324 /// The value is leaked in the sense that
1325 ///
1326 /// 1. the drop implementation of the allocated value is never called;
1327 /// 2. reusing the memory for another allocation in the same `Bump` requires manual unsafe code
1328 /// to handle dropping and reinitialization.
1329 ///
1330 /// However, it does not mean that the underlying memory used for the allocated value is never
1331 /// reclaimed. If the `Bump` itself is a stack value then it will get reclaimed together with
1332 /// it.
1333 ///
1334 /// ## Safety notice
1335 ///
1336 /// It is important to understand that it is undefined behaviour to reuse the allocation for
1337 /// the *whole lifetime* of the returned reference. That is, dropping the allocation in-place
1338 /// while the reference is still within its lifetime comes with the exact same unsafety caveats
1339 /// as [`ManuallyDrop::drop`].
1340 ///
1341 /// ```
1342 /// # use static_alloc::bump::{Bump, BumpSlice};
1343 /// #[derive(Debug, Default)]
1344 /// struct FooBar {
1345 /// // ...
1346 /// # _private: [u8; 1],
1347 /// }
1348 ///
1349 /// let local: Bump<[FooBar; 3]> = Bump::uninit();
1350 /// let local = local.as_bump_slice().unwrap();
1351 /// let one = local.leak(FooBar::default()).unwrap();
1352 ///
1353 /// // Dangerous but justifiable.
1354 /// let one = unsafe {
1355 /// // Ensures there is no current mutable borrow.
1356 /// core::ptr::drop_in_place(&mut *one);
1357 /// };
1358 /// ```
1359 ///
1360 /// ## Usage
1361 ///
1362 /// ```
1363 /// use static_alloc::bump::{Bump, BumpSlice};
1364 ///
1365 /// let local: Bump<[u64; 3]> = Bump::uninit();
1366 /// let local = local.as_bump_slice().unwrap();
1367 ///
1368 /// let one = local.leak(0_u64).unwrap();
1369 /// assert_eq!(*one, 0);
1370 /// *one = 42;
1371 /// ```
1372 ///
1373 /// ## Limitations
1374 ///
1375 /// Only sized values can be allocated in this manner for now, unsized values are blocked on
1376 /// stabilization of [`ptr::slice_from_raw_parts`]. We can not otherwise get a fat pointer to
1377 /// the allocated region.
1378 ///
1379 /// [`ptr::slice_from_raw_parts`]: https://github.com/rust-lang/rust/issues/36925
1380 /// [`ManuallyDrop::drop`]: https://doc.rust-lang.org/beta/std/mem/struct.ManuallyDrop.html#method.drop
1381 ///
1382 /// TODO: will be deprecated sooner or later in favor of a method that does not move the
1383 /// resource on failure.
1384 // #[deprecated = "Use leak_box and initialize it with the value. This does not move the value in the failure case."]
1385 #[expect(clippy::mut_from_ref)] // This is an allocator.
1386 pub fn leak<V>(&self, val: V) -> Result<&mut V, LeakError<V>> {
1387 match self.get::<V>() {
1388 // SAFETY: Just allocated this for a `V`.
1389 Some(alloc) => Ok(unsafe { alloc.leak(val) }),
1390 None => Err(LeakError::new(val, Failure::Exhausted)),
1391 }
1392 }
1393
1394 /// Allocate a value with a precise location.
1395 ///
1396 /// See [`leak`] for basics on allocation of values.
1397 ///
1398 /// The level is an identifer for a base location (more at [`level`]). This will succeed if it
1399 /// can be allocate exactly at the expected location.
1400 ///
1401 /// This method will return the new level of the slab allocator. A next allocation at the
1402 /// returned level will be placed next to this allocation, only separated by necessary padding
1403 /// from alignment. In particular, this is the same strategy as applied for the placement of
1404 /// `#[repr(C)]` struct members. (Except for the final padding at the last member to the full
1405 /// struct alignment.)
1406 ///
1407 /// ## Usage
1408 ///
1409 /// ```
1410 /// use static_alloc::bump::{Bump, BumpSlice};
1411 ///
1412 /// let local: Bump<[u64; 3]> = Bump::uninit();
1413 /// let local = local.as_bump_slice().unwrap();
1414 ///
1415 /// let base = local.level();
1416 /// let (one, level) = local.leak_at(1_u64, base).unwrap();
1417 /// // Will panic when an allocation happens in between.
1418 /// let (two, _) = local.leak_at(2_u64, level).unwrap();
1419 ///
1420 /// assert_eq!((one as *const u64).wrapping_offset(1), two);
1421 /// ```
1422 ///
1423 /// [`leak`]: #method.leak
1424 /// [`level`]: #method.level
1425 ///
1426 /// TODO: will be deprecated sooner or later in favor of a method that does not move the
1427 /// resource on failure.
1428 ///
1429 // #[deprecated = "Use leak_box_at and initialize it with the value. This does not move the value in the failure case."]
1430 #[expect(clippy::mut_from_ref)] // This is an allocator.
1431 pub fn leak_at<V>(&self, val: V, level: Level) -> Result<(&mut V, Level), LeakError<V>> {
1432 let alloc = match self.get_at::<V>(level) {
1433 Ok(alloc) => alloc,
1434 Err(err) => return Err(LeakError::new(val, err)),
1435 };
1436
1437 // SAFETY: Just allocated this for a `V`.
1438 let level = alloc.level;
1439 let mutref = unsafe { alloc.leak(val) };
1440 Ok((mutref, level))
1441 }
1442}
1443
1444impl<'lt> BumpView<'lt> {
1445 pub fn alloc(self, layout: Layout) -> Option<NonNull<u8>> {
1446 Some(self.try_alloc(layout).ok()?.ptr)
1447 }
1448
1449 pub fn alloc_at(self, layout: Layout, level: Level) -> Result<Allocation<'lt>, Failure> {
1450 let Allocation {
1451 ptr,
1452 lifetime,
1453 level,
1454 } = self.try_alloc_at(layout, level.0)?;
1455
1456 Ok(Allocation {
1457 ptr: ptr.cast(),
1458 lifetime,
1459 level,
1460 })
1461 }
1462
1463 pub fn get_layout(self, layout: Layout) -> Option<Allocation<'lt>> {
1464 self.try_alloc(layout).ok()
1465 }
1466
1467 pub fn get_layout_at(self, layout: Layout, at: Level) -> Result<Allocation<'lt>, Failure> {
1468 self.try_alloc_at(layout, at.0)
1469 }
1470
1471 pub fn get<V>(self) -> Option<Allocation<'lt, V>> {
1472 if mem::size_of::<V>() == 0 {
1473 return Some(self.zst_fake_alloc());
1474 }
1475
1476 let layout = Layout::new::<V>();
1477 let Allocation {
1478 ptr,
1479 lifetime,
1480 level,
1481 } = self.try_alloc(layout).ok()?;
1482
1483 Some(Allocation {
1484 ptr: ptr.cast(),
1485 lifetime,
1486 level,
1487 })
1488 }
1489
1490 pub fn get_at<V>(self, level: Level) -> Result<Allocation<'lt, V>, Failure> {
1491 if mem::size_of::<V>() == 0 {
1492 let fake = self.zst_fake_alloc();
1493 // Note: zst_fake_alloc is a noop on the level, we may as well check after.
1494 if fake.level != level {
1495 return Err(Failure::Mismatch {
1496 observed: fake.level,
1497 });
1498 }
1499 return Ok(fake);
1500 }
1501
1502 let layout = Layout::new::<V>();
1503 let Allocation {
1504 ptr,
1505 lifetime,
1506 level,
1507 } = self.try_alloc_at(layout, level.0)?;
1508
1509 Ok(Allocation {
1510 // It has exactly size and alignment for `V` as requested.
1511 ptr: ptr.cast(),
1512 lifetime,
1513 level,
1514 })
1515 }
1516
1517 pub fn get_slice<V>(&self, len: usize) -> Option<Allocation<'lt, [V]>> {
1518 if len == 0 {
1519 return Some(Allocation::for_empty_slice(self.level()));
1520 }
1521
1522 let layout = Layout::array::<V>(len).ok()?;
1523
1524 if layout.size() == 0 {
1525 // Synthesize the slice for this ZST.
1526 return Some(Allocation::for_zst_slice(len, self.level()));
1527 };
1528
1529 let alloc = self.get_layout(layout)?;
1530
1531 Some(Allocation {
1532 ptr: NonNull::slice_from_raw_parts(alloc.ptr.cast(), len),
1533 lifetime: alloc.lifetime,
1534 level: alloc.level,
1535 })
1536 }
1537
1538 pub fn leak_box<V>(self, val: V) -> Option<LeakBox<'lt, V>> {
1539 let Allocation { ptr, lifetime, .. } = self.get::<V>()?;
1540 Some(unsafe { LeakBox::new_from_raw_non_null(ptr, val, lifetime) })
1541 }
1542
1543 pub fn leak_box_at<V>(self, val: V, level: Level) -> Result<LeakBox<'lt, V>, Failure> {
1544 let Allocation { ptr, lifetime, .. } = self.get_at::<V>(level)?;
1545 Ok(unsafe { LeakBox::new_from_raw_non_null(ptr, val, lifetime) })
1546 }
1547
1548 pub fn level(&self) -> Level {
1549 Level(self.header.consumed.load(Ordering::SeqCst))
1550 }
1551
1552 /// # Safety
1553 ///
1554 /// - The level must refer to an existing allocation, i.e. it must previously have been
1555 /// returned in [`Allocation::level`].
1556 /// - As a corollary, particular it must be in-bounds of the allocator's memory.
1557 /// - Another consequence, the result pointer must be aligned for the requested type.
1558 pub unsafe fn get_unchecked<V>(self, level: Level) -> Allocation<'lt, V> {
1559 debug_assert!(level.0 <= mem::size_of_val(self.storage));
1560
1561 debug_assert!(
1562 level <= self.level(),
1563 "Tried to access an allocation that does not yet exist"
1564 );
1565
1566 let base_ptr = self.storage.get().cast::<u8>();
1567 // SAFETY: `level.0` is in bounds as assert above, or by the caller by having provided an
1568 // existing allocation—all allocations we hand out are in bounds.
1569 let alloc = unsafe { base_ptr.add(level.0) };
1570 let ptr = NonNull::new(alloc).unwrap().cast::<V>();
1571
1572 debug_assert!(
1573 ptr.as_ptr().is_aligned(),
1574 "Tried to access an allocation with improper type"
1575 );
1576
1577 Allocation {
1578 level,
1579 lifetime: AllocTime::default(),
1580 ptr,
1581 }
1582 }
1583
1584 // FIXME: should take `NonZeroLayout`.
1585 pub(crate) fn try_alloc(self, layout: Layout) -> Result<Allocation<'lt>, Level> {
1586 // Guess the current level, this will fail when we try to access it and it isn't.
1587 let mut consumed = self.level().0;
1588 // FIXME: parts of the initial computation depends mostly on `layout` and `storage`, i.e.
1589 // not on the current level. It's not verified if LLVM moves these out of the loop and it's
1590 // doubtful since there's a CAS within it (`self.bump`). Rewrite to avoid this, e.g. a
1591 // 'qualified layout` type filled with specifics to our storage? Especially since we align
1592 // upwards which isn't a simple AND. However, calculating the last possible end-location and
1593 // then the last possible start, and then a simpler comparison would be.
1594 //
1595 // Speaking of this might motivate changing to storing the number of bytes left instead of
1596 // the number of bytes consumed. Then we have again an AND boundary with an addition for the
1597 // CAS update.
1598 loop {
1599 match self.try_alloc_at(layout, consumed) {
1600 Ok(alloc) => return Ok(alloc),
1601 Err(Failure::Exhausted) => return Err(Level(consumed)),
1602 Err(Failure::Mismatch { observed }) => consumed = observed.0,
1603 }
1604 }
1605 }
1606
1607 /// Try to allocate some layout with a precise base location.
1608 ///
1609 /// The base location is the currently consumed byte count, without correction for the
1610 /// alignment of the allocation. This will succeed if it can be allocate exactly at the
1611 /// expected location.
1612 ///
1613 /// # Panics
1614 /// This function panics if `expect_consumed` is larger than `length`.
1615 /// FIXME: should take `NonZeroLayout`.
1616 fn try_alloc_at(
1617 self,
1618 layout: Layout,
1619 expect_consumed: usize,
1620 ) -> Result<Allocation<'lt>, Failure> {
1621 assert!(layout.size() > 0);
1622 let length = self.storage.get().len();
1623 let base_ptr = self.storage.get().cast::<u8>();
1624
1625 let alignment = layout.align();
1626 let requested = layout.size();
1627
1628 // Ensure no overflows when calculating offets within.
1629 assert!(expect_consumed <= length);
1630
1631 let available = length.checked_sub(expect_consumed).unwrap();
1632 let ptr_to = base_ptr.wrapping_add(expect_consumed);
1633 let offset = ptr_to.align_offset(alignment);
1634
1635 if requested > available.saturating_sub(offset) {
1636 return Err(Failure::Exhausted); // exhausted
1637 }
1638
1639 // `size` can not be zero, saturation will thus always make this true.
1640 assert!(offset < available);
1641 let at_aligned = expect_consumed.checked_add(offset).unwrap();
1642 let new_consumed = at_aligned.checked_add(requested).unwrap();
1643 // new_consumed
1644 // = consumed + offset + requested [lines above]
1645 // <= consumed + available [bail out: exhausted]
1646 // <= length [first line of loop]
1647 // So it's ok to store `allocated` into `consumed`.
1648 assert!(new_consumed <= length);
1649 assert!(at_aligned < length);
1650
1651 // Try to actually allocate.
1652 match self.bump(expect_consumed, new_consumed) {
1653 Ok(()) => (),
1654 Err(observed) => {
1655 // Someone else was faster, if you want it then recalculate again.
1656 return Err(Failure::Mismatch {
1657 observed: Level(observed),
1658 });
1659 }
1660 }
1661
1662 let aligned = unsafe {
1663 // SAFETY:
1664 // * `0 <= at_aligned < length` in bounds as checked above.
1665 base_ptr.byte_add(at_aligned)
1666 };
1667
1668 Ok(Allocation {
1669 ptr: NonNull::new(aligned).unwrap(),
1670 lifetime: AllocTime::default(),
1671 level: Level(new_consumed),
1672 })
1673 }
1674
1675 /// 'Allocate' a ZST.
1676 fn zst_fake_alloc<Z>(&self) -> Allocation<'lt, Z> {
1677 Allocation::for_zst(self.level())
1678 }
1679
1680 /// Try to bump the monotonic, atomic consume counter.
1681 ///
1682 /// This is the only place doing shared modification to `self.consumed`.
1683 ///
1684 /// Returns `Ok` if the consume counter was as expected. Monotonicty and atomicity guarantees
1685 /// to the caller that no overlapping range can succeed as well. This allocates the range to
1686 /// the caller.
1687 ///
1688 /// Returns the observed consume counter in an `Err` if it was not as expected.
1689 ///
1690 /// ## Panics
1691 /// This function panics if either argument exceeds the byte length of the underlying memory.
1692 /// It also panics if the expected value is larger than the new value.
1693 fn bump(&self, expect_consumed: usize, new_consumed: usize) -> Result<(), usize> {
1694 assert!(expect_consumed <= new_consumed);
1695 assert!(new_consumed <= self.storage.get().len());
1696 self.header.bump(expect_consumed, new_consumed)
1697 }
1698}
1699
1700impl Header {
1701 const fn empty() -> Self {
1702 Header {
1703 consumed: AtomicUsize::new(0),
1704 }
1705 }
1706
1707 fn bump(&self, expect_consumed: usize, new_consumed: usize) -> Result<(), usize> {
1708 self.consumed
1709 .compare_exchange(
1710 expect_consumed,
1711 new_consumed,
1712 Ordering::SeqCst,
1713 Ordering::SeqCst,
1714 )
1715 .map(drop)
1716 }
1717}
1718
1719impl<'alloc, T> Allocation<'alloc, T> {
1720 /// Write a value into the allocation and leak it.
1721 ///
1722 /// ## Safety
1723 ///
1724 /// Must have been allocated for a layout that fits the layout of T previously. The pointer
1725 /// must not be aliased.
1726 ///
1727 /// ## Usage
1728 ///
1729 /// Consider the alternative [`Bump::leak`] to safely allocate and directly leak a value.
1730 ///
1731 /// [`Bump::leak`]: struct.Bump.html#method.leak
1732 pub unsafe fn leak(self, val: T) -> &'alloc mut T {
1733 // Safety: The pointer is valid for a write as per caller.
1734 unsafe { core::ptr::write(self.ptr.as_ptr(), val) };
1735 // Safety: The pointer is not borrowed and valid as guaranteed by the caller.
1736 unsafe { &mut *self.ptr.as_ptr() }
1737 }
1738
1739 /// Write a value into the allocation and own it.
1740 ///
1741 /// ## Safety
1742 ///
1743 /// Must have been allocated for a layout that fits the layout of T previously. The pointer
1744 /// must not be aliased.
1745 ///
1746 /// ## Usage
1747 ///
1748 /// Consider the alternative [`Bump::leak`] to safely allocate and directly leak a value.
1749 ///
1750 /// [`Bump::leak`]: struct.Bump.html#method.leak
1751 pub unsafe fn boxed(self, val: T) -> LeakBox<'alloc, T> {
1752 // The pointer is not aliased and valid as guaranteed by the caller.
1753 unsafe { core::ptr::write(self.ptr.as_ptr(), val) };
1754 // Safety: the instance is valid, was just initialized.
1755 unsafe { LeakBox::from_raw(self.ptr.as_ptr()) }
1756 }
1757
1758 /// Convert this into a mutable reference to an uninitialized slot.
1759 ///
1760 /// ## Safety
1761 ///
1762 /// Must have been allocated for a layout that fits the layout of T previously.
1763 pub unsafe fn uninit(self) -> &'alloc mut MaybeUninit<T> {
1764 unsafe { &mut *self.ptr.cast().as_ptr() }
1765 }
1766
1767 /// An 'allocation' for an arbitrary ZST, at some arbitrary level.
1768 pub(crate) fn for_zst(level: Level) -> Self {
1769 assert!(mem::size_of::<T>() == 0);
1770 // If `Z` is a ZST, then the stride of any array is equal to 0. Thus, all arrays and slices
1771 // havee the same layout which only depends on the alignment. If we need a storage for this
1772 // ZST we just take one of those as our base 'allocation' which can also never be aliased.
1773 let alloc: &[T; 0] = &[];
1774
1775 Allocation {
1776 ptr: NonNull::from(alloc).cast(),
1777 lifetime: AllocTime::default(),
1778 level,
1779 }
1780 }
1781
1782 pub(crate) fn for_zst_slice(len: usize, level: Level) -> Allocation<'alloc, [T]> {
1783 assert!(mem::size_of::<T>() == 0);
1784 let alloc: &[T; 0] = &[];
1785
1786 Allocation {
1787 ptr: NonNull::slice_from_raw_parts(NonNull::from(alloc).cast(), len),
1788 lifetime: AllocTime::default(),
1789 level,
1790 }
1791 }
1792
1793 pub(crate) fn for_empty_slice(level: Level) -> Allocation<'alloc, [T]> {
1794 let alloc: &[T; 0] = &[];
1795
1796 Allocation {
1797 ptr: NonNull::from(alloc),
1798 lifetime: AllocTime::default(),
1799 level,
1800 }
1801 }
1802}
1803
1804impl<T> LeakError<T> {
1805 fn new(val: T, failure: Failure) -> Self {
1806 LeakError { val, failure }
1807 }
1808
1809 /// Inspect the cause of this error.
1810 pub fn kind(&self) -> Failure {
1811 self.failure
1812 }
1813
1814 /// Retrieve the value that could not be allocated.
1815 pub fn into_inner(self) -> T {
1816 self.val
1817 }
1818}
1819
1820// SAFETY: at most one thread gets a pointer to each chunk of data.
1821unsafe impl<T> Sync for Bump<T> {}
1822
1823// SAFETY: at most one thread gets a pointer to each chunk of data.
1824unsafe impl Sync for BumpView<'_> {}
1825unsafe impl Send for BumpView<'_> {}
1826
1827unsafe impl<T> GlobalAlloc for Bump<T> {
1828 unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
1829 // Safety: just handing over arguments exactly as is. These two allocators are 'compatible'
1830 // in the sense they hold onto the same value handles.
1831 unsafe { GlobalAlloc::alloc(&self.as_view(), layout) }
1832 }
1833
1834 unsafe fn realloc(&self, ptr: *mut u8, current: Layout, new_size: usize) -> *mut u8 {
1835 // Safety: just handing over arguments exactly as is. These two allocators are 'compatible'
1836 // in the sense they hold onto the same value handles.
1837 unsafe { GlobalAlloc::realloc(&self.as_view(), ptr, current, new_size) }
1838 }
1839
1840 unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
1841 // We are a slab allocator and do not deallocate.
1842 }
1843}
1844
1845unsafe impl GlobalAlloc for &'static BumpSlice {
1846 unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
1847 // Safety: just handing over arguments exactly as is. These two allocators are 'compatible'
1848 // in the sense they hold onto the same value handles.
1849 unsafe { GlobalAlloc::alloc(&self.as_view(), layout) }
1850 }
1851
1852 unsafe fn realloc(&self, ptr: *mut u8, current: Layout, new_size: usize) -> *mut u8 {
1853 // Safety: just handing over arguments exactly as is. These two allocators are 'compatible'
1854 // in the sense they hold onto the same value handles.
1855 unsafe { GlobalAlloc::realloc(&self.as_view(), ptr, current, new_size) }
1856 }
1857
1858 unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
1859 // We are a slab allocator and do not deallocate.
1860 }
1861}
1862
1863unsafe impl GlobalAlloc for BumpView<'_> {
1864 unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
1865 BumpView::alloc(*self, layout)
1866 .map(NonNull::as_ptr)
1867 .unwrap_or_else(null_mut)
1868 }
1869
1870 unsafe fn realloc(&self, ptr: *mut u8, current: Layout, new_size: usize) -> *mut u8 {
1871 let current = NonZeroLayout::from_layout(current.into()).unwrap();
1872 // Safety: As required of the caller, `new_size` is greater than 0.
1873 let new_size = unsafe { core::num::NonZeroUsize::new_unchecked(new_size) };
1874
1875 let target = match layout_reallocated(current, new_size) {
1876 Some(target) => target,
1877 None => return core::ptr::null_mut(),
1878 };
1879
1880 // Construct an allocation. This is not safe in general but the lifetime is not important.
1881 let reconstructed = alloc_traits::Allocation {
1882 // Safety: `ptr` is currently allocated via this allocator, i.e. non-null.
1883 ptr: unsafe { NonNull::new_unchecked(ptr) },
1884 layout: current,
1885 lifetime: AllocTime::default(),
1886 };
1887
1888 // Safety: satisfies our own invariants.
1889 unsafe { alloc_traits::LocalAlloc::realloc(self, reconstructed, target) }
1890 .map(|alloc| alloc.ptr.as_ptr())
1891 .unwrap_or_else(core::ptr::null_mut)
1892 }
1893
1894 unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
1895 // We are a slab allocator and do not deallocate.
1896 }
1897}
1898
1899fn layout_reallocated(
1900 layout: NonZeroLayout,
1901 target: core::num::NonZeroUsize,
1902) -> Option<NonZeroLayout> {
1903 // This may not be a valid layout.
1904 let layout = Layout::from_size_align(target.get(), layout.align()).ok()?;
1905 // This must succeed though, as the size was non-zero.
1906 Some(NonZeroLayout::from_layout(layout.into()).unwrap())
1907}
1908
1909unsafe impl<'alloc, T> LocalAlloc<'alloc> for Bump<T> {
1910 fn alloc(&'alloc self, layout: NonZeroLayout) -> Option<alloc_traits::Allocation<'alloc>> {
1911 let raw_alloc = self.get_layout(layout.into())?;
1912 Some(alloc_traits::Allocation {
1913 ptr: raw_alloc.ptr,
1914 layout,
1915 lifetime: AllocTime::default(),
1916 })
1917 }
1918
1919 unsafe fn realloc(
1920 &'alloc self,
1921 alloc: alloc_traits::Allocation<'alloc>,
1922 layout: NonZeroLayout,
1923 ) -> Option<alloc_traits::Allocation<'alloc>> {
1924 if alloc.ptr.as_ptr() as usize % layout.align() == 0 && alloc.layout.size() >= layout.size()
1925 {
1926 // Obvious fit, nothing to do.
1927 return Some(alloc_traits::Allocation {
1928 ptr: alloc.ptr,
1929 layout,
1930 lifetime: alloc.lifetime,
1931 });
1932 }
1933
1934 // TODO: we could try to allocate at the exact level that the allocation ends. If this
1935 // succeeds, there is no copying necessary. This was the point of `Level` anyways.
1936
1937 let new_alloc = LocalAlloc::alloc(self, layout)?;
1938
1939 // Safety:
1940 // - the old allocation is valid for the old size, as required of the caller.
1941 // - the old allocation is valid for reads as it is an allocation of the allocator.
1942 // - the new allocation is valid for the new size.
1943 // - the new allocation is valid for writes as it was successful.
1944 // - our effective copy is at most the old and new size.
1945 unsafe {
1946 core::ptr::copy_nonoverlapping(
1947 alloc.ptr.as_ptr(),
1948 new_alloc.ptr.as_ptr(),
1949 layout.size().min(alloc.layout.size()).into(),
1950 );
1951 }
1952
1953 // No dealloc.
1954 Some(new_alloc)
1955 }
1956
1957 unsafe fn dealloc(&'alloc self, _: alloc_traits::Allocation<'alloc>) {
1958 // We are a slab allocator and do not deallocate.
1959 }
1960}
1961
1962unsafe impl<'alloc> LocalAlloc<'alloc> for BumpView<'alloc> {
1963 fn alloc(&'alloc self, layout: NonZeroLayout) -> Option<alloc_traits::Allocation<'alloc>> {
1964 let raw_alloc = self.get_layout(layout.into())?;
1965 Some(alloc_traits::Allocation {
1966 ptr: raw_alloc.ptr,
1967 layout,
1968 lifetime: AllocTime::default(),
1969 })
1970 }
1971
1972 // TODO: alloc zeroed if the constructor was `Self::zeroed()`
1973
1974 /// Reallocates if the layout is strictly smaller and the allocation aligned.
1975 ///
1976 /// Note that this may succeed spuriously if the previous allocation is incidentally aligned to
1977 /// a larger alignment than had been request.
1978 ///
1979 /// Also not, reallocating to a smaller layout is NOT useless.
1980 ///
1981 /// It confirms that this allocator does not need the allocated layout to re/deallocate.
1982 /// Otherwise, even reallocating to a strictly smaller layout would be impossible without
1983 /// storing the prior layout.
1984 unsafe fn realloc(
1985 &'alloc self,
1986 alloc: alloc_traits::Allocation<'alloc>,
1987 layout: NonZeroLayout,
1988 ) -> Option<alloc_traits::Allocation<'alloc>> {
1989 if alloc.ptr.as_ptr() as usize % layout.align() == 0 && alloc.layout.size() >= layout.size()
1990 {
1991 // Obvious fit, nothing to do.
1992 return Some(alloc_traits::Allocation {
1993 ptr: alloc.ptr,
1994 layout,
1995 lifetime: alloc.lifetime,
1996 });
1997 }
1998
1999 // TODO: we could try to allocate at the exact level that the allocation ends. If this
2000 // succeeds, there is no copying necessary. This was the point of `Level` anyways.
2001
2002 let new_alloc = LocalAlloc::alloc(self, layout)?;
2003
2004 // Safety:
2005 // - the old allocation is valid for the old size, as required of the caller.
2006 // - the old allocation is valid for reads as it is an allocation of the allocator.
2007 // - the new allocation is valid for the new size.
2008 // - the new allocation is valid for writes as it was successful.
2009 // - our effective copy is at most the old and new size.
2010 unsafe {
2011 core::ptr::copy_nonoverlapping(
2012 alloc.ptr.as_ptr(),
2013 new_alloc.ptr.as_ptr(),
2014 layout.size().min(alloc.layout.size()).into(),
2015 );
2016 }
2017
2018 // No dealloc.
2019 Some(new_alloc)
2020 }
2021
2022 unsafe fn dealloc(&'alloc self, _: alloc_traits::Allocation<'alloc>) {
2023 // We are a slab allocator and do not deallocate.
2024 }
2025}
2026
2027#[cfg(test)]
2028mod tests {
2029 use super::*;
2030
2031 #[test]
2032 fn zst_no_drop() {
2033 #[derive(Debug)]
2034 struct PanicOnDrop;
2035
2036 impl Drop for PanicOnDrop {
2037 fn drop(&mut self) {
2038 panic!("No instance of this should ever get dropped");
2039 }
2040 }
2041
2042 let alloc = Bump::<()>::uninit();
2043 let _ = alloc.leak(PanicOnDrop).unwrap();
2044 }
2045}