attachable-slab-allocator 0.1.0

A high-performance, $O(1)$, Master-Slave slab allocator designed for `no_std` environments, kernels, and embedded systems. This library provides fixed-size memory management with RAII safety while remaining completely agnostic of the underlying memory provider.
Documentation
//! # Attachable Slab Allocator: The Manual 🦀
//!
//! A high-performance, $O(1)$, Master-Slave slab allocator designed for `no_std` environments,
//! kernels, and embedded systems.
//!
//! ## 1. The Core Philosophy: "The Bridge"
//!
//! This library provides the logic for dividing memory into fixed-size "slots", but it does
//! not know how to acquire raw memory from the system. You must provide two "bridges"
//! (hooks) using the `define_allocation_hooks!` macro.
//!
//! **Note:** If these hooks are not defined, your code will fail to link.
//!
//! ### Example: Setting up Hooks
//! ```rust, ignore
//! use std::alloc::{alloc, dealloc, Layout};
//! use core::ptr::NonNull;
//! use attachable_slab_allocator::{define_allocation_hooks, Result};
//!
//! unsafe fn my_alloc(layout: Layout) -> Option<NonNull<u8>> {
//!     NonNull::new(alloc(layout))
//! }
//!
//! unsafe fn my_free(ptr: NonNull<u8>, layout: Layout) -> Result<()> {
//!     dealloc(ptr.as_ptr(), layout);
//!     Ok(())
//! }
//!
//! define_allocation_hooks!(my_alloc, my_free);
//! ```
//!
//! ## 2. Using `SlabCache`
//!
//! `SlabCache` is the primary interface. It is reference-counted and handles the
//! creation of Slaves when memory runs out.
//!
//! ### Constraints on `T` and `SLAB_SIZE`:
//! - **`T` Size**: Must be at least 4 bytes (`u32`) to store internal freelist indices.
//! - **`T` Alignment**: Must be at least `u32` aligned.
//! - **`SLAB_SIZE`**: Must be a **Power of Two**.
//! - **Slab Alignment**: The allocator enforces that `Slab Alignment == SLAB_SIZE`. This is
//!   checked at compile time.
//!
//! ### Example: Allocation
//! ```rust, ignore
//! use attachable_slab_allocator::{SlabCache, locks::SpinLock};
//!
//! // Create a cache for u64, using a 4096-byte slab size.
//! let mut cache = SlabCache::<u64, SpinLock, 4096>::new().unwrap();
//!
//! // Allocate a smart pointer (SlabBox)
//! let mut boxed_val = cache.alloc().unwrap();
//! *boxed_val = 12345;
//!
//! // boxed_val is dropped here, returning memory to the slab automatically.
//! ```
//!
//! ## 3. Synchronization and Locks
//!
//! The allocator uses a **Master-Slave** architecture. The **Master Slab** holds the
//! lock that protects the entire hierarchy (itself and all its Slaves).
//!
//! ### Custom Locks:
//! You can implement the `LockTrait` for your own synchronization primitive.
//! **Requirement**: The lock structure must be **smaller than or equal to 16 bytes**
//! to ensure the slab header remains efficient.
//!
//! ## 4. `SlabBox`: Independence & RAII
//!
//! `SlabBox<T>` is a smart pointer that automatically returns its memory to the slab
//! when dropped. It is **independent** of the `SlabCache`. You can clone the cache,
//! drop the cache, or move the `SlabBox` to another thread—it will always find its
//! home slab using the "Alignment == Size" bitmask trick.
//!
//! ## 5. Internal Mechanisms
//!
//! - **Link Lists**: The allocator uses internal intrusive doubly linked lists to
//!   manage slabs. Metadata is stored *inside* the slab headers.
//! - **Freelist**: Within each slab, free slots are tracked using an intrusive
//!   stack (the slot memory itself stores the index of the next free slot).
//!
//! ## 6. Error Handling and Safety
//!
//! ### `Result` and `SlabError`:
//! Operations return a `Result<T, SlabError>`. Common errors include:
//! - `OutOfMemory`: System hooks failed or capacity reached.
//! - `InvalidPointer`: Magic header check failed (indicates corruption or use-after-free).
//!
//! ### ⚠️ Critical Safety:
//! - **Internal Panic/Corruption**: If you write outside the bounds of your type `T`,
//!   you might overwrite the `Slab` header or the internal freelist. This can lead to
//!   internal panics or silent data corruption.
//! - **Double Free**: Manually freeing the same pointer twice will corrupt the
//!   internal list. Always prefer `SlabBox` for automatic management.

#![no_std]

mod allocation;
mod defs;
mod mem_lay;
mod slab;
mod slab_box;
mod slab_cache;
mod slots;
mod utils;

pub mod locks;
#[doc(inline)]
pub use defs::Result;
#[doc(inline)]
pub use defs::SlabError;
#[doc(inline)]
pub use slab_box::SlabBox;
#[doc(inline)]
pub use slab_cache::SlabCache;

mod prelude {
    pub use crate::allocation::*;
    pub use crate::defs::*;
    pub use crate::utils::*;
}