use core::ffi::{CStr, c_void};
#[cfg(feature = "component")]
use core::{
alloc::{AllocError, Allocator, Layout},
ptr::NonNull,
};
use crate::abi::{AnonPtr, SandboxSafe, SbxPtr};
#[cfg(feature = "component")]
use crate::abi::{BMap, BVec};
use super::{AllocRef, AllocRegion, baryl_leak_and_initialize};
#[cfg(feature = "component")]
use super::{baryl_ck_heap_alloc, baryl_ck_heap_free};
unsafe extern "C" fn call_init(addr: u64, userdata: *mut c_void) {
let f = unsafe { &mut *userdata.cast::<&mut dyn FnMut(u64)>() };
f(addr);
}
impl AllocRef {
pub fn leak_and_initialize_sbx<T: SandboxSafe>(
&self,
name: &CStr,
init: impl FnOnce(u64),
) -> SbxPtr<T> {
let mut once = Some(init);
let mut call = |addr: u64| {
let f = once.take().expect("an SbxRegion name inits at most once");
f(addr);
};
let mut dyn_call: &mut dyn FnMut(u64) = &mut call;
let addr = unsafe {
baryl_leak_and_initialize(
*self,
name.as_ptr(),
AllocRegion::SbxRegion,
size_of::<T>() as u64,
align_of::<T>() as u64,
Some(call_init),
(&raw mut dyn_call).cast(),
)
};
SbxPtr::from_addr(addr)
}
pub fn leak_and_initialize_anon<T: SandboxSafe>(
&self,
name: &CStr,
mut init: impl FnMut(u64),
) -> AnonPtr<T> {
let mut call = |addr: u64| init(addr);
let mut dyn_call: &mut dyn FnMut(u64) = &mut call;
let addr = unsafe {
baryl_leak_and_initialize(
*self,
name.as_ptr(),
AllocRegion::AnonRegion,
size_of::<T>() as u64,
align_of::<T>() as u64,
Some(call_init),
(&raw mut dyn_call).cast(),
)
};
AnonPtr::from_addr(addr)
}
#[cfg(feature = "component")]
pub fn ck_heap(&self) -> SbxAlloc {
SbxAlloc(*self)
}
}
#[cfg(feature = "component")]
#[repr(transparent)]
#[derive(Clone, Copy, Debug)]
pub struct SbxAlloc(pub AllocRef);
#[cfg(feature = "component")]
unsafe impl SandboxSafe for SbxAlloc {}
#[cfg(feature = "component")]
unsafe impl Allocator for SbxAlloc {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
let addr =
unsafe { baryl_ck_heap_alloc(self.0, layout.size() as u64, layout.align() as u64) };
NonNull::new(addr as *mut u8)
.map(|p| NonNull::slice_from_raw_parts(p, layout.size()))
.ok_or(AllocError)
}
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
unsafe {
baryl_ck_heap_free(
self.0,
ptr.as_ptr() as u64,
layout.size() as u64,
layout.align() as u64,
);
}
}
}
const _: () = assert!(size_of::<AllocRef>() == 0x8, "the handle is one pointer");
#[cfg(feature = "component")]
const _: () = assert!(size_of::<BVec<u8, SbxAlloc>>() == 0x18, "handle, storage, count");
#[cfg(feature = "component")]
const _: () = assert!(
size_of::<BMap<u64, u64, SbxAlloc>>() == 0x20,
"the slot array and the live count"
);