Skip to content

Commit

Permalink
Return ocaml function call results directly instead of wrapped in Result
Browse files Browse the repository at this point in the history
  • Loading branch information
tizoc committed Dec 19, 2020
1 parent d2c6ecf commit 34c141b
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 258 deletions.
24 changes: 10 additions & 14 deletions src/closure.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
// Copyright (c) SimpleStaking and Tezedge Contributors
// SPDX-License-Identifier: MIT

use crate::{OCamlRooted, OCamlRuntime, memory::OCamlAllocResult};
use crate::{OCamlRooted, OCamlRuntime};
use crate::mlvalues::tag;
use crate::mlvalues::{extract_exception, is_exception_result, tag_val, RawOCaml};
use crate::value::OCaml;
use crate::{
error::{OCamlError, OCamlException},
OCamlAllocToken,
};
use ocaml_sys::{
caml_callback2_exn, caml_callback3_exn, caml_callbackN_exn, caml_callback_exn, caml_named_value,
Expand Down Expand Up @@ -37,28 +36,25 @@ fn get_named(name: &str) -> Option<*const RawOCaml> {
}
}

/// The result of calls to OCaml functions. Can be a value or an error.
pub type OCamlResult<T> = Result<OCamlAllocResult<T>, OCamlError>;

/// OCaml function that accepts one argument.
pub type OCamlFn1<A, Ret> = unsafe fn(OCamlAllocToken, OCaml<A>) -> OCamlResult<Ret>;
pub type OCamlFn1<'a, A, Ret> = unsafe fn(&'a mut OCamlRuntime, OCaml<A>) -> OCaml<'a, Ret>;
/// OCaml function that accepts two arguments.
pub type OCamlFn2<A, B, Ret> = unsafe fn(OCamlAllocToken, OCaml<A>, OCaml<B>) -> OCamlResult<Ret>;
pub type OCamlFn2<'a, A, B, Ret> = unsafe fn(&'a mut OCamlRuntime, OCaml<A>, OCaml<B>) -> OCaml<'a, Ret>;
/// OCaml function that accepts three arguments.
pub type OCamlFn3<A, B, C, Ret> =
unsafe fn(OCamlAllocToken, OCaml<A>, OCaml<B>, OCaml<C>) -> OCamlResult<Ret>;
pub type OCamlFn3<'a, A, B, C, Ret> =
unsafe fn(&'a mut OCamlRuntime, OCaml<A>, OCaml<B>, OCaml<C>) -> OCaml<'a, Ret>;
/// OCaml function that accepts four arguments.
pub type OCamlFn4<A, B, C, D, Ret> =
unsafe fn(OCamlAllocToken, OCaml<A>, OCaml<B>, OCaml<C>, OCaml<D>) -> OCamlResult<Ret>;
pub type OCamlFn4<'a, A, B, C, D, Ret> =
unsafe fn(&'a mut OCamlRuntime, OCaml<A>, OCaml<B>, OCaml<C>, OCaml<D>) -> OCaml<'a, Ret>;
/// OCaml function that accepts five arguments.
pub type OCamlFn5<A, B, C, D, E, Ret> = unsafe fn(
OCamlAllocToken,
pub type OCamlFn5<'a, A, B, C, D, E, Ret> = unsafe fn(
&'a mut OCamlRuntime,
OCaml<A>,
OCaml<B>,
OCaml<C>,
OCaml<D>,
OCaml<E>,
) -> OCamlResult<Ret>;
) -> OCaml<'a, Ret>;

impl OCamlClosure {
pub fn named(name: &str) -> Option<OCamlClosure> {
Expand Down
127 changes: 57 additions & 70 deletions src/conv/to_ocaml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,142 +4,134 @@
use core::str;
use ocaml_sys::{caml_alloc, store_field};

use crate::{
memory::{
use crate::{OCamlRuntime, memory::{
alloc_bytes, alloc_cons, alloc_double, alloc_int32, alloc_int64, alloc_some, alloc_string,
alloc_tuple, alloc_tuple_3, alloc_tuple_4, OCamlAllocResult, OCamlRooted,
},
mlvalues::{
alloc_tuple, alloc_tuple_3, alloc_tuple_4, OCamlRooted,
}, mlvalues::{
tag, OCamlBytes, OCamlFloat, OCamlInt, OCamlInt32, OCamlInt64, OCamlList, RawOCaml, FALSE,
NONE, TRUE,
},
ocaml_alloc, ocaml_frame,
runtime::OCamlAllocToken,
to_ocaml,
value::OCaml,
};
}, ocaml_frame, to_ocaml, value::OCaml};

/// Implements conversion from Rust values into OCaml values.
pub unsafe trait ToOCaml<T> {
/// Convert to OCaml value.
///
/// Should not be called directly, use [`to_ocaml!`] macro instead.
/// If called directly, the call should be wrapped by [`ocaml_alloc!`].
fn to_ocaml(&self, token: OCamlAllocToken) -> OCamlAllocResult<T>;
fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, T>;
}

unsafe impl<'a, T> ToOCaml<T> for OCamlRooted<'a, T> {
fn to_ocaml(&self, _token: OCamlAllocToken) -> OCamlAllocResult<T> {
OCamlAllocResult::of(unsafe { self.get_raw() })
unsafe impl<'root, T> ToOCaml<T> for OCamlRooted<'root, T> {
fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, T> {
unsafe { OCaml::new(cr, self.get_raw()) }
}
}

unsafe impl ToOCaml<OCamlInt> for i64 {
fn to_ocaml(&self, _token: OCamlAllocToken) -> OCamlAllocResult<OCamlInt> {
OCamlAllocResult::of(((self << 1) | 1) as RawOCaml)
fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlInt> {
unsafe { OCaml::new(cr, ((self << 1) | 1) as RawOCaml) }
}
}

unsafe impl ToOCaml<OCamlInt> for i32 {
fn to_ocaml(&self, token: OCamlAllocToken) -> OCamlAllocResult<OCamlInt> {
(*self as i64).to_ocaml(token)
fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlInt> {
(*self as i64).to_ocaml(cr)
}
}

unsafe impl ToOCaml<OCamlInt32> for i32 {
fn to_ocaml(&self, token: OCamlAllocToken) -> OCamlAllocResult<OCamlInt32> {
alloc_int32(token, *self)
fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlInt32> {
alloc_int32(cr, *self)
}
}

unsafe impl ToOCaml<OCamlInt64> for i64 {
fn to_ocaml(&self, token: OCamlAllocToken) -> OCamlAllocResult<OCamlInt64> {
alloc_int64(token, *self)
fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlInt64> {
alloc_int64(cr, *self)
}
}

unsafe impl ToOCaml<OCamlFloat> for f64 {
fn to_ocaml(&self, token: OCamlAllocToken) -> OCamlAllocResult<OCamlFloat> {
alloc_double(token, *self)
fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlFloat> {
alloc_double(cr, *self)
}
}

unsafe impl ToOCaml<bool> for bool {
fn to_ocaml(&self, _token: OCamlAllocToken) -> OCamlAllocResult<bool> {
OCamlAllocResult::of(if *self { TRUE } else { FALSE })
fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, bool> {
unsafe { OCaml::new(cr, if *self { TRUE } else { FALSE }) }
}
}

unsafe impl ToOCaml<String> for &str {
fn to_ocaml(&self, token: OCamlAllocToken) -> OCamlAllocResult<String> {
alloc_string(token, self)
fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, String> {
alloc_string(cr, self)
}
}

unsafe impl ToOCaml<OCamlBytes> for &str {
fn to_ocaml(&self, token: OCamlAllocToken) -> OCamlAllocResult<OCamlBytes> {
alloc_bytes(token, self.as_bytes())
fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlBytes> {
alloc_bytes(cr, self.as_bytes())
}
}

unsafe impl ToOCaml<OCamlBytes> for &[u8] {
fn to_ocaml(&self, token: OCamlAllocToken) -> OCamlAllocResult<OCamlBytes> {
alloc_bytes(token, self)
fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlBytes> {
alloc_bytes(cr, self)
}
}

unsafe impl ToOCaml<String> for &[u8] {
fn to_ocaml(&self, token: OCamlAllocToken) -> OCamlAllocResult<String> {
alloc_string(token, unsafe { str::from_utf8_unchecked(self) })
fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, String> {
alloc_string(cr, unsafe { str::from_utf8_unchecked(self) })
}
}

unsafe impl ToOCaml<String> for String {
fn to_ocaml(&self, token: OCamlAllocToken) -> OCamlAllocResult<String> {
self.as_str().to_ocaml(token)
fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, String> {
self.as_str().to_ocaml(cr)
}
}

unsafe impl ToOCaml<OCamlBytes> for String {
fn to_ocaml(&self, token: OCamlAllocToken) -> OCamlAllocResult<OCamlBytes> {
self.as_str().to_ocaml(token)
fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlBytes> {
self.as_str().to_ocaml(cr)
}
}

unsafe impl ToOCaml<String> for Vec<u8> {
fn to_ocaml(&self, token: OCamlAllocToken) -> OCamlAllocResult<String> {
self.as_slice().to_ocaml(token)
fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, String> {
self.as_slice().to_ocaml(cr)
}
}

unsafe impl ToOCaml<OCamlBytes> for Vec<u8> {
fn to_ocaml(&self, token: OCamlAllocToken) -> OCamlAllocResult<OCamlBytes> {
self.as_slice().to_ocaml(token)
fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlBytes> {
self.as_slice().to_ocaml(cr)
}
}

unsafe impl<A, OCamlA> ToOCaml<OCamlA> for Box<A>
where
A: ToOCaml<OCamlA>,
{
fn to_ocaml(&self, token: OCamlAllocToken) -> OCamlAllocResult<OCamlA> {
self.as_ref().to_ocaml(token)
fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlA> {
self.as_ref().to_ocaml(cr)
}
}

unsafe impl<A, OCamlA> ToOCaml<Option<OCamlA>> for Option<A>
where
A: ToOCaml<OCamlA>,
{
fn to_ocaml(&self, token: OCamlAllocToken) -> OCamlAllocResult<Option<OCamlA>> {
let cr = unsafe { &mut token.recover_runtime_handle() };
fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, Option<OCamlA>> {
if let Some(value) = self {
ocaml_frame!(cr, (root), {
let ocaml_value = to_ocaml!(cr, value, root);
alloc_some(unsafe { cr.token() }, &ocaml_value)
alloc_some(cr, &ocaml_value)
})
} else {
OCamlAllocResult::of(NONE)
unsafe { OCaml::new(cr, NONE) }
}
}
}
Expand All @@ -149,20 +141,19 @@ where
A: ToOCaml<OCamlA>,
Err: ToOCaml<OCamlErr>,
{
fn to_ocaml(&self, token: OCamlAllocToken) -> OCamlAllocResult<Result<OCamlA, OCamlErr>> {
let cr = unsafe { &mut token.recover_runtime_handle() };
fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, Result<OCamlA, OCamlErr>> {
match self {
Ok(value) => ocaml_frame!(cr, (root), {
let ocaml_value = to_ocaml!(cr, value, root);
let ocaml_ok = unsafe { caml_alloc(1, tag::TAG_OK) };
unsafe { store_field(ocaml_ok, 0, ocaml_value.get_raw()) };
OCamlAllocResult::of(ocaml_ok)
unsafe { OCaml::new(cr, ocaml_ok) }
}),
Err(error) => ocaml_frame!(cr, (root), {
let ocaml_error = to_ocaml!(cr, error, root);
let ocaml_err = unsafe { caml_alloc(1, tag::TAG_ERROR) };
unsafe { store_field(ocaml_err, 0, ocaml_error.get_raw()) };
OCamlAllocResult::of(ocaml_err)
unsafe { OCaml::new(cr, ocaml_err) }
}),
}
}
Expand All @@ -173,12 +164,11 @@ where
A: ToOCaml<OCamlA>,
B: ToOCaml<OCamlB>,
{
fn to_ocaml(&self, token: OCamlAllocToken) -> OCamlAllocResult<(OCamlA, OCamlB)> {
let cr = unsafe { &mut token.recover_runtime_handle() };
fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, (OCamlA, OCamlB)> {
ocaml_frame!(cr, (fst, snd), {
let fst = to_ocaml!(cr, self.0, fst);
let snd = to_ocaml!(cr, self.1, snd);
alloc_tuple(unsafe { cr.token() }, &fst, &snd)
alloc_tuple(cr, &fst, &snd)
})
}
}
Expand All @@ -189,13 +179,12 @@ where
B: ToOCaml<OCamlB>,
C: ToOCaml<OCamlC>,
{
fn to_ocaml(&self, token: OCamlAllocToken) -> OCamlAllocResult<(OCamlA, OCamlB, OCamlC)> {
let cr = unsafe { &mut token.recover_runtime_handle() };
fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, (OCamlA, OCamlB, OCamlC)> {
ocaml_frame!(cr, (fst, snd, elt3), {
let fst = to_ocaml!(cr, self.0, fst);
let snd = to_ocaml!(cr, self.1, snd);
let elt3 = to_ocaml!(cr, self.2, elt3);
alloc_tuple_3(unsafe { cr.token() }, &fst, &snd, &elt3)
alloc_tuple_3(cr, &fst, &snd, &elt3)
})
}
}
Expand All @@ -208,17 +197,16 @@ where
C: ToOCaml<OCamlC>,
D: ToOCaml<OCamlD>,
{
fn to_ocaml(
fn to_ocaml<'a>(
&self,
token: OCamlAllocToken,
) -> OCamlAllocResult<(OCamlA, OCamlB, OCamlC, OCamlD)> {
let cr = unsafe { &mut token.recover_runtime_handle() };
cr: &'a mut OCamlRuntime,
) -> OCaml<'a, (OCamlA, OCamlB, OCamlC, OCamlD)> {
ocaml_frame!(cr, (fst, snd, elt3, elt4), {
let fst = to_ocaml!(cr, self.0, fst);
let snd = to_ocaml!(cr, self.1, snd);
let elt3 = to_ocaml!(cr, self.2, elt3);
let elt4 = to_ocaml!(cr, self.3, elt4);
alloc_tuple_4(unsafe { cr.token() }, &fst, &snd, &elt3, &elt4)
alloc_tuple_4(cr, &fst, &snd, &elt3, &elt4)
})
}
}
Expand All @@ -227,25 +215,24 @@ unsafe impl<A, OCamlA> ToOCaml<OCamlList<OCamlA>> for Vec<A>
where
A: ToOCaml<OCamlA>,
{
fn to_ocaml(&self, token: OCamlAllocToken) -> OCamlAllocResult<OCamlList<OCamlA>> {
(&self).to_ocaml(token)
fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlList<OCamlA>> {
(&self).to_ocaml(cr)
}
}

unsafe impl<A, OCamlA> ToOCaml<OCamlList<OCamlA>> for &Vec<A>
where
A: ToOCaml<OCamlA>,
{
fn to_ocaml(&self, token: OCamlAllocToken) -> OCamlAllocResult<OCamlList<OCamlA>> {
let cr = unsafe { &mut token.recover_runtime_handle() };
fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlList<OCamlA>> {
ocaml_frame!(cr, (result_root, ov_root), {
let mut result_root = result_root.keep(OCaml::nil());
for elt in self.iter().rev() {
let ov = to_ocaml!(cr, elt, ov_root);
let cons = ocaml_alloc!(alloc_cons(cr, &ov, &result_root));
let cons = alloc_cons(cr, &ov, &result_root);
result_root.set(cons);
}
OCamlAllocResult::of_ocaml(cr.get(&result_root))
cr.get(&result_root)
})
}
}
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,10 +400,10 @@ mod mlvalues;
mod runtime;
mod value;

pub use crate::closure::{OCamlFn1, OCamlFn2, OCamlFn3, OCamlFn4, OCamlFn5, OCamlResult};
pub use crate::closure::{OCamlFn1, OCamlFn2, OCamlFn3, OCamlFn4, OCamlFn5};
pub use crate::conv::{FromOCaml, ToOCaml};
pub use crate::error::{OCamlError, OCamlException};
pub use crate::memory::{OCamlAllocResult, OCamlRooted};
pub use crate::memory::OCamlRooted;
pub use crate::mlvalues::{
OCamlBytes, OCamlFloat, OCamlInt, OCamlInt32, OCamlInt64, OCamlList, RawOCaml,
};
Expand Down
Loading

0 comments on commit 34c141b

Please sign in to comment.