It is not as easy as you like.
Distribution methods are expanded in the heap module of the alloc box .
Creating some wrapper methods and filling the structure is straightforward, but we quickly encounter a problem:
#![feature(heap_api)] extern crate libc; extern crate alloc; use libc::{c_void, c_uint}; use alloc::heap; #[repr(C)] #[derive(Copy, Clone, Debug, PartialEq)] pub struct Allocator { alloc: Option<extern "C" fn(*mut c_void, c_uint) -> *mut c_void>, free: Option<extern "C" fn(*mut c_void)>, } extern "C" fn alloc_ext(old: *mut c_void, size: c_uint) -> *mut c_void { if old.is_null() { heap::allocate(size as usize, align) as *mut c_void } else { heap::reallocate(old as *mut u8, old_size, size as usize, align) as *mut c_void } } extern "C" fn free_ext(old: *mut c_void) { heap::deallocate(old as *mut u8, old_size, align); } fn main() { Allocator { alloc: Some(alloc_ext), free: Some(free_ext), }; }
The Rust dispenser expects the size of any previous distribution to be specified, as well as the desired alignment. The corresponding API has no way to pass this.
Coordination should (I'm not an expert) be fine with hard code for some value, say 16 bytes. The size is harder. You will most likely have to steal some of the old C tricks and set aside a little extra storage space for the size. Then you can save the size and return the pointer a bit later.
A completely untested example:
#![feature(alloc, heap_api)] extern crate libc; extern crate alloc; use libc::{c_void, c_uint}; use alloc::heap; use std::{mem, ptr}; #[repr(C)] #[derive(Copy, Clone, Debug, PartialEq)] pub struct Allocator { alloc: Option<extern "C" fn(*mut c_void, c_uint) -> *mut c_void>, free: Option<extern "C" fn(*mut c_void)>, } const ALIGNMENT: usize = 16; extern "C" fn alloc_ext(old: *mut c_void, size: c_uint) -> *mut c_void { unsafe { // Should check for integer overflow let size_size = mem::size_of::<usize>(); let size = size as usize + size_size; let memory = if old.is_null() { heap::allocate(size, ALIGNMENT) } else { let old = old as *mut u8; let old = old.offset(-(size_size as isize)); let old_size = *(old as *const usize); heap::reallocate(old, old_size, size, ALIGNMENT) }; *(memory as *mut usize) = size; memory.offset(size_size as isize) as *mut c_void } } extern "C" fn free_ext(old: *mut c_void) { if old.is_null() { return } unsafe { let size_size = mem::size_of::<usize>(); let old = old as *mut u8; let old = old.offset(-(size_size as isize)); let old_size = *(old as *const usize); heap::deallocate(old as *mut u8, old_size, ALIGNMENT); } } fn main() { Allocator { alloc: Some(alloc_ext), free: Some(free_ext), }; let pointer = alloc_ext(ptr::null_mut(), 54); let pointer = alloc_ext(pointer, 105); free_ext(pointer); }
Not [... using Vec as a distributor ...] a higher-level solution?
This is certainly possible, but I'm not quite sure how this will work with redistribution. You will also need to track the size and capacity of the Vec in order to restore it, to redistribute / delete it.