From 55e1c5113d710f37ae25baafb8f7179ee41e15bc Mon Sep 17 00:00:00 2001 From: tiny-book2 <147479614+tiny-book2@users.noreply.github.com> Date: Thu, 12 Oct 2023 02:06:58 +0000 Subject: [PATCH 1/7] Owned to OCaml --- src/conv/to_ocaml.rs | 126 +++++++++++++++++++++++++++---------------- src/macros.rs | 10 ++-- src/value.rs | 4 +- 3 files changed, 87 insertions(+), 53 deletions(-) diff --git a/src/conv/to_ocaml.rs b/src/conv/to_ocaml.rs index 4dd5ef26..31007223 100644 --- a/src/conv/to_ocaml.rs +++ b/src/conv/to_ocaml.rs @@ -19,66 +19,102 @@ use crate::{ }; /// Implements conversion from Rust values into OCaml values. -pub unsafe trait ToOCaml { +pub unsafe trait ToOCaml: Sized { /// Convert to OCaml value. Return an already rooted value as [`BoxRoot`]``. - fn to_boxroot(&self, cr: &mut OCamlRuntime) -> BoxRoot { + fn to_boxroot(self, cr: &mut OCamlRuntime) -> BoxRoot { BoxRoot::new(self.to_ocaml(cr)) } /// Convert to OCaml value. - fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, T>; + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, T>; } unsafe impl<'root, T> ToOCaml for OCamlRef<'root, T> { - fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, T> { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, T> { unsafe { OCaml::new(cr, self.get_raw()) } } } unsafe impl ToOCaml for BoxRoot { - fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, T> { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, T> { self.get(cr) } } unsafe impl ToOCaml<()> for () { - fn to_ocaml(&self, _cr: &mut OCamlRuntime) -> OCaml<'static, ()> { + fn to_ocaml(self, _cr: &mut OCamlRuntime) -> OCaml<'static, ()> { OCaml::unit() } } unsafe impl ToOCaml for i64 { - fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlInt> { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlInt> { unsafe { OCaml::new(cr, ((self << 1) | 1i64) as RawOCaml) } } } unsafe impl ToOCaml for i32 { - fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlInt> { - (*self as i64).to_ocaml(cr) + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlInt> { + (self as i64).to_ocaml(cr) } } unsafe impl ToOCaml for i32 { - fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlInt32> { - alloc_int32(cr, *self) + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlInt32> { + alloc_int32(cr, self) } } unsafe impl ToOCaml for i64 { - fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlInt64> { - alloc_int64(cr, *self) + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlInt64> { + alloc_int64(cr, self) } } unsafe impl ToOCaml for f64 { - fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlFloat> { - alloc_double(cr, *self) + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlFloat> { + alloc_double(cr, self) } } unsafe impl ToOCaml for bool { - fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, bool> { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, bool> { + unsafe { OCaml::new(cr, if self { TRUE } else { FALSE }) } + } +} + +unsafe impl ToOCaml for &i64 { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlInt> { + unsafe { OCaml::new(cr, ((self << 1) | 1i64) as RawOCaml) } + } +} + +unsafe impl ToOCaml for &i32 { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlInt> { + (*self as i64).to_ocaml(cr) + } +} + +unsafe impl ToOCaml for &i32 { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlInt32> { + alloc_int32(cr, *self) + } +} + +unsafe impl ToOCaml for &i64 { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlInt64> { + alloc_int64(cr, *self) + } +} + +unsafe impl ToOCaml for &f64 { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlFloat> { + alloc_double(cr, *self) + } +} + +unsafe impl ToOCaml for &bool { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, bool> { unsafe { OCaml::new(cr, if *self { TRUE } else { FALSE }) } } } @@ -89,72 +125,70 @@ unsafe impl ToOCaml for bool { // conflict. unsafe impl ToOCaml for &str { - fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, String> { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, String> { alloc_string(cr, self) } } unsafe impl ToOCaml for &str { - fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlBytes> { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlBytes> { alloc_bytes(cr, self.as_bytes()) } } unsafe impl ToOCaml for &[u8] { - fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlBytes> { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlBytes> { alloc_bytes(cr, self) } } unsafe impl ToOCaml for &[u8] { - fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, String> { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, String> { alloc_string(cr, unsafe { str::from_utf8_unchecked(self) }) } } unsafe impl ToOCaml for String { - fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, String> { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, String> { self.as_str().to_ocaml(cr) } } unsafe impl ToOCaml for String { - fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlBytes> { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlBytes> { self.as_str().to_ocaml(cr) } } -unsafe impl ToOCaml for Vec { - fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, String> { - self.as_slice().to_ocaml(cr) +unsafe impl ToOCaml for &String { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, String> { + self.as_str().to_ocaml(cr) } } -unsafe impl ToOCaml for Vec { - fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlBytes> { - self.as_slice().to_ocaml(cr) +unsafe impl ToOCaml for &String { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlBytes> { + self.as_str().to_ocaml(cr) } } -unsafe impl ToOCaml for Box<[u8]> { - fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlBytes> { - let slice: &[u8] = self; - slice.to_ocaml(cr) +unsafe impl ToOCaml for Vec { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, String> { + self.as_slice().to_ocaml(cr) } } -unsafe impl ToOCaml> for Box<[u8]> { - fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, Array1> { - let slice: &[u8] = self; - slice.to_ocaml(cr) +unsafe impl ToOCaml for Vec { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlBytes> { + self.as_slice().to_ocaml(cr) } } -unsafe impl ToOCaml for Box +unsafe impl ToOCaml for &Box where - A: ToOCaml, + for<'a> &'a A: ToOCaml, { - fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlA> { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlA> { self.as_ref().to_ocaml(cr) } } @@ -163,7 +197,7 @@ unsafe impl ToOCaml> for Option where A: ToOCaml, { - fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, Option> { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, Option> { if let Some(value) = self { let ocaml_value = value.to_boxroot(cr); alloc_some(cr, &ocaml_value) @@ -179,7 +213,7 @@ where A: ToOCaml, Err: ToOCaml, { - fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, Result> { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, Result> { match self { Ok(value) => { let ocaml_value = value.to_boxroot(cr); @@ -193,11 +227,11 @@ where } } -unsafe impl ToOCaml> for Vec +unsafe impl ToOCaml> for &Vec where - A: ToOCaml, + for<'a> &'a A: ToOCaml, { - fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlList> { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlList> { let mut result = BoxRoot::new(OCaml::nil()); for elt in self.iter().rev() { let ov = elt.to_boxroot(cr); @@ -216,7 +250,7 @@ macro_rules! tuple_to_ocaml { where $($t: ToOCaml<$ot>),+ { - fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, ($($ot),+)> { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, ($($ot),+)> { let len = $crate::count_fields!($($t)*); let ocaml_tuple: BoxRoot<($($ot),+)> = BoxRoot::new(unsafe { alloc_tuple(cr, len) }); @@ -299,7 +333,7 @@ tuple_to_ocaml!( // This copies unsafe impl ToOCaml> for &[A] { - fn to_ocaml<'a>(&self, cr: &'a mut OCamlRuntime) -> OCaml<'a, Array1> { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, Array1> { alloc_bigarray1(cr, self) } } diff --git a/src/macros.rs b/src/macros.rs index d0f07889..89860ca2 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -587,8 +587,8 @@ macro_rules! impl_to_ocaml_record { ($rust_typ:ty => $ocaml_typ:ident { $($field:ident : $ocaml_field_typ:ty $(=> $conv_expr:expr)?),+ $(,)? }) => { - unsafe impl $crate::ToOCaml<$ocaml_typ> for $rust_typ { - fn to_ocaml<'a>(&self, cr: &'a mut $crate::OCamlRuntime) -> $crate::OCaml<'a, $ocaml_typ> { + unsafe impl $crate::ToOCaml<$ocaml_typ> for &$rust_typ { + fn to_ocaml<'a>(self, cr: &'a mut $crate::OCamlRuntime) -> $crate::OCaml<'a, $ocaml_typ> { $crate::ocaml_alloc_record! { cr, self { $($field : $ocaml_field_typ $(=> $conv_expr)?),+ @@ -858,7 +858,7 @@ macro_rules! impl_to_ocaml_variant { $($t:tt)* }) => { unsafe impl $crate::ToOCaml<$ocaml_typ> for $rust_typ { - fn to_ocaml<'a>(&self, cr: &'a mut $crate::OCamlRuntime) -> $crate::OCaml<'a, $ocaml_typ> { + fn to_ocaml<'a>(self, cr: &'a mut $crate::OCamlRuntime) -> $crate::OCaml<'a, $ocaml_typ> { $crate::ocaml_alloc_variant! { cr, self => { $($t)* @@ -923,8 +923,8 @@ macro_rules! impl_to_ocaml_polymorphic_variant { ($rust_typ:ty => $ocaml_typ:ty { $($t:tt)* }) => { - unsafe impl $crate::ToOCaml<$ocaml_typ> for $rust_typ { - fn to_ocaml<'a>(&self, cr: &'a mut $crate::OCamlRuntime) -> $crate::OCaml<'a, $ocaml_typ> { + unsafe impl $crate::ToOCaml<$ocaml_typ> for &$rust_typ { + fn to_ocaml<'a>(self, cr: &'a mut $crate::OCamlRuntime) -> $crate::OCaml<'a, $ocaml_typ> { $crate::ocaml_alloc_polymorphic_variant! { cr, self => { $($t)* diff --git a/src/value.rs b/src/value.rs index 3507ec29..2b1e54c4 100644 --- a/src/value.rs +++ b/src/value.rs @@ -530,10 +530,10 @@ impl<'a, 'b, OCamlValue> OCamlParam<'a, 'b, (), OCamlValue> for &'a OCamlRef<'b, impl<'a, 'b, RustValue, OCamlValue> OCamlParam<'a, 'b, RustValue, OCamlValue> for &RustValue where - RustValue: crate::ToOCaml, + for<'c> &'c RustValue: crate::ToOCaml, { fn to_rooted(self, cr: &mut OCamlRuntime) -> RefOrRooted<'a, 'b, OCamlValue> { - let boxroot = self.to_boxroot(cr); + let boxroot = crate::ToOCaml::to_boxroot(self, cr); RefOrRooted::Root(boxroot) } } From 168a9d5f1e38b49db0a4aff5efb9e19b2f962b66 Mon Sep 17 00:00:00 2001 From: tiny-book2 <147479614+tiny-book2@users.noreply.github.com> Date: Thu, 12 Oct 2023 04:55:11 +0000 Subject: [PATCH 2/7] impl for ref options and results too --- src/conv/to_ocaml.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/conv/to_ocaml.rs b/src/conv/to_ocaml.rs index 31007223..36b048f7 100644 --- a/src/conv/to_ocaml.rs +++ b/src/conv/to_ocaml.rs @@ -207,6 +207,20 @@ where } } +unsafe impl ToOCaml> for &Option +where + for<'a> &'a A: ToOCaml, +{ + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, Option> { + if let Some(value) = self { + let ocaml_value = value.to_boxroot(cr); + alloc_some(cr, &ocaml_value) + } else { + unsafe { OCaml::new(cr, NONE) } + } + } +} + unsafe impl ToOCaml> for Result where @@ -227,6 +241,26 @@ where } } +unsafe impl ToOCaml> + for &Result +where + for<'a> &'a A: ToOCaml, + for<'a> &'a Err: ToOCaml, +{ + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, Result> { + match self { + Ok(value) => { + let ocaml_value = value.to_boxroot(cr); + alloc_ok(cr, &ocaml_value) + } + Err(error) => { + let ocaml_error = error.to_boxroot(cr); + alloc_error(cr, &ocaml_error) + } + } + } +} + unsafe impl ToOCaml> for &Vec where for<'a> &'a A: ToOCaml, From a65c2641da8ecf5495491125d64895e79ec8b93a Mon Sep 17 00:00:00 2001 From: tiny-book2 <147479614+tiny-book2@users.noreply.github.com> Date: Thu, 12 Oct 2023 05:13:51 +0000 Subject: [PATCH 3/7] double references --- src/conv/to_ocaml.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/conv/to_ocaml.rs b/src/conv/to_ocaml.rs index 36b048f7..9f03e45f 100644 --- a/src/conv/to_ocaml.rs +++ b/src/conv/to_ocaml.rs @@ -276,6 +276,15 @@ where } } +unsafe impl ToOCaml for &&T +where + for<'a> &'a T: ToOCaml, +{ + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlT> { + (*self).to_ocaml(cr) + } +} + // Tuples macro_rules! tuple_to_ocaml { From 6c3b3edd38d7d37bbdc0de6d4c20c5b896d3c138 Mon Sep 17 00:00:00 2001 From: tiny-book2 <147479614+tiny-book2@users.noreply.github.com> Date: Thu, 12 Oct 2023 05:59:51 +0000 Subject: [PATCH 4/7] tuple refs --- src/conv/to_ocaml.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/conv/to_ocaml.rs b/src/conv/to_ocaml.rs index 9f03e45f..477e8741 100644 --- a/src/conv/to_ocaml.rs +++ b/src/conv/to_ocaml.rs @@ -307,6 +307,25 @@ macro_rules! tuple_to_ocaml { cr.get(&ocaml_tuple) } } + + unsafe impl<$($t),+, $($ot: 'static),+> ToOCaml<($($ot),+)> for &($($t),+) + where + $(for<'a> &'a $t: ToOCaml<$ot>),+ + { + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, ($($ot),+)> { + let len = $crate::count_fields!($($t)*); + + let ocaml_tuple: BoxRoot<($($ot),+)> = BoxRoot::new(unsafe { alloc_tuple(cr, len) }); + $( + unsafe { + let field_val = self.$n.to_ocaml(cr).get_raw(); + store_raw_field_at(cr, &ocaml_tuple, $n, field_val); + } + )+ + + cr.get(&ocaml_tuple) + } + } }; } From 45357b39ad4a72e7003a22b39ba80a0e45f6e897 Mon Sep 17 00:00:00 2001 From: tiny-book2 <147479614+tiny-book2@users.noreply.github.com> Date: Thu, 12 Oct 2023 06:21:43 +0000 Subject: [PATCH 5/7] better list support, unsized double refs --- src/conv/to_ocaml.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/conv/to_ocaml.rs b/src/conv/to_ocaml.rs index 477e8741..9419176d 100644 --- a/src/conv/to_ocaml.rs +++ b/src/conv/to_ocaml.rs @@ -261,7 +261,7 @@ where } } -unsafe impl ToOCaml> for &Vec +unsafe impl ToOCaml> for &[A] where for<'a> &'a A: ToOCaml, { @@ -276,9 +276,25 @@ where } } -unsafe impl ToOCaml for &&T +unsafe impl ToOCaml> for Vec +where + A: ToOCaml, +{ + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlList> { + let mut result = BoxRoot::new(OCaml::nil()); + for elt in self.into_iter().rev() { + let ov = elt.to_boxroot(cr); + let cons = alloc_cons(cr, &ov, &result); + result.keep(cons); + } + cr.get(&result) + } +} + +unsafe impl<'b, 'c, T, OCamlT: 'static> ToOCaml for &'b &'c T where for<'a> &'a T: ToOCaml, + T: ?Sized, { fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlT> { (*self).to_ocaml(cr) From b53ea2ec4792e98a1ac8a6496396ad3eb4501ab0 Mon Sep 17 00:00:00 2001 From: tiny-book2 <147479614+tiny-book2@users.noreply.github.com> Date: Thu, 12 Oct 2023 06:24:01 +0000 Subject: [PATCH 6/7] also vec refs --- src/conv/to_ocaml.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/conv/to_ocaml.rs b/src/conv/to_ocaml.rs index 9419176d..bead279d 100644 --- a/src/conv/to_ocaml.rs +++ b/src/conv/to_ocaml.rs @@ -276,6 +276,21 @@ where } } +unsafe impl ToOCaml> for &Vec +where + for<'a> &'a A: ToOCaml, +{ + fn to_ocaml<'a>(self, cr: &'a mut OCamlRuntime) -> OCaml<'a, OCamlList> { + let mut result = BoxRoot::new(OCaml::nil()); + for elt in self.iter().rev() { + let ov = elt.to_boxroot(cr); + let cons = alloc_cons(cr, &ov, &result); + result.keep(cons); + } + cr.get(&result) + } +} + unsafe impl ToOCaml> for Vec where A: ToOCaml, From b25d8178bce6efc0f774a0149465d8c51ee55b26 Mon Sep 17 00:00:00 2001 From: tiny-book2 <147479614+tiny-book2@users.noreply.github.com> Date: Fri, 13 Oct 2023 04:49:38 +0000 Subject: [PATCH 7/7] fix rust-caller test --- testing/rust-caller/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testing/rust-caller/src/lib.rs b/testing/rust-caller/src/lib.rs index ec244b0b..7e999247 100644 --- a/testing/rust-caller/src/lib.rs +++ b/testing/rust-caller/src/lib.rs @@ -149,9 +149,9 @@ pub fn verify_polymorphic_variant_test(cr: &mut OCamlRuntime, variant: ocaml::Po pub fn allocate_alot(cr: &mut OCamlRuntime) -> bool { let vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; for _n in 1..50000 { - let _x: OCaml = vec.to_ocaml(cr); - let _y: OCaml = vec.to_ocaml(cr); - let _z: OCaml = vec.to_ocaml(cr); + let _x: OCaml = vec.as_slice().to_ocaml(cr); + let _y: OCaml = vec.as_slice().to_ocaml(cr); + let _z: OCaml = vec.as_slice().to_ocaml(cr); } true }