#[cfg_attr(not(feature = "std"), no_std)]
use core::{
ffi::{c_long, c_uint, c_ulong, c_void},
mem::MaybeUninit,
ptr::{addr_of, null_mut},
sync::atomic::{AtomicBool, Ordering},
};
use libc::{free, malloc, realloc, size_t};
use libxdiff_sys::{memallocator_t, mmfile_t, xdl_init_mmfile, xdl_set_allocator, XDL_MMF_ATOMIC};
mod mmfile;
pub use mmfile::*;
mod mmblocks;
pub use mmblocks::*;
#[cfg(test)]
mod tests;
unsafe extern "C" fn wrap_malloc(_obj: *mut c_void, size: c_uint) -> *mut c_void {
malloc(size as size_t)
}
unsafe extern "C" fn wrap_free(_obj: *mut c_void, ptr: *mut c_void) {
free(ptr)
}
unsafe extern "C" fn wrap_realloc(
_obj: *mut c_void,
ptr: *mut c_void,
size: c_uint,
) -> *mut c_void {
realloc(ptr, size as size_t)
}
unsafe fn init() {
let alloc_struct = memallocator_t {
priv_: null_mut(),
malloc: Some(wrap_malloc),
free: Some(wrap_free),
realloc: Some(wrap_realloc),
};
unsafe { xdl_set_allocator(addr_of!(alloc_struct)) };
}
static INITIALIZED: AtomicBool = AtomicBool::new(false);
pub(crate) fn ensure_init() {
if let Ok(_) = INITIALIZED.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) {
unsafe { init() }
}
}
pub(crate) fn init_mmfile(len: usize) -> mmfile_t {
ensure_init();
let mut inner: MaybeUninit<mmfile_t> = MaybeUninit::uninit();
let inner_ptr = inner.as_mut_ptr();
let err = unsafe { xdl_init_mmfile(inner_ptr, len as c_long, XDL_MMF_ATOMIC as c_ulong) };
if err != 0 {
panic!("mmfile initialization failed");
}
unsafe { inner.assume_init() }
}