use caml_ffi_types::{Intnat, Uintnat, Cint, Cchar, Cvoid, Value};
extern {
fn caml_alloc_custom(ops: *const CustomOperations, size: Intnat, used: Intnat, max: Intnat) -> Value;
fn get_custom_data(v: Value) -> *mut Cvoid;
fn set_custom_data(v: Value, p: *mut Cvoid) -> Cvoid;
fn caml_compare_default(v1: Value, v2: Value) -> Cint;
fn caml_compare_ext_default(v1: Value, v2: Value) -> Cint;
fn caml_hash_default(v: Value) -> Intnat;
fn caml_serialize_default(v: Value, bsize_32: *const Uintnat, bsize_64: *const Uintnat) -> Cvoid;
fn caml_deserialize_default(dst: *mut Cvoid) -> Uintnat;
}
#[repr(C)]
pub struct CustomFixedLength {
pub bsize_32: Intnat,
pub bsize_64: Intnat,
}
#[repr(C)]
pub struct CustomOperations {
pub identifier: *const Cchar,
pub finalize: extern fn(v: Value),
pub compare: extern fn (v1: Value, v2: Value) -> Cint,
pub compare_ext: extern fn (v1: Value, v2: Value) -> Cint,
pub hash: extern fn (v: Value) -> Intnat,
pub serialize: extern fn (v: Value, bsize_32: *const Uintnat, *const Uintnat) -> Cvoid,
pub deserialize: extern fn (*mut Cvoid) -> Uintnat,
}
unsafe impl Sync for CustomOperations { }
pub fn alloc<T>(ops_ptr: *const CustomOperations, v: T) -> Value {
let data = Box::new(v);
let size = std::mem::size_of::<*mut Cvoid>() as isize;
let mem = unsafe { caml_alloc_custom(ops_ptr, size, 0, 1) };
let data_ptr = Box::into_raw(data);
unsafe { set_custom_data(mem, data_ptr as *mut Cvoid) };
mem
}
pub fn acquire<T>(v: Value) -> &'static T {
let data_ptr = unsafe { get_custom_data(v) as *mut *mut Cvoid };
let data_ptr = unsafe { (*data_ptr) as *mut T };
unsafe { data_ptr.as_ref().unwrap() }
}
pub extern fn finalize<T>(v: Value) {
let data_ptr = unsafe { get_custom_data(v) as *mut *mut Cvoid };
drop(unsafe { Box::from_raw((*data_ptr) as *mut T) })
}
#[no_mangle]
pub extern fn default_compare(v1: Value, v2: Value) -> Cint {
unsafe { caml_compare_default(v1, v2) }
}
pub extern fn compare<T: Ord>(v1: Value, v2: Value) -> Cint {
let v1_ptr = unsafe { get_custom_data(v1) as *mut *mut Cvoid };
let v2_ptr = unsafe { get_custom_data(v2) as *mut *mut Cvoid };
let v1 = unsafe { Box::from_raw((*v1_ptr) as *mut T) };
let v2 = unsafe { Box::from_raw((*v2_ptr) as *mut T) };
let r = v1.cmp(&v2) as Cint;
let _ = Box::into_raw(v1);
let _ = Box::into_raw(v2);
r
}
#[no_mangle]
pub extern fn default_compare_ext(v1: Value, v2: Value) -> Cint {
unsafe { caml_compare_ext_default(v1, v2) }
}
#[no_mangle]
pub extern fn default_hash(v: Value) -> Intnat {
unsafe { caml_hash_default(v) }
}
#[no_mangle]
pub extern fn default_serialize(v: Value, bsize_32: *const Uintnat, bsize_64: *const Uintnat) -> Cvoid {
unsafe { caml_serialize_default(v, bsize_32, bsize_64) }
}
#[no_mangle]
pub extern fn default_deserialize(dst: *mut Cvoid) -> Uintnat {
unsafe { caml_deserialize_default(dst) }
}