use core::{
alloc::Layout,
ptr::{self, NonNull},
};
#[cfg(feature = "nightly")]
use core::alloc::{AllocError, Allocator};
#[cfg(any(
target_arch = "x86",
target_arch = "arm",
target_arch = "mips",
target_arch = "powerpc",
target_arch = "powerpc64",
target_arch = "sparc",
target_arch = "wasm32",
target_arch = "hexagon",
target_arch = "riscv32"
))]
const MIN_ALIGN: usize = 8;
#[cfg(any(
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "mips64",
target_arch = "s390x",
target_arch = "sparc64",
target_arch = "riscv64"
))]
const MIN_ALIGN: usize = 16;
#[derive(Copy, Clone, Default, Debug)]
pub struct Scratch;
impl Scratch {
#[inline]
pub fn malloc(&self, layout: Layout) -> Option<NonNull<[u8]>> {
let (raw_ptr, alloc_mem_size) =
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
let size = layout.size();
unsafe { (evil_janet::janet_smalloc(size) as *mut u8, size) }
} else {
#[cfg(target_os = "macos")]
if layout.align() > (1 << 31) {
return None;
}
let size = layout.size() + layout.align();
unsafe { (evil_janet::janet_smalloc(size) as *mut u8, size) }
};
NonNull::new(ptr::slice_from_raw_parts_mut(raw_ptr, alloc_mem_size))
}
#[inline]
pub fn calloc(&self, layout: Layout) -> Option<NonNull<[u8]>> {
let (raw_ptr, alloc_mem_size) =
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
let size = layout.size();
unsafe { (evil_janet::janet_scalloc(1, size) as *mut u8, size) }
} else {
#[cfg(target_os = "macos")]
if layout.align() > (1 << 31) {
return None;
}
let size = layout.size() + layout.align();
unsafe { (evil_janet::janet_scalloc(1, size) as *mut u8, size) }
};
NonNull::new(ptr::slice_from_raw_parts_mut(raw_ptr, alloc_mem_size))
}
#[inline]
pub unsafe fn realloc(
&self, ptr: NonNull<[u8]>, layout: Layout, new_size: usize,
) -> Option<NonNull<[u8]>> {
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
let (raw_ptr, alloc_mem_size) =
if layout.align() <= MIN_ALIGN && layout.align() <= new_layout.size() {
let size = new_layout.size();
(
evil_janet::janet_srealloc(ptr.as_ptr() as *mut _, size) as *mut u8,
size,
)
} else {
#[cfg(target_os = "macos")]
if layout.align() > (1 << 31) {
return None;
}
let size = layout.size() + layout.align();
(
evil_janet::janet_srealloc(ptr.as_ptr() as *mut _, size) as *mut u8,
size,
)
};
NonNull::new(ptr::slice_from_raw_parts_mut(raw_ptr, alloc_mem_size))
}
#[inline]
pub unsafe fn free(&self, ptr: NonNull<[u8]>) {
evil_janet::janet_sfree(ptr.as_ptr() as *mut _)
}
}
#[cfg(feature = "nightly")]
#[cfg_attr(docsrs, doc(cfg(feature = "nightly")))]
unsafe impl Allocator for Scratch {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
self.malloc(layout).ok_or(AllocError)
}
unsafe fn deallocate(&self, _ptr: NonNull<u8>, _layout: Layout) {}
}