Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

helper to define functions and custom types #124

Open
mimoo opened this issue Mar 23, 2023 · 0 comments
Open

helper to define functions and custom types #124

mimoo opened this issue Mar 23, 2023 · 0 comments

Comments

@mimoo
Copy link
Contributor

mimoo commented Mar 23, 2023

just making the suggestion here as I don't have time to make a PR these days. In my codebase I'm using a macro to more easily define a bunch of functions:

impl_functions! {
  // my functions
}

the implementation is pretty simple:

/// add the necessary attributes to all the functions listed.
macro_rules! impl_functions {
    ($fn: item) => {
        #[ocaml_gen::func]
        #[ocaml::func]
        $fn
    };
    ($fn: item $($fns: item)*) => {
        impl_functions!($fn);
        impl_functions!($($fns)*);
    };
}

the same for custom types that need to be wrappers (for foreign types)

// to implement a custom
impl_custom!(NameOfWrapper, WrappedType);
impl_custom!(NameOfWrapper2, WrappedType2, Debug, Display); // additional impl to derive

// or if I know the wrapped type implements clone (not always the case):
impl_custom_clone!(ClonableWrapper, ClonableWrappedType);

implementation:

/// Implement a custom wrapper type with a given number of optional traits to derive on the type.
macro_rules! impl_custom {
    ($name: ident, $typ: ty) => {
        impl_custom!($name, $typ,);
    };
    ($name: ident, $typ: ty, $($trait: ident),*) => {
        #[derive(ocaml_gen::CustomType, $($trait),*)]
        pub struct $name(pub $typ);

        impl $name {
            extern "C" fn caml_pointer_finalize(v: ocaml::Raw) {
                unsafe {
                    let v: ocaml::Pointer<$name> = v.as_pointer();
                    v.drop_in_place();
                }
            }

            extern "C" fn caml_pointer_compare(_: ocaml::Raw, _: ocaml::Raw) -> i32 {
                panic!("comparing custom types is not supported");
            }
        }

        ocaml::custom!($name {
            finalize: $name::caml_pointer_finalize,
            compare: $name::caml_pointer_compare,
        });

        impl std::ops::Deref for $name {
            type Target = $typ;

            fn deref(&self) -> &Self::Target {
                &self.0
            }
        }
    };
}

/// Same as `impl_custom`, but also implements `FromValue` for the type.
/// It only works if the inner type is `Clone`.
macro_rules! impl_custom_clone {
    ($name: ident, $typ: ty) => {
        impl_custom_clone!($name, $typ,);
    };
    ($name: ident, $typ: ty, $($trait: ident),*) => {
        #[derive(ocaml_gen::CustomType, Clone, $($trait),*)]
        pub struct $name(pub $typ);

        impl $name {
            extern "C" fn caml_pointer_finalize(v: ocaml::Raw) {
                unsafe {
                    let v: ocaml::Pointer<$name> = v.as_pointer();
                    v.drop_in_place();
                }
            }

            extern "C" fn caml_pointer_compare(_: ocaml::Raw, _: ocaml::Raw) -> i32 {
                panic!("comparing custom types is not supported");
            }
        }

        ocaml::custom!($name {
            finalize: $name::caml_pointer_finalize,
            compare: $name::caml_pointer_compare,
        });

        impl std::ops::Deref for $name {
            type Target = $typ;

            fn deref(&self) -> &Self::Target {
                &self.0
            }
        }

        unsafe impl<'a> ocaml::FromValue<'a> for $name {
            fn from_value(value: ocaml::Value) -> Self {
                let x: ocaml::Pointer<Self> = ocaml::FromValue::from_value(value);
                x.as_ref().clone()
            }
        }
    };
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant