use std::default::Default;
use std::ptr;
use mlvalues::Value;
#[repr(C)]
#[derive(Debug, Clone)]
pub struct CamlRootsBlock {
pub next: *mut CamlRootsBlock,
pub ntables: usize,
pub nitems: usize,
pub tables: [*mut Value; 5],
}
impl Default for CamlRootsBlock {
fn default() -> CamlRootsBlock {
CamlRootsBlock {
next: ptr::null_mut(),
ntables: 0,
nitems: 0,
tables: [ptr::null_mut(); 5],
}
}
}
extern "C" {
pub static mut caml_local_roots: *mut CamlRootsBlock;
pub fn caml_modify(addr: *mut Value, value: Value);
}
#[macro_export]
macro_rules! return0 {
() => (caml_local_roots = caml_frame; return);
}
#[macro_export]
macro_rules! store_field {
($block: ident, $offset: expr, $val: ident, ) => (
caml_modify (&field!($block, $offset), $val);
);
}
pub unsafe fn store_field(block: *mut Value, offset: usize, value: Value) {
let contents = (block.offset(offset as isize)) as *mut Value;
caml_modify(contents, value);
}
macro_rules! count {
() => (0usize);
( $x:tt $($xs:tt)* ) => (1usize + count!($($xs)*));
}
#[macro_export]
macro_rules! caml_ffi {
($code:tt) => {
let mut caml_frame = $crate::memory::caml_local_roots.clone();
$code;
return
};
($code:tt => $result:ident) => {
let mut caml_frame = $crate::memory::caml_local_roots;
$code;
return $result;
}
}
#[macro_export]
macro_rules! caml_param {
(@step $idx:expr, $caml_roots:ident,) => {
$caml_roots.ntables = $idx;
};
(@step $idx:expr, $caml_roots:ident, $param:ident, $($tail:ident,)*) => {
$caml_roots.tables[$idx] = &mut $param;
caml_param!(@step $idx + 1usize, $caml_roots, $($tail,)*);
};
($($n:ident),*) => {
let mut caml_roots: $crate::memory::CamlRootsBlock = ::std::default::Default::default();
caml_roots.next = $crate::memory::caml_local_roots;
$crate::memory::caml_local_roots = (&mut caml_roots) as *mut $crate::memory::CamlRootsBlock;
caml_roots.nitems = 1; caml_param!(@step 0usize, caml_roots, $($n,)*);
}
}
#[macro_export]
macro_rules! caml_local {
($($local:ident),*) => {
$(let mut $local = $crate::mlvalues::UNIT;)*
caml_param!($($local),*);
}
}
#[macro_export]
macro_rules! caml_body {
(||, <$($local:ident),*>, $code:block) => {
let caml_frame = $crate::memory::caml_local_roots;
caml_local!($($local),*);
$code;
$crate::memory::caml_local_roots = caml_frame;
};
(|$($param:ident),*|, @code $code:block) => {
let caml_frame = $crate::memory::caml_local_roots;
caml_param!($($param),*);
$code;
$crate::memory::caml_local_roots = caml_frame;
};
(|$($param:ident),*|, <$($local:ident),*>, $code:block) => {
let caml_frame = $crate::memory::caml_local_roots;
caml_param!($($param),*);
caml_local!($($local),*);
$code;
$crate::memory::caml_local_roots = caml_frame;
}
}
#[macro_export]
macro_rules! caml {
($name:ident, |$($param:ident),*|, <$($local:ident),*>, $code:block -> $retval:ident) => {
#[no_mangle]
pub unsafe extern fn $name ($(mut $param: $crate::mlvalues::Value,)*) -> $crate::mlvalues::Value {
caml_body!(|$($param),*|, <$($local),*>, $code);
return $retval;
}
};
($name:ident, |$($param:ident),*|, $code:block) => {
#[no_mangle]
pub unsafe extern fn $name ($(mut $param: $crate::mlvalues::Value,)*) {
caml_body!(|$($param),*|, @code $code);
return;
}
};
($name:ident, |$($param:ident),*|, $code:block -> $retval:ident) => {
#[no_mangle]
pub unsafe extern fn $name ($(mut $param: $crate::mlvalues::Value,)*) -> $crate::mlvalues::Value {
caml_body!(|$($param),*|, @code $code);
return $retval;
}
};
}