#allocator-api #safe #traits #allocation #alloc #layout #automatic

no-std safe-allocator-api

A safe wrapper around the allocator_api’s Allocator trait

4 releases (2 breaking)

0.3.0 Nov 26, 2024
0.2.0 Nov 24, 2024
0.1.1 Nov 24, 2024
0.1.0 Nov 24, 2024

#160 in Memory management

Download history 167/week @ 2024-11-18 152/week @ 2024-11-25 158/week @ 2024-12-02 4/week @ 2024-12-09

481 downloads per month

Custom license

24KB
301 lines

safe-allocator-api

Crates.io Docs.rs CI License: MIT

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 Send and Sync)
    • 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 😉.

Usage

Add this to your Cargo.toml:

[dependencies]
safe-allocator-api = "0.1.0"

Examples

Basic Allocation

use allocator_api2::alloc::*;
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

use allocator_api2::alloc::*;
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

use allocator_api2::alloc::*;
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

use allocator_api2::alloc::*;
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.

Crate Features

  • std [default]: Builds against std
  • nightly: Enables the nightly allocator_api feature

Development

For information on how to work with this codebase, see README-DEV.MD.

License

Licensed under MIT.

Learn more about Reloaded's general choice of licensing for projects..

Dependencies

~265KB