pub struct InlineBacked<const N: usize> { /* private fields */ }Expand description
Fixed-size inline storage backing.
The N bytes are stored inline in the struct, aligned to MAX_ALIGN.
Allocations bump a cursor through this buffer; deallocation is a no-op.
Reset via reset (requires &mut self).
N MUST be a multiple of core::mem::align_of::<usize>(); constructing
with any other N is a compile-time error (const _: () = assert!(…)
inside new).
§API-misuse compile-failures (pinned)
N must satisfy N % core::mem::align_of::<usize>() == 0. On the
32- and 64-bit targets this crate supports, align_of::<usize>() is
4 or 8 respectively, so N = 7 is never valid. The const assert
(ASSERT_N_ALIGNED) fires at the call site of new():
// FAILS TO COMPILE: 7 is not a multiple of align_of::<usize>()
// on any supported target, so `ASSERT_N_ALIGNED` panics at const
// evaluation inside `InlineBacked::<7>::new()`.
use forge_alloc::InlineBacked;
let _ = InlineBacked::<7>::new();§Move invariant (structure-relative backing)
base() returns a pointer derived from &self.storage, which lives
inside the struct itself. Moving an InlineBacked (return by value,
mem::swap, Box::new, putting it into a container that reallocates,
etc.) relocates its inline storage to a new address. After such a move
base() correctly reflects the new location, but any pointer
previously returned from allocate is now dangling
— it points at the old, now-deallocated stack slot or heap cell.
Wrappers that store an InlineBacked (e.g. BumpArena<InlineBacked<N>>)
must NOT cache base() at construction; they must re-query on every
allocation. The wrappers in this crate family follow that discipline.
Raw callers who hold their own NonNull<u8> between allocate sites
are responsible for pinning the InlineBacked (e.g. via Pin<Box<…>>
or by keeping it in a local that the borrow checker proves is not
moved) before issuing the allocation.
§Thread safety
Send: yes — the storage is owned (auto-derived; both UnsafeCell fields
hold Send payloads).
Sync: NO. The cursor uses UnsafeCell so that Allocator::allocate can
take &self; concurrent &self allocation would race on the cursor.
UnsafeCell<T> is !Sync regardless of T, which gives us the right
behavior without any extra marker field. If you need cross-thread
allocation use a higher-layer wrapper that adds atomicity (e.g.
SharedBumpArena).
Implementations§
Source§impl<const N: usize> InlineBacked<N>
impl<const N: usize> InlineBacked<N>
Sourcepub const fn new() -> Self
pub const fn new() -> Self
Construct empty inline storage.
Compile-time enforces that N is a multiple of
core::mem::align_of::<usize>().
Sourcepub fn reset(&mut self)
pub fn reset(&mut self)
Reset the cursor to 0, reclaiming all allocated memory.
§Safety
All previously issued pointers become invalid. The caller is
responsible for ensuring no outstanding pointer is read or written
after this call. The &mut self receiver and BumpDeallocator<'a>
lifetime patterns enforce this at compile time for Box-style
usage; raw allocate callers must enforce it themselves.
Trait Implementations§
Source§impl<const N: usize> Allocator for InlineBacked<N>
impl<const N: usize> Allocator for InlineBacked<N>
Source§fn allocate(&self, layout: NonZeroLayout) -> Result<NonNull<[u8]>, AllocError>
fn allocate(&self, layout: NonZeroLayout) -> Result<NonNull<[u8]>, AllocError>
layout. The returned slice’s length is
at least layout.size() but may be larger.Source§fn capacity_bytes(&self) -> Option<usize>
fn capacity_bytes(&self) -> Option<usize>
None for unbounded
allocators like System. Used by Watermark to compute thresholds.Source§fn allocate_zeroed(
&self,
layout: NonZeroLayout,
) -> Result<NonNull<[u8]>, AllocError>
fn allocate_zeroed( &self, layout: NonZeroLayout, ) -> Result<NonNull<[u8]>, AllocError>
Source§unsafe fn grow(
&self,
ptr: NonNull<u8>,
old: NonZeroLayout,
new: NonZeroLayout,
) -> Result<NonNull<[u8]>, AllocError>
unsafe fn grow( &self, ptr: NonNull<u8>, old: NonZeroLayout, new: NonZeroLayout, ) -> Result<NonNull<[u8]>, AllocError>
Source§unsafe fn shrink(
&self,
ptr: NonNull<u8>,
old: NonZeroLayout,
new: NonZeroLayout,
) -> Result<NonNull<[u8]>, AllocError>
unsafe fn shrink( &self, ptr: NonNull<u8>, old: NonZeroLayout, new: NonZeroLayout, ) -> Result<NonNull<[u8]>, AllocError>
Source§fn reset(&mut self) -> Result<(), AllocError>
fn reset(&mut self) -> Result<(), AllocError>
AllocError — only arena-style allocators implement a meaningful
reset. Read moreSource§unsafe fn usable_size(
&self,
_ptr: NonNull<u8>,
_layout: NonZeroLayout,
) -> Option<usize>
unsafe fn usable_size( &self, _ptr: NonNull<u8>, _layout: NonZeroLayout, ) -> Option<usize>
None — implementors that track usable size
override. Read more