8 releases (5 breaking)
| 0.6.0 | Dec 12, 2025 |
|---|---|
| 0.5.0 | Sep 24, 2025 |
| 0.4.1 | Jun 27, 2025 |
| 0.4.0 | May 16, 2025 |
| 0.1.1 | Nov 24, 2024 |
#233 in Memory management
387 downloads per month
Used in 3 crates
(via lossless-transform-utils)
25KB
322 lines
safe-allocator-api
A safe wrapper around the allocator_api's Allocator trait.
This crate provides a wrapper around the returned results, ensuring that any allocated memory is automatically dropped when its lifetime expires.
Features
- Safe wrapper around raw allocations with known layout
- Automatic deallocation when values go out of scope
- Support for custom allocators
- Zero-initialization options
- Grow and shrink operations with proper error handling
- Thread-safe (implements
SendandSync)- Actual thread safety depends on safety of the allocator used internally, tread wisely.
In my case I wrote this crate to have a 'safe' way to make aligned allocations 😉.
Installation
Add this to your Cargo.toml:
[dependencies]
safe-allocator-api = "0.5.0"
Feature Flags
| Feature | Description |
|---|---|
std |
Enable standard library support (enabled by default) |
nightly |
Enable nightly allocator_api feature |
Usage
Basic Allocation
#![cfg_attr(feature = "nightly", feature(allocator_api))]
use safe_allocator_api::prelude::*;
use safe_allocator_api::RawAlloc;
fn allocate_example() -> Result<(), AllocError> {
// Create a new allocation of 1024 bytes
let layout = Layout::array::<u8>(1024).unwrap();
let mut alloc = RawAlloc::new(layout)?;
// Write some data
unsafe {
core::ptr::write(alloc.as_mut_ptr(), 42u8);
}
// Memory is automatically deallocated when alloc goes out of scope
Ok(())
}
Zero-Initialized Memory
#![cfg_attr(feature = "nightly", feature(allocator_api))]
use safe_allocator_api::prelude::*;
use safe_allocator_api::RawAlloc;
fn zero_initialized_example() -> Result<(), AllocError> {
// Create a zero-initialized allocation
let layout = Layout::array::<u8>(1024).unwrap();
let alloc = RawAlloc::new_zeroed(layout)?;
// Verify memory is zeroed
unsafe {
let slice = core::slice::from_raw_parts(alloc.as_ptr(), 1024);
assert!(slice.iter().all(|&x| x == 0));
}
Ok(())
}
Growing and Shrinking Allocations
#![cfg_attr(feature = "nightly", feature(allocator_api))]
use safe_allocator_api::prelude::*;
use safe_allocator_api::RawAlloc;
fn grow_and_shrink_example() -> Result<(), AllocError> {
// Start with a small allocation
let layout = Layout::array::<u8>(100).unwrap();
let mut alloc = RawAlloc::new(layout)?;
// Grow the allocation
let new_layout = Layout::array::<u8>(200).unwrap();
alloc.grow(new_layout)?;
// Shrink it back down
let final_layout = Layout::array::<u8>(50).unwrap();
alloc.shrink(final_layout)?;
Ok(())
}
Custom Allocators
#![cfg_attr(feature = "nightly", feature(allocator_api))]
use safe_allocator_api::prelude::*;
use safe_allocator_api::RawAlloc;
fn custom_allocator_example() -> Result<(), AllocError> {
let layout = Layout::new::<u64>();
let alloc = RawAlloc::new_in(layout, Global)?;
Ok(())
}
Error Handling
Operations will return AllocError in the following cases:
- The allocator reports an error
- Attempting to allocate zero bytes
- Growing to a smaller size
- Shrinking to a larger size
i.e. This is a thin wrapper around the existing API, so we reuse error types from std.
License
Licensed under MIT.
Dependencies
~305KB