Skip to main content

ExtendableSlab

Struct ExtendableSlab 

Source
pub struct ExtendableSlab<T, M: FreelistProtection = NoProtection> { /* private fields */ }
Expand description

Growable typed slab.

Each segment is a fixed-capacity Slab<T, MmapBacked, M>. Growth allocates a new MmapBacked and appends a new segment; the previous segments’ pointers remain valid. Segments are never reallocated or moved.

§Thread safety

Send + Sync. The segment list is guarded by a Mutex because we may need to push to a Vec on growth; per-segment slabs are !Sync but the mutex serializes access to the list itself. (For high-contention workloads, switch to SlabOwner/SlabRemote for per-thread segments.)

§Panic safety

If a thread panics while holding the segments mutex, the mutex is poisoned. allocate, deallocate, segment_count, and the internal build_segment helper all call expect("mutex poisoned") and re-panic on a poisoned lock. This is intentional and asymmetric with SlabOwner::drop’s into_inner() recovery:

  • SlabOwner::drop runs during unwind and MUST NOT double-panic, so it recovers the inner state via into_inner() even on a poisoned mutex.
  • ExtendableSlab::{allocate, deallocate, build_segment, segment_count} run on the normal call path. A poisoned mutex means some prior call panicked under the lock — the allocator state is suspect and the safest policy is fail-loud rather than silently continue. Once poisoned, the wrapper is permanently unusable; the application should treat this as a fatal allocator error and recreate the ExtendableSlab.

This asymmetry is intentional and documented here for future maintainers.

Implementations§

Source§

impl<T> ExtendableSlab<T, NoProtection>

Source

pub fn new(segment_capacity: usize) -> Self

Construct an empty ExtendableSlab with NoProtection. Segments are added lazily on first allocate.

Source§

impl<T, M: FreelistProtection> ExtendableSlab<T, M>

Source

pub fn with_protection(segment_capacity: usize, mac_factory: fn() -> M) -> Self

Construct an empty ExtendableSlab with an explicit freelist-protection factory.

Source

pub fn with_initial_segments( count: usize, segment_capacity: usize, mac_factory: fn() -> M, ) -> Result<Self, AllocError>

Construct with initial_segments segments pre-allocated.

Source

pub fn segment_count(&self) -> usize

Number of segments currently allocated.

Trait Implementations§

Source§

impl<T, M: FreelistProtection + Send> Allocator for ExtendableSlab<T, M>
where T: Send,

Source§

fn allocate(&self, layout: NonZeroLayout) -> Result<NonNull<[u8]>, AllocError>

Allocate a block satisfying layout. The returned slice’s length is at least layout.size() but may be larger.
Source§

unsafe fn usable_size( &self, ptr: NonNull<u8>, layout: NonZeroLayout, ) -> Option<usize>

Usable size of an existing allocation, if the allocator can report it. Defaults to None — implementors that track usable size override. Read more
Source§

fn capacity_bytes(&self) -> Option<usize>

Total bytes this allocator can issue, if bounded. None for unbounded allocators like System. Used by Watermark to compute thresholds.
Source§

fn corruption_events(&self) -> u64

Detected freelist / metadata corruption events observed by this allocator since construction. Read more
Source§

fn allocate_zeroed( &self, layout: NonZeroLayout, ) -> Result<NonNull<[u8]>, AllocError>

Allocate a zero-initialized block.
Source§

unsafe fn grow( &self, ptr: NonNull<u8>, old: NonZeroLayout, new: NonZeroLayout, ) -> Result<NonNull<[u8]>, AllocError>

Grow an allocation in place if possible, otherwise allocate-copy-free. Read more
Source§

unsafe fn shrink( &self, ptr: NonNull<u8>, old: NonZeroLayout, new: NonZeroLayout, ) -> Result<NonNull<[u8]>, AllocError>

Shrink an allocation in place if possible, otherwise allocate-copy-free. Read more
Source§

fn reset(&mut self) -> Result<(), AllocError>

Reclaim everything previously allocated. Default impl returns AllocError — only arena-style allocators implement a meaningful reset. Read more
Source§

impl<T, M: FreelistProtection + Send> Deallocator for ExtendableSlab<T, M>
where T: Send,

Source§

unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: NonZeroLayout)

Release a previously allocated block. Read more

Auto Trait Implementations§

§

impl<T, M = NoProtection> !Freeze for ExtendableSlab<T, M>

§

impl<T, M> RefUnwindSafe for ExtendableSlab<T, M>

§

impl<T, M> Send for ExtendableSlab<T, M>
where T: Send, M: Send,

§

impl<T, M> Sync for ExtendableSlab<T, M>
where T: Send, M: Send,

§

impl<T, M> Unpin for ExtendableSlab<T, M>
where M: Unpin, T: Unpin,

§

impl<T, M> UnsafeUnpin for ExtendableSlab<T, M>

§

impl<T, M> UnwindSafe for ExtendableSlab<T, M>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.