use core::alloc::{GlobalAlloc, Layout};
use core::ptr;
use veecle_freertos_sys::bindings::{portBYTE_ALIGNMENT, pvPortMalloc, vPortFree};
#[derive(Debug)]
pub struct FreeRtosAllocator {
_private: (),
}
#[repr(C)]
struct OriginalPointer(*mut u8);
impl FreeRtosAllocator {
pub const unsafe fn new() -> Self {
Self { _private: () }
}
}
unsafe impl GlobalAlloc for FreeRtosAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
if layout.align() <= usize::from(portBYTE_ALIGNMENT) {
pvPortMalloc(layout.size()).cast()
} else {
let alloc_information_size =
size_of::<OriginalPointer>() + align_of::<OriginalPointer>();
let required_size = layout.align() + layout.size() + alloc_information_size;
let allocated_memory_region: *mut u8 = pvPortMalloc(required_size).cast();
if allocated_memory_region.is_null() {
return ptr::null_mut();
}
let layout_align_start = unsafe { allocated_memory_region.add(alloc_information_size) };
let offset = layout_align_start.align_offset(layout.align());
if offset >= layout.align() {
unsafe { vPortFree(allocated_memory_region.cast()) };
return ptr::null_mut();
}
let layout_memory_region = unsafe { layout_align_start.add(offset) };
let alloc_info_region_start =
unsafe { layout_memory_region.sub(alloc_information_size) };
let alloc_info_offset =
alloc_info_region_start.align_offset(align_of::<OriginalPointer>());
if alloc_info_offset >= align_of::<OriginalPointer>() {
unsafe { vPortFree(allocated_memory_region.cast()) };
return ptr::null_mut();
}
let original_pointer_location =
unsafe { alloc_info_region_start.add(alloc_info_offset) };
unsafe {
original_pointer_location
.cast::<OriginalPointer>()
.write(OriginalPointer(allocated_memory_region));
}
layout_memory_region
}
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
if layout.align() <= usize::from(portBYTE_ALIGNMENT) {
unsafe { vPortFree(ptr.cast()) }
} else {
let alloc_information_size =
size_of::<OriginalPointer>() + align_of::<OriginalPointer>();
let alloc_info_region_start = unsafe { ptr.sub(alloc_information_size) };
let alloc_info_offset =
alloc_info_region_start.align_offset(align_of::<OriginalPointer>());
let original_pointer_location =
unsafe { alloc_info_region_start.add(alloc_info_offset) };
let original_pointer =
unsafe { original_pointer_location.cast::<OriginalPointer>().read().0 };
unsafe { vPortFree(original_pointer.cast()) }
}
}
}