ocaml_interop/
closure.rs

1// Copyright (c) Viable Systems and TezEdge Contributors
2// SPDX-License-Identifier: MIT
3
4use crate::mlvalues::tag;
5use crate::mlvalues::{tag_val, RawOCaml};
6use crate::value::OCaml;
7use crate::{OCamlRef, OCamlRuntime};
8use ocaml_sys::{
9    caml_callback2_exn, caml_callback3_exn, caml_callbackN_exn, caml_callback_exn, caml_named_value,
10};
11
12#[derive(Copy, Clone)]
13pub struct OCamlClosure(*const RawOCaml);
14
15unsafe impl Sync for OCamlClosure {}
16
17impl OCamlClosure {
18    pub fn named(name: &str) -> Option<OCamlClosure> {
19        let named = unsafe {
20            let s = match std::ffi::CString::new(name) {
21                Ok(s) => s,
22                Err(_) => return None,
23            };
24            caml_named_value(s.as_ptr())
25        };
26        if named.is_null() || unsafe { tag_val(*named) } != tag::CLOSURE {
27            None
28        } else {
29            Some(OCamlClosure(named))
30        }
31    }
32
33    pub fn call<'a, T, R>(&self, cr: &'a mut OCamlRuntime, arg: OCamlRef<T>) -> OCaml<'a, R> {
34        let result = unsafe { caml_callback_exn(*self.0, arg.get_raw()) };
35        self.handle_call_result(cr, result)
36    }
37
38    pub fn call2<'a, T, U, R>(
39        &self,
40        cr: &'a mut OCamlRuntime,
41        arg1: OCamlRef<T>,
42        arg2: OCamlRef<U>,
43    ) -> OCaml<'a, R> {
44        let result = unsafe { caml_callback2_exn(*self.0, arg1.get_raw(), arg2.get_raw()) };
45        self.handle_call_result(cr, result)
46    }
47
48    pub fn call3<'a, T, U, V, R>(
49        &self,
50        cr: &'a mut OCamlRuntime,
51        arg1: OCamlRef<T>,
52        arg2: OCamlRef<U>,
53        arg3: OCamlRef<V>,
54    ) -> OCaml<'a, R> {
55        let result =
56            unsafe { caml_callback3_exn(*self.0, arg1.get_raw(), arg2.get_raw(), arg3.get_raw()) };
57        self.handle_call_result(cr, result)
58    }
59
60    pub fn call_n<'a, R>(&self, cr: &'a mut OCamlRuntime, args: &mut [RawOCaml]) -> OCaml<'a, R> {
61        let len = args.len();
62        let result = unsafe { caml_callbackN_exn(*self.0, len, args.as_mut_ptr()) };
63        self.handle_call_result(cr, result)
64    }
65
66    #[inline]
67    fn handle_call_result<'a, R>(
68        &self,
69        cr: &'a mut OCamlRuntime,
70        result: RawOCaml,
71    ) -> OCaml<'a, R> {
72        match unsafe { OCaml::of_exception_result(cr, result) } {
73            Some(ex) => panic!("OCaml exception, message: {:?}", ex.message()),
74            None => unsafe { OCaml::new(cr, result) },
75        }
76    }
77}
78
79/// OCaml function that accepts one argument.
80pub type OCamlFn1<'a, A, Ret> = unsafe fn(&'a mut OCamlRuntime, OCamlRef<A>) -> OCaml<'a, Ret>;
81/// OCaml function that accepts two arguments.
82pub type OCamlFn2<'a, A, B, Ret> =
83    unsafe fn(&'a mut OCamlRuntime, OCamlRef<A>, OCamlRef<B>) -> OCaml<'a, Ret>;
84/// OCaml function that accepts three arguments.
85pub type OCamlFn3<'a, A, B, C, Ret> =
86    unsafe fn(&'a mut OCamlRuntime, OCamlRef<A>, OCamlRef<B>, OCamlRef<C>) -> OCaml<'a, Ret>;
87/// OCaml function that accepts four arguments.
88pub type OCamlFn4<'a, A, B, C, D, Ret> = unsafe fn(
89    &'a mut OCamlRuntime,
90    OCamlRef<A>,
91    OCamlRef<B>,
92    OCamlRef<C>,
93    OCamlRef<D>,
94) -> OCaml<'a, Ret>;
95/// OCaml function that accepts five arguments.
96pub type OCamlFn5<'a, A, B, C, D, E, Ret> = unsafe fn(
97    &'a mut OCamlRuntime,
98    OCamlRef<A>,
99    OCamlRef<B>,
100    OCamlRef<C>,
101    OCamlRef<D>,
102    OCamlRef<E>,
103) -> OCaml<'a, Ret>;