1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use crate::error::{OCamlError, OCamlException};
use crate::memory::{OCamlAllocResult, OCamlAllocToken};
use crate::mlvalues::tag;
use crate::mlvalues::{extract_exception, is_exception_result, tag_val, RawOCaml};
use crate::value::OCaml;
extern "C" {
fn caml_named_value(name: *const i8) -> *const RawOCaml;
fn caml_callback_exn(closure: RawOCaml, arg1: RawOCaml) -> RawOCaml;
fn caml_callback2_exn(closure: RawOCaml, arg1: RawOCaml, arg2: RawOCaml) -> RawOCaml;
fn caml_callback3_exn(
closure: RawOCaml,
arg1: RawOCaml,
arg2: RawOCaml,
arg3: RawOCaml,
) -> RawOCaml;
fn caml_callbackN_exn(closure: RawOCaml, narg: usize, args: *mut RawOCaml) -> RawOCaml;
}
#[derive(Copy, Clone)]
pub struct OCamlClosure(*const RawOCaml);
unsafe impl Sync for OCamlClosure {}
fn get_named(name: &str) -> Option<*const RawOCaml> {
unsafe {
let s = match std::ffi::CString::new(name) {
Ok(s) => s,
Err(_) => return None,
};
let named = caml_named_value(s.as_ptr());
if named.is_null() {
return None;
}
if tag_val(*named) != tag::CLOSURE {
return None;
}
Some(named)
}
}
pub type OCamlResult<T> = Result<OCamlAllocResult<T>, OCamlError>;
pub type OCamlFn1<A, Ret> = unsafe fn(OCamlAllocToken, OCaml<A>) -> OCamlResult<Ret>;
pub type OCamlFn2<A, B, Ret> = unsafe fn(OCamlAllocToken, OCaml<A>, OCaml<B>) -> OCamlResult<Ret>;
pub type OCamlFn3<A, B, C, Ret> = unsafe fn(OCamlAllocToken, OCaml<A>, OCaml<B>, OCaml<C>) -> OCamlResult<Ret>;
pub type OCamlFn4<A, B, C, D, Ret> = unsafe fn(OCamlAllocToken, OCaml<A>, OCaml<B>, OCaml<C>, OCaml<D>) -> OCamlResult<Ret>;
pub type OCamlFn5<A, B, C, D, E, Ret> = unsafe fn(OCamlAllocToken, OCaml<A>, OCaml<B>, OCaml<C>, OCaml<D>, OCaml<E>) -> OCamlResult<Ret>;
impl OCamlClosure {
pub fn named(name: &str) -> Option<OCamlClosure> {
get_named(name).map(OCamlClosure)
}
pub fn call<T, R>(&self, _token: OCamlAllocToken, arg: OCaml<T>) -> OCamlResult<R> {
let result = unsafe { caml_callback_exn(*self.0, arg.raw()) };
self.handle_result(result)
}
pub fn call2<T, U, R>(
&self,
_token: OCamlAllocToken,
arg1: OCaml<T>,
arg2: OCaml<U>,
) -> OCamlResult<R> {
let result = unsafe { caml_callback2_exn(*self.0, arg1.raw(), arg2.raw()) };
self.handle_result(result)
}
pub fn call3<T, U, V, R>(
&self,
_token: OCamlAllocToken,
arg1: OCaml<T>,
arg2: OCaml<U>,
arg3: OCaml<V>,
) -> OCamlResult<R> {
let result = unsafe { caml_callback3_exn(*self.0, arg1.raw(), arg2.raw(), arg3.raw()) };
self.handle_result(result)
}
pub fn call_n<R>(&self, _token: OCamlAllocToken, args: &mut [RawOCaml]) -> OCamlResult<R> {
let len = args.len();
let result = unsafe { caml_callbackN_exn(*self.0, len, args.as_mut_ptr()) };
self.handle_result(result)
}
#[inline]
fn handle_result<R>(self, result: RawOCaml) -> OCamlResult<R> {
if is_exception_result(result) {
let ex = extract_exception(result);
Err(OCamlError::Exception(OCamlException::of(ex)))
} else {
let gv = OCamlAllocResult::of(result);
Ok(gv)
}
}
}