use std::alloc::{self, Layout};
use std::mem;
#[repr(align(16))]
#[derive(Default, Copy, Clone)]
#[allow(dead_code)]
pub struct AlignedType([u8; 16]);
pub const MIN_ALIGN: usize = mem::align_of::<AlignedType>();
type AllocatorFn = unsafe fn(Layout) -> *mut u8;
unsafe fn allocate(size_bytes: usize, allocator: AllocatorFn) -> *mut u8 {
assert!(mem::align_of::<usize>() <= MIN_ALIGN);
assert!(mem::align_of::<&usize>() <= MIN_ALIGN);
assert!(mem::size_of::<usize>() <= MIN_ALIGN);
let size_prefixed_bytes = MIN_ALIGN.saturating_add(size_bytes);
let layout =
Layout::from_size_align(size_prefixed_bytes, MIN_ALIGN).expect("allocated too many bytes");
let ptr_prefix = allocator(layout);
if ptr_prefix.is_null() {
alloc::handle_alloc_error(layout);
}
(ptr_prefix as *mut usize).write(size_prefixed_bytes);
ptr_prefix.add(MIN_ALIGN)
}
#[no_mangle]
pub unsafe extern "C" fn rust_0_6_malloc(size_bytes: usize) -> *mut u8 {
allocate(size_bytes, alloc::alloc)
}
#[no_mangle]
pub unsafe extern "C" fn rust_0_6_calloc(num: usize, size: usize) -> *mut u8 {
let size_bytes = num * size;
allocate(size_bytes, alloc::alloc_zeroed)
}
#[no_mangle]
pub unsafe extern "C" fn rust_0_6_free(ptr_bytes: *mut u8) {
if ptr_bytes.is_null() {
return;
}
let ptr_prefix = ptr_bytes.sub(MIN_ALIGN);
let size_prefixed_bytes = (ptr_prefix as *mut usize).read();
let layout = Layout::from_size_align(size_prefixed_bytes, MIN_ALIGN).unwrap();
alloc::dealloc(ptr_prefix, layout)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn aligned_type_size() {
unsafe {
assert!(MIN_ALIGN >= mem::size_of::<usize>());
assert!(MIN_ALIGN >= mem::size_of::<u128>());
assert!(MIN_ALIGN >= crate::ffi::c_sizeof_long_double);
}
}
#[test]
fn aligned_type_align() {
unsafe {
assert!(MIN_ALIGN.is_power_of_two());
assert!(MIN_ALIGN >= mem::align_of::<usize>());
assert!(MIN_ALIGN >= mem::align_of::<&usize>());
assert!(MIN_ALIGN >= mem::align_of::<u128>());
assert!(MIN_ALIGN >= crate::ffi::c_alignof_long_double);
}
}
}