use crate::qjs;
mod rust;
use alloc::boxed::Box;
pub use rust::RustAllocator;
pub unsafe trait Allocator {
fn alloc(&mut self, size: usize) -> *mut u8;
fn calloc(&mut self, count: usize, size: usize) -> *mut u8;
unsafe fn dealloc(&mut self, ptr: *mut u8);
unsafe fn realloc(&mut self, ptr: *mut u8, new_size: usize) -> *mut u8;
unsafe fn usable_size(ptr: *mut u8) -> usize
where
Self: Sized;
}
type DynAllocator = Box<dyn Allocator>;
#[derive(Debug)]
pub(crate) struct AllocatorHolder(*mut DynAllocator);
impl Drop for AllocatorHolder {
fn drop(&mut self) {
let _ = unsafe { Box::from_raw(self.0) };
}
}
#[allow(clippy::extra_unused_type_parameters)]
impl AllocatorHolder {
pub(crate) fn functions<A>() -> qjs::JSMallocFunctions
where
A: Allocator,
{
qjs::JSMallocFunctions {
js_calloc: Some(Self::calloc::<A>),
js_malloc: Some(Self::malloc::<A>),
js_free: Some(Self::free::<A>),
js_realloc: Some(Self::realloc::<A>),
js_malloc_usable_size: Some(Self::malloc_usable_size::<A>),
}
}
pub(crate) fn new<A>(allocator: A) -> Self
where
A: Allocator + 'static,
{
Self(Box::into_raw(Box::new(Box::new(allocator))))
}
pub(crate) fn opaque_ptr(&self) -> *mut DynAllocator {
self.0
}
unsafe extern "C" fn calloc<A>(
opaque: *mut qjs::c_void,
count: qjs::size_t,
size: qjs::size_t,
) -> *mut qjs::c_void
where
A: Allocator,
{
let allocator = &mut *(opaque as *mut DynAllocator);
let rust_size: usize = size.try_into().expect(qjs::SIZE_T_ERROR);
let rust_count: usize = count.try_into().expect(qjs::SIZE_T_ERROR);
allocator.calloc(rust_count, rust_size) as *mut qjs::c_void
}
unsafe extern "C" fn malloc<A>(opaque: *mut qjs::c_void, size: qjs::size_t) -> *mut qjs::c_void
where
A: Allocator,
{
let allocator = &mut *(opaque as *mut DynAllocator);
let rust_size: usize = size.try_into().expect(qjs::SIZE_T_ERROR);
allocator.alloc(rust_size) as *mut qjs::c_void
}
unsafe extern "C" fn free<A>(opaque: *mut qjs::c_void, ptr: *mut qjs::c_void)
where
A: Allocator,
{
if ptr.is_null() {
return;
}
let allocator = &mut *(opaque as *mut DynAllocator);
allocator.dealloc(ptr as _);
}
unsafe extern "C" fn realloc<A>(
opaque: *mut qjs::c_void,
ptr: *mut qjs::c_void,
size: qjs::size_t,
) -> *mut qjs::c_void
where
A: Allocator,
{
let rust_size: usize = size.try_into().expect(qjs::SIZE_T_ERROR);
let allocator = &mut *(opaque as *mut DynAllocator);
allocator.realloc(ptr as _, rust_size) as *mut qjs::c_void
}
unsafe extern "C" fn malloc_usable_size<A>(ptr: *const qjs::c_void) -> qjs::size_t
where
A: Allocator,
{
if ptr.is_null() {
return 0;
}
A::usable_size(ptr as _).try_into().unwrap()
}
}