buddy_slab_allocator/lib.rs
1//! buddy-slab-allocator Memory Allocator
2//!
3//! This crate implements a high-performance memory allocator designed for embedded
4//! and kernel environments, featuring:
5//! - Buddy page allocator for page-level allocation
6//! - Slab allocator for small object allocation
7//! - Global allocator coordination
8//! - Zero `std` dependency (fully `#![no_std]`)
9//!
10//! # Features
11//!
12//! - **Buddy Page Allocator**: Efficient page-level memory allocation with automatic merging
13//! - **Slab Byte Allocator**: Fast small object allocation (≤2048 bytes)
14//! - **Global Allocator**: Automatic selection between page and slab allocation based on size
15//! - **No_std Compatible**: Fully `#![no_std]` for embedded/kernel use
16//! - **Optional Logging**: Conditional compilation with `log` feature
17//! - **Memory Tracking**: Detailed statistics with `tracking` feature
18//!
19//! # Quick Start
20//!
21//! ```no_run
22//! use buddy_slab_allocator::{GlobalAllocator, PageAllocator};
23//! use core::alloc::Layout;
24//!
25//! const PAGE_SIZE: usize = 0x1000;
26//! let mut allocator = GlobalAllocator::<PAGE_SIZE>::new();
27//!
28//! // Initialize with memory region
29//! let heap_start = 0x8000_0000;
30//! let heap_size = 16 * 1024 * 1024; // 16MB
31//! allocator.init(heap_start, heap_size).unwrap();
32//!
33//! // Allocate pages
34//! let addr = allocator.alloc_pages(4, PAGE_SIZE).unwrap();
35//! // Use the allocated memory...
36//! allocator.dealloc_pages(addr, 4);
37//! ```
38//!
39//! # Small Object Allocation
40//!
41//! ```no_run
42//! use buddy_slab_allocator::GlobalAllocator;
43//! use core::alloc::Layout;
44//!
45//! const PAGE_SIZE: usize = 0x1000;
46//! let mut allocator = GlobalAllocator::<PAGE_SIZE>::new();
47//! allocator.init(0x8000_0000, 16 * 1024 * 1024).unwrap();
48//!
49//! // Small allocations go through slab allocator
50//! let layout = Layout::from_size_align(64, 8).unwrap();
51//! let ptr = allocator.alloc(layout).unwrap();
52//! // Use the allocated memory...
53//! allocator.dealloc(ptr, layout);
54//! ```
55//!
56//! # Statistics Tracking
57//!
58//! ```no_run
59//! # #[cfg(feature = "tracking")]
60//! # {
61//! use buddy_slab_allocator::GlobalAllocator;
62//!
63//! const PAGE_SIZE: usize = 0x1000;
64//! let mut allocator = GlobalAllocator::<PAGE_SIZE>::new();
65//! allocator.init(0x8000_0000, 16 * 1024 * 1024).unwrap();
66//!
67//! let stats = allocator.get_stats();
68//! println!("Total pages: {}", stats.total_pages);
69//! println!("Used pages: {}", stats.used_pages);
70//! println!("Free pages: {}", stats.free_pages);
71//! # }
72//! ```
73
74#![no_std]
75
76extern crate alloc;
77
78// Logging support - conditionally import log crate
79#[cfg(feature = "log")]
80extern crate log;
81
82// Stub macros when log is disabled - these become no-ops
83#[cfg(not(feature = "log"))]
84macro_rules! error {
85 ($($arg:tt)*) => {};
86}
87#[cfg(not(feature = "log"))]
88macro_rules! warn {
89 ($($arg:tt)*) => {};
90}
91#[cfg(not(feature = "log"))]
92macro_rules! info {
93 ($($arg:tt)*) => {};
94}
95#[cfg(not(feature = "log"))]
96macro_rules! debug {
97 ($($arg:tt)*) => {};
98}
99#[cfg(not(feature = "log"))]
100#[allow(unused_macros)]
101macro_rules! trace {
102 ($($arg:tt)*) => {};
103}
104
105pub use axallocator::{
106 AllocError, AllocResult, BaseAllocator, ByteAllocator, IdAllocator, PageAllocator,
107};
108
109/// Default page size for backward compatibility (4KB)
110pub const DEFAULT_PAGE_SIZE: usize = 0x1000;
111
112/// Address translator used by allocators to reason about physical addresses.
113///
114/// Implementations should provide a stable virtual-to-physical mapping
115/// for the allocator-managed address range.
116///
117/// # Examples
118///
119/// ```
120/// use buddy_slab_allocator::AddrTranslator;
121///
122/// struct SimpleMapper;
123///
124/// impl AddrTranslator for SimpleMapper {
125/// fn virt_to_phys(&self, va: usize) -> Option<usize> {
126/// // Identity mapping for this example
127/// Some(va)
128/// }
129/// }
130/// ```
131pub trait AddrTranslator: Sync {
132 /// Translate a virtual address to a physical address.
133 ///
134 /// Returns `None` if the address is not valid or not mapped.
135 fn virt_to_phys(&self, va: usize) -> Option<usize>;
136}
137
138#[inline]
139#[allow(dead_code)]
140const fn align_down(pos: usize, align: usize) -> usize {
141 pos & !(align - 1)
142}
143
144#[inline]
145#[allow(dead_code)]
146const fn align_up(pos: usize, align: usize) -> usize {
147 (pos + align - 1) & !(align - 1)
148}
149
150/// Checks whether the address has the demanded alignment.
151///
152/// Equivalent to `addr % align == 0`, but the alignment must be a power of two.
153#[inline]
154#[allow(dead_code)]
155const fn is_aligned(base_addr: usize, align: usize) -> bool {
156 base_addr & (align - 1) == 0
157}
158
159// Export our allocator implementations
160pub mod buddy;
161#[cfg(feature = "tracking")]
162pub use buddy::BuddyStats;
163pub use buddy::{BuddyPageAllocator, DEFAULT_MAX_ORDER, MAX_ZONES};
164
165pub mod page_allocator;
166pub use page_allocator::CompositePageAllocator;
167
168pub mod slab;
169pub use slab::slab_byte_allocator::{PageAllocatorForSlab, SizeClass, SlabByteAllocator};
170
171pub mod global_allocator;
172pub use global_allocator::GlobalAllocator;
173#[cfg(feature = "tracking")]
174pub use global_allocator::UsageStats;