1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
//! # 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.
pub use Result;
pub use SlabError;
pub use SlabBox;
pub use SlabCache;