use core::ffi::c_void;
fn malloc_default(size: usize) -> *mut c_void {
let result = unsafe { libc_malloc(size) };
if size > 0 && result.is_null() {
alloc_failed("allocate", size);
}
result
}
fn calloc_default(count: usize, size: usize) -> *mut c_void {
let result = unsafe { libc_calloc(count, size) };
if count > 0 && result.is_null() {
alloc_failed("allocate", count * size);
}
result
}
unsafe fn realloc_default(buffer: *mut c_void, size: usize) -> *mut c_void {
let result = unsafe { libc_realloc(buffer, size) };
if size > 0 && result.is_null() {
alloc_failed("reallocate", size);
}
result
}
pub fn alloc_failed(action: &str, size: usize) -> ! {
#[cfg(feature = "std")]
std::eprintln!("tree-sitter failed to {action} {size} bytes");
#[cfg(not(feature = "std"))]
let _ = (action, size);
unsafe { abort() }
}
extern "C" {
fn abort() -> !;
#[link_name = "malloc"]
fn libc_malloc(size: usize) -> *mut c_void;
#[link_name = "calloc"]
fn libc_calloc(count: usize, size: usize) -> *mut c_void;
#[link_name = "realloc"]
fn libc_realloc(ptr: *mut c_void, size: usize) -> *mut c_void;
#[link_name = "free"]
fn libc_free(ptr: *mut c_void);
}
#[no_mangle]
pub static mut ts_current_malloc: unsafe extern "C" fn(usize) -> *mut c_void = ts_malloc_default_c;
#[no_mangle]
pub static mut ts_current_calloc: unsafe extern "C" fn(usize, usize) -> *mut c_void =
ts_calloc_default_c;
#[no_mangle]
pub static mut ts_current_realloc: unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void =
ts_realloc_default_c;
#[no_mangle]
pub static mut ts_current_free: unsafe extern "C" fn(*mut c_void) = libc_free_c;
unsafe extern "C" fn ts_malloc_default_c(size: usize) -> *mut c_void {
malloc_default(size)
}
unsafe extern "C" fn ts_calloc_default_c(count: usize, size: usize) -> *mut c_void {
calloc_default(count, size)
}
unsafe extern "C" fn ts_realloc_default_c(buffer: *mut c_void, size: usize) -> *mut c_void {
unsafe { realloc_default(buffer, size) }
}
unsafe extern "C" fn libc_free_c(ptr: *mut c_void) {
unsafe { libc_free(ptr) }
}
#[no_mangle]
pub unsafe extern "C" fn ts_set_allocator(
new_malloc: Option<unsafe extern "C" fn(usize) -> *mut c_void>,
new_calloc: Option<unsafe extern "C" fn(usize, usize) -> *mut c_void>,
new_realloc: Option<unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void>,
new_free: Option<unsafe extern "C" fn(*mut c_void)>,
) {
unsafe {
ts_current_malloc = new_malloc.unwrap_or(ts_malloc_default_c);
ts_current_calloc = new_calloc.unwrap_or(ts_calloc_default_c);
ts_current_realloc = new_realloc.unwrap_or(ts_realloc_default_c);
ts_current_free = new_free.unwrap_or(libc_free_c);
}
}
#[inline]
pub unsafe fn malloc(size: usize) -> *mut c_void {
unsafe { (ts_current_malloc)(size) }
}
#[inline]
pub unsafe fn calloc(count: usize, size: usize) -> *mut c_void {
unsafe { (ts_current_calloc)(count, size) }
}
#[inline]
pub unsafe fn realloc(ptr: *mut c_void, size: usize) -> *mut c_void {
unsafe { (ts_current_realloc)(ptr, size) }
}
#[inline]
pub unsafe fn free(ptr: *mut c_void) {
unsafe { (ts_current_free)(ptr) }
}