#[cfg(doc)]
use crate::*;
#[macro_export]
macro_rules! ocaml {
() => ();
($vis:vis fn $name:ident(
$arg:ident: $typ:ty $(,)?
) $(-> $rtyp:ty)?; $($t:tt)*) => {
$vis fn $name<'a>(
cr: &'a mut $crate::OCamlRuntime,
$arg: $crate::OCamlRef<$typ>,
) -> $crate::BoxRoot<$crate::default_to_unit!($($rtyp)?)> {
$crate::ocaml_closure_reference!(closure, $name);
$crate::BoxRoot::new(closure.call(cr, $arg))
}
$crate::ocaml!($($t)*);
};
($vis:vis fn $name:ident(
$arg1:ident: $typ1:ty,
$arg2:ident: $typ2:ty $(,)?
) $(-> $rtyp:ty)?; $($t:tt)*) => {
$vis fn $name<'a>(
cr: &'a mut $crate::OCamlRuntime,
$arg1: $crate::OCamlRef<$typ1>,
$arg2: $crate::OCamlRef<$typ2>,
) -> $crate::BoxRoot<$crate::default_to_unit!($($rtyp)?)> {
$crate::ocaml_closure_reference!(closure, $name);
$crate::BoxRoot::new(closure.call2(cr, $arg1, $arg2))
}
$crate::ocaml!($($t)*);
};
($vis:vis fn $name:ident(
$arg1:ident: $typ1:ty,
$arg2:ident: $typ2:ty,
$arg3:ident: $typ3:ty $(,)?
) $(-> $rtyp:ty)?; $($t:tt)*) => {
$vis fn $name<'a>(
cr: &'a mut $crate::OCamlRuntime,
$arg1: $crate::OCamlRef<$typ1>,
$arg2: $crate::OCamlRef<$typ2>,
$arg3: $crate::OCamlRef<$typ3>,
) -> $crate::BoxRoot<$crate::default_to_unit!($($rtyp)?)> {
$crate::ocaml_closure_reference!(closure, $name);
$crate::BoxRoot::new(closure.call3(cr, $arg1, $arg2, $arg3))
}
$crate::ocaml!($($t)*);
};
($vis:vis fn $name:ident(
$($arg:ident: $typ:ty),+ $(,)?
) $(-> $rtyp:ty)?; $($t:tt)*) => {
$vis fn $name<'a>(
cr: &'a mut $crate::OCamlRuntime,
$($arg: $crate::OCamlRef<$typ>),+
) -> $crate::BoxRoot<$crate::default_to_unit!($($rtyp)?)> {
$crate::ocaml_closure_reference!(closure, $name);
$crate::BoxRoot::new(closure.call_n(cr, &mut [$(unsafe { $arg.get_raw() }),+]))
}
$crate::ocaml!($($t)*);
}
}
#[macro_export]
macro_rules! impl_conv_ocaml_record {
($rust_typ:ident => $ocaml_typ:ident {
$($field:ident : $ocaml_field_typ:ty $(=> $conv_expr:expr)?),+ $(,)?
}) => {
$crate::impl_to_ocaml_record! {
$rust_typ => $ocaml_typ {
$($field : $ocaml_field_typ $(=> $conv_expr)?),+
}
}
$crate::impl_from_ocaml_record! {
$ocaml_typ => $rust_typ {
$($field : $ocaml_field_typ),+
}
}
};
($both_typ:ident {
$($t:tt)*
}) => {
$crate::impl_conv_ocaml_record! {
$both_typ => $both_typ {
$($t)*
}
}
};
}
#[macro_export]
macro_rules! impl_conv_ocaml_variant {
($rust_typ:ty => $ocaml_typ:ty {
$($($tag:ident)::+ $(($($slot_name:ident: $slot_typ:ty),+ $(,)?))? $(=> $conv:expr)?),+ $(,)?
}) => {
$crate::impl_to_ocaml_variant! {
$rust_typ => $ocaml_typ {
$($($tag)::+ $(($($slot_name: $slot_typ),+))? $(=> $conv)?),+
}
}
$crate::impl_from_ocaml_variant! {
$ocaml_typ => $rust_typ {
$($($tag)::+ $(($($slot_name: $slot_typ),+))?),+
}
}
};
($both_typ:ty {
$($t:tt)*
}) => {
$crate::impl_conv_ocaml_variant!{
$both_typ => $both_typ {
$($t)*
}
}
};
}
#[macro_export]
macro_rules! ocaml_unpack_record {
($var:ident => $cons:ident {
$($field:ident : $ocaml_typ:ty),+ $(,)?
}) => {{
let record = $var;
unsafe {
let mut current = 0;
$(
let $field = record.field::<$ocaml_typ>(current).to_rust();
current += 1;
)+
$cons {
$($field),+
}
}
}};
($var:ident => $cons:ident (
$($field:ident : $ocaml_typ:ty),+ $(,)?
)) => {{
let record = $var;
unsafe {
let mut current = 0;
$(
let $field = record.field::<$ocaml_typ>(current).to_rust();
current += 1;
)+
$cons (
$($field),+
)
}
}};
}
#[macro_export]
macro_rules! ocaml_alloc_tagged_block {
($cr:ident, $tag:expr, $($field:ident : $ocaml_typ:ty),+ $(,)?) => {
unsafe {
let mut current = 0;
let field_count = $crate::count_fields!($($field)*);
let block: $crate::BoxRoot<()> = $crate::BoxRoot::new($crate::OCaml::new($cr, $crate::internal::caml_alloc(field_count, $tag)));
$(
let $field: $crate::OCaml<$ocaml_typ> = $field.to_ocaml($cr);
$crate::internal::store_field(block.get_raw(), current, $field.raw());
current += 1;
)+
$crate::OCaml::new($cr, block.get_raw())
}
};
}
#[macro_export]
macro_rules! ocaml_alloc_record {
($cr:ident, $self:ident {
$($field:ident : $ocaml_typ:ty $(=> $conv_expr:expr)?),+ $(,)?
}) => {
unsafe {
let mut current = 0;
let field_count = $crate::count_fields!($($field)*);
let record: $crate::BoxRoot<()> = $crate::BoxRoot::new($crate::OCaml::new($cr, $crate::internal::caml_alloc(field_count, 0)));
$(
let $field = &$crate::prepare_field_for_mapping!($self.$field $(=> $conv_expr)?);
let $field: $crate::OCaml<$ocaml_typ> = $field.to_ocaml($cr);
$crate::internal::store_field(record.get_raw(), current, $field.raw());
current += 1;
)+
$crate::OCaml::new($cr, record.get_raw())
}
};
}
#[macro_export]
macro_rules! impl_from_ocaml_record {
($ocaml_typ:ident => $rust_typ:ident {
$($field:ident : $ocaml_field_typ:ty),+ $(,)?
}) => {
unsafe impl $crate::FromOCaml<$ocaml_typ> for $rust_typ {
fn from_ocaml(v: $crate::OCaml<$ocaml_typ>) -> Self {
$crate::ocaml_unpack_record! { v =>
$rust_typ {
$($field : $ocaml_field_typ),+
}
}
}
}
};
($both_typ:ident {
$($t:tt)*
}) => {
$crate::impl_from_ocaml_record! {
$both_typ => $both_typ {
$($t)*
}
}
};
($ocaml_typ:ident => $rust_typ:ident (
$($field:ident : $ocaml_field_typ:ty),+ $(,)?
)) => {
unsafe impl $crate::FromOCaml<$ocaml_typ> for $rust_typ {
fn from_ocaml(v: $crate::OCaml<$ocaml_typ>) -> Self {
$crate::ocaml_unpack_record! { v =>
$rust_typ (
$($field : $ocaml_field_typ),+
)
}
}
}
};
($both_typ:ident (
$($t:tt)*
)) => {
$crate::impl_from_ocaml_record! {
$both_typ => $both_typ (
$($t)*
)
}
};
}
#[macro_export]
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> {
$crate::ocaml_alloc_record! {
cr, self {
$($field : $ocaml_field_typ $(=> $conv_expr)?),+
}
}
}
}
};
($both_typ:ident {
$($t:tt)*
}) => {
$crate::impl_to_ocaml_record! {
$both_typ => $both_typ {
$($t)*
}
}
};
}
#[macro_export]
macro_rules! impl_from_ocaml_variant {
($ocaml_typ:ty => $rust_typ:ty {
$($t:tt)*
}) => {
unsafe impl $crate::FromOCaml<$ocaml_typ> for $rust_typ {
fn from_ocaml(v: $crate::OCaml<$ocaml_typ>) -> Self {
let result = $crate::ocaml_unpack_variant! {
v => {
$($t)*
}
};
let msg = concat!(
"Failure when unpacking an OCaml<", stringify!($ocaml_typ), "> variant into ",
stringify!($rust_typ), " (unexpected tag value)");
result.expect(msg)
}
}
};
($both_typ:ty {
$($t:tt)*
}) => {
$crate::impl_from_ocaml_variant!{
$both_typ => $both_typ {
$($t)*
}
}
};
}
#[macro_export]
macro_rules! ocaml_unpack_variant {
($self:ident => {
$($($tag:ident)::+ $(($($slot_name:ident: $slot_typ:ty),+ $(,)?))? $(=> $conv:expr)?),+ $(,)?
}) => {
(|| {
let mut current_block_tag = 0;
let mut current_long_tag = 0;
$(
$crate::unpack_variant_tag!(
$self, current_block_tag, current_long_tag,
$($tag)::+ $(($($slot_name: $slot_typ),+))? $(=> $conv)?);
)+
Err("Invalid tag value found when converting from an OCaml variant")
})()
};
($self:ident => {
$($($tag:ident)::+ $({$($slot_name:ident: $slot_typ:ty),+ $(,)?})? $(=> $conv:expr)?),+ $(,)?
}) => {
(|| {
let mut current_block_tag = 0;
let mut current_long_tag = 0;
$(
$crate::unpack_variant_tag!(
$self, current_block_tag, current_long_tag,
$($tag)::+ $({$($slot_name: $slot_typ),+})? $(=> $conv)?);
)+
Err("Invalid tag value found when converting from an OCaml variant")
})()
};
}
#[macro_export]
macro_rules! ocaml_alloc_variant {
($cr:ident, $self:ident => {
$($($tag:ident)::+ $(($($slot_name:ident: $slot_typ:ty),+ $(,)?))? $(,)?),+
}) => {
$crate::ocaml_alloc_variant_match!{
$cr, $self, 0u8, 0u8,
@units {}
@blocks {}
@pending $({ $($tag)::+ $(($($slot_name: $slot_typ),+))? })+
}
};
}
#[macro_export]
macro_rules! impl_to_ocaml_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> {
$crate::ocaml_alloc_variant! {
cr, self => {
$($t)*
}
}
}
}
};
($both_typ:ty {
$($t:tt)*
}) => {
$crate::impl_to_ocaml_variant!{
$both_typ => $both_typ {
$($t)*
}
}
};
}
#[macro_export]
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> {
$crate::ocaml_alloc_polymorphic_variant! {
cr, self => {
$($t)*
}
}
}
}
};
($both_typ:ty {
$($t:tt)*
}) => {
$crate::impl_to_ocaml_polymorphic_variant!{
$both_typ => $both_typ {
$($t)*
}
}
};
}
#[macro_export]
macro_rules! impl_from_ocaml_polymorphic_variant {
($ocaml_typ:ty => $rust_typ:ty {
$($t:tt)*
}) => {
unsafe impl $crate::FromOCaml<$ocaml_typ> for $rust_typ {
fn from_ocaml(v: $crate::OCaml<$ocaml_typ>) -> Self {
let result = $crate::ocaml_unpack_polymorphic_variant! {
v => {
$($t)*
}
};
let msg = concat!(
"Failure when unpacking an OCaml<", stringify!($ocaml_typ), "> polymorphic variant into ",
stringify!($rust_typ), " (unexpected tag value)");
result.expect(msg)
}
}
};
($both_typ:ty {
$($t:tt)*
}) => {
$crate::impl_from_ocaml_polymorphic_variant!{
$both_typ => $both_typ {
$($t)*
}
}
};
}
#[macro_export]
macro_rules! ocaml_unpack_polymorphic_variant {
($self:ident => {
$($tag:ident $(($($slot_name:ident: $slot_typ:ty),+ $(,)?))? => $conv:expr),+ $(,)?
}) => {
(|| {
$(
$crate::unpack_polymorphic_variant_tag!(
$self, $tag $(($($slot_name: $slot_typ),+))? => $conv);
)+
Err("Invalid tag value found when converting from an OCaml polymorphic variant")
})()
};
}
#[macro_export]
macro_rules! ocaml_alloc_polymorphic_variant {
($cr:ident, $self:ident => {
$($($tag:ident)::+ $(($($slot_name:ident: $slot_typ:ty),+ $(,)?))? $(,)?),+
}) => {
$crate::ocaml_alloc_polymorphic_variant_match!{
$cr, $self,
@units {}
@unit_blocks {}
@blocks {}
@pending $({ $($tag)::+ $(($($slot_name: $slot_typ),+))? })+
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! count_fields {
() => {0usize};
($_f1:ident $_f2:ident $_f3:ident $_f4:ident $_f5:ident $($fields:ident)*) => {
5usize + $crate::count_fields!($($fields)*)
};
($field:ident $($fields:ident)*) => {1usize + $crate::count_fields!($($fields)*)};
}
#[doc(hidden)]
#[macro_export]
macro_rules! prepare_field_for_mapping {
($self:ident.$field:ident) => {
$self.$field
};
($self:ident.$field:ident => $conv_expr:expr) => {{
let $field = &$self.$field;
$conv_expr
}};
}
#[doc(hidden)]
#[macro_export]
macro_rules! unpack_variant_tag {
($self:ident, $current_block_tag:ident, $current_long_tag:ident, $($tag:ident)::+) => {
$crate::unpack_variant_tag!($self, $current_block_tag, $current_long_tag, $($tag)::+ => $($tag)::+)
};
($self:ident, $current_block_tag:ident, $current_long_tag:ident, $($tag:ident)::+ => $conv:expr) => {
if $self.is_long() && $crate::internal::int_val(unsafe { $self.raw() }) == $current_long_tag {
return Ok($conv);
}
$current_long_tag += 1;
};
($self:ident, $current_block_tag:ident, $current_long_tag:ident,
$($tag:ident)::+ ($($slot_name:ident: $slot_typ:ty),+)) => {
$crate::unpack_variant_tag!(
$self, $current_block_tag, $current_long_tag,
$($tag)::+ ($($slot_name: $slot_typ),+) => $($tag)::+($($slot_name),+))
};
($self:ident, $current_block_tag:ident, $current_long_tag:ident,
$($tag:ident)::+ {$($slot_name:ident: $slot_typ:ty),+}) => {
$crate::unpack_variant_tag!(
$self, $current_block_tag, $current_long_tag,
$($tag)::+ {$($slot_name: $slot_typ),+} => $($tag)::+{$($slot_name),+})
};
($self:ident, $current_block_tag:ident, $current_long_tag:ident,
$($tag:ident)::+ ($($slot_name:ident: $slot_typ:ty),+) => $conv:expr) => {
if $self.is_block() && $self.tag_value() == $current_block_tag {
let mut current_field = 0;
$(
let $slot_name = unsafe { $self.field::<$slot_typ>(current_field).to_rust() };
current_field += 1;
)+
return Ok($conv);
}
$current_block_tag += 1;
};
($self:ident, $current_block_tag:ident, $current_long_tag:ident,
$($tag:ident)::+ {$($slot_name:ident: $slot_typ:ty),+} => $conv:expr) => {
if $self.is_block() && $self.tag_value() == $current_block_tag {
let mut current_field = 0;
$(
let $slot_name = unsafe { $self.field::<$slot_typ>(current_field).to_rust() };
current_field += 1;
)+
return Ok($conv);
}
$current_block_tag += 1;
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! ocaml_alloc_variant_match {
($cr:ident, $self:ident, $current_block_tag:expr, $current_long_tag:expr,
@units {
$({ $($unit_tag:ident)::+ @ $unit_tag_counter:expr })*
}
@blocks {
$({ $($block_tag:ident)::+ ($($block_slot_name:ident: $block_slot_typ:ty),+) @ $block_tag_counter:expr })*
}
@pending
) => {
match $self {
$(
$($unit_tag)::+ =>
unsafe { $crate::OCaml::new($cr, $crate::OCaml::of_i64_unchecked($unit_tag_counter as i64).raw()) },
)*
$(
$($block_tag)::+($($block_slot_name),+) =>
$crate::ocaml_alloc_tagged_block!($cr, $block_tag_counter, $($block_slot_name: $block_slot_typ),+),
)*
}
};
($cr:ident, $self:ident, $current_block_tag:expr, $current_long_tag:expr,
@units { $($unit_tags_accum:tt)* }
@blocks { $($block_tags_accum:tt)* }
@pending
{ $($found_tag:ident)::+ }
$($tail:tt)*
) => {
$crate::ocaml_alloc_variant_match!{
$cr, $self, $current_block_tag, {1u8 + $current_long_tag},
@units {
$($unit_tags_accum)*
{ $($found_tag)::+ @ $current_long_tag }
}
@blocks { $($block_tags_accum)* }
@pending $($tail)*
}
};
($cr:ident, $self:ident, $current_block_tag:expr, $current_long_tag:expr,
@units { $($unit_tags_accum:tt)* }
@blocks { $($block_tags_accum:tt)* }
@pending
{ $($found_tag:ident)::+ ($($found_slot_name:ident: $found_slot_typ:ty),+) }
$($tail:tt)*
) => {
$crate::ocaml_alloc_variant_match!{
$cr, $self, {1u8 + $current_block_tag}, $current_long_tag,
@units { $($unit_tags_accum)* }
@blocks {
$($block_tags_accum)*
{ $($found_tag)::+ ($($found_slot_name: $found_slot_typ),+) @ $current_block_tag }
}
@pending $($tail)*
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! ocaml_alloc_polymorphic_variant_match {
($cr:ident, $self:ident,
@units {
$({ $($unit_tag:ident)::+ })*
}
@unit_blocks {
$({ $($unit_block_tag:ident)::+ ($unit_block_slot_name:ident: $unit_block_slot_typ:ty) })*
}
@blocks {
$({ $($block_tag:ident)::+ ($($block_slot_name:ident: $block_slot_typ:ty),+) })*
}
@pending
) => {
match &$self {
$(
$($unit_tag)::+ => {
let polytag = $crate::polymorphic_variant_tag_hash!($($unit_tag)::+);
unsafe { $crate::OCaml::new($cr, polytag) }
},
)*
$(
$($unit_block_tag)::+($unit_block_slot_name) => {
let polytag = $crate::polymorphic_variant_tag_hash!($($unit_block_tag)::+);
let $unit_block_slot_name: $crate::BoxRoot<$unit_block_slot_typ> =
$crate::ToOCaml::to_boxroot($unit_block_slot_name, $cr);
unsafe {
let block = $crate::internal::caml_alloc(2, $crate::internal::tag::TAG_POLYMORPHIC_VARIANT);
$crate::internal::store_field(block, 0, polytag);
$crate::internal::store_field(block, 1, $unit_block_slot_name.get($cr).raw());
$crate::OCaml::new($cr, block)
}
},
)*
$(
$($block_tag)::+($($block_slot_name),+) => {
let polytag = $crate::polymorphic_variant_tag_hash!($($block_tag)::+);
let tuple: $crate::BoxRoot<($($block_slot_typ),+)> =
$crate::BoxRoot::new(unsafe {
$crate::internal::alloc_tuple($cr, $crate::count_fields!($($block_slot_name)+))
});
let mut n = 0;
$(
let $block_slot_name: $crate::OCaml<$block_slot_typ> =
$crate::ToOCaml::to_ocaml($block_slot_name, $cr);
let raw = unsafe { $block_slot_name.raw() };
unsafe { $crate::internal::store_field(tuple.get($cr).raw(), n, raw) };
n += 1;
)+
unsafe {
let block = $crate::internal::caml_alloc(2, $crate::internal::tag::TAG_POLYMORPHIC_VARIANT);
$crate::internal::store_field(block, 0, polytag);
$crate::internal::store_field(block, 1, tuple.get($cr).raw());
$crate::OCaml::new($cr, block)
}
},
)*
}
};
($cr:ident, $self:ident,
@units { $($unit_tags_accum:tt)* }
@unit_blocks { $($unit_block_tags_accum:tt)* }
@blocks { $($block_tags_accum:tt)* }
@pending
{ $($found_tag:ident)::+ }
$($tail:tt)*
) => {
$crate::ocaml_alloc_polymorphic_variant_match!{
$cr, $self,
@units {
$($unit_tags_accum)*
{ $($found_tag)::+ }
}
@unit_blocks { $($unit_block_tags_accum)* }
@blocks { $($block_tags_accum)* }
@pending $($tail)*
}
};
($cr:ident, $self:ident,
@units { $($unit_tags_accum:tt)* }
@unit_blocks { $($unit_block_tags_accum:tt)* }
@blocks { $($block_tags_accum:tt)* }
@pending
{ $($found_tag:ident)::+ ($found_slot_name:ident: $found_slot_typ:ty) }
$($tail:tt)*
) => {
$crate::ocaml_alloc_polymorphic_variant_match!{
$cr, $self,
@units { $($unit_tags_accum)* }
@unit_blocks {
$($unit_block_tags_accum)*
{ $($found_tag)::+ ($found_slot_name: $found_slot_typ) }
}
@blocks { $($block_tags_accum)* }
@pending $($tail)*
}
};
($cr:ident, $self:ident,
@units { $($unit_tags_accum:tt)* }
@unit_blocks { $($unit_block_tags_accum:tt)* }
@blocks { $($block_tags_accum:tt)* }
@pending
{ $($found_tag:ident)::+ ($($found_slot_name:ident: $found_slot_typ:ty),+) }
$($tail:tt)*
) => {
$crate::ocaml_alloc_polymorphic_variant_match!{
$cr, $self,
@units { $($unit_tags_accum)* }
@unit_blocks { $($unit_block_tags_accum)* }
@blocks {
$($block_tags_accum)*
{ $($found_tag)::+ ($($found_slot_name: $found_slot_typ),+) }
}
@pending $($tail)*
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! unpack_polymorphic_variant_tag {
($self:ident, $tag:ident => $conv:expr) => {
#[allow(non_snake_case)]
let $tag = $crate::polymorphic_variant_tag_hash!($tag);
if $self.is_long() && unsafe { $self.raw() } == $tag {
return Ok($conv);
}
};
($self:ident, $tag:ident($slot_name:ident: $slot_typ:ty) => $conv:expr) => {
#[allow(non_snake_case)]
let $tag = $crate::polymorphic_variant_tag_hash!($tag);
if $self.is_block_sized(2) &&
$self.tag_value() == $crate::internal::tag::TAG_POLYMORPHIC_VARIANT &&
unsafe { $self.field::<$crate::OCamlInt>(0).raw() } == $tag {
let $slot_name = unsafe { $self.field::<$slot_typ>(1).to_rust() };
return Ok($conv);
}
};
($self:ident, $tag:ident($($slot_name:ident: $slot_typ:ty),+) => $conv:expr) => {
#[allow(non_snake_case)]
let $tag = $crate::polymorphic_variant_tag_hash!($tag);
if $self.is_block_sized(2) &&
$self.tag_value() == $crate::internal::tag::TAG_POLYMORPHIC_VARIANT &&
unsafe { $self.field::<$crate::OCamlInt>(0).raw() } == $tag {
let ($($slot_name),+) = unsafe { $self.field::<($($slot_typ),+)>(1).to_rust() };
return Ok($conv);
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! ocaml_closure_reference {
($var:ident, $name:ident) => {
static NAME: &str = stringify!($name);
static mut OC: Option<$crate::internal::OCamlClosure> = None;
static INIT: ::std::sync::Once = ::std::sync::Once::new();
let $var = unsafe {
INIT.call_once(|| {
OC = $crate::internal::OCamlClosure::named(NAME);
});
OC.unwrap_or_else(|| panic!("OCaml closure with name '{}' not registered", NAME))
};
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! default_to_unit {
() => {
()
};
($rtyp:ty) => {
$rtyp
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! polymorphic_variant_tag_hash {
($prefix:ident::$($tag:ident)::+) => {
$crate::polymorphic_variant_tag_hash!($($tag)::+)
};
($tag:ident) => {{
static mut TAG_HASH: $crate::RawOCaml = 0;
static INIT_TAG_HASH: std::sync::Once = std::sync::Once::new();
unsafe {
INIT_TAG_HASH.call_once(|| {
TAG_HASH =
$crate::internal::caml_hash_variant(concat!(stringify!($tag), "\0").as_ptr())
});
TAG_HASH
}
}};
}