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