This crate provides automatic generation of OCaml bindings. Refer to the rustdoc for more information.
Here's an example of generating some bindings. Create a main.rs
as:
```rust use ocaml_gen::prelude::*;
// Some Rust code you have:
pub struct SomeType { pub a: u8, }
fn createsometype() -> SomeType { SomeType { a: 42 } }
fn main() { // initialize your environment let env = &mut Env::default();
// choose where you want to write the bindings let w = &mut std::io::stdout();
// you can declare modules
declmodule!(w, env, "Types", {
// and types
decltype!(w, env, SomeType => "t");
});
declmodule!(w, env, "Functions", { // and functions declfunc!(w, env, createsometype => "create"); }); } ```
Note that the underlying function imported by decl_func!
is actually caml_of_numeral_to_ocaml
, which is created by the annotated macro ocaml_gen::func
.
So either your function is in scope, or you import everything (e.g. use path::*
), or you import the derived function directly (e.g. use path::caml_of_numeral_to_ocaml
).
The OCaml bindings generated should look like this:
```ocaml,ignore module Types = struct type nonrec t end
module Functions = struct val create : unit -> Types.t end ```
In general, you can use this library by following these steps:
ocaml-rs
and ocaml_gen
macros.main.rs
file to generate your binding file bindings.ml
as shown above.ocaml-rs
crate to export the static library that OCaml will use.dune
file to your crate to build the Rust static library as well as the OCaml bindings. (protip: use (mode promote)
in the dune file to have the resulting binding file live within the folder.)You can see an example of these steps in the test/ folder. (Although we don't "promote" the file with dune for testing purposes.)
To allow ocaml-gen to understand how to generate OCaml bindings from your types and functions, you must annotate them using ocaml-gen's macros.
To allow generation of bindings on structs, use ocaml_gen::Struct
:
```rust,ignore
struct MyType { // ... } ```
To allow generation of bindings on enums, use ocaml_gen::Enum
:
```rust,ignore
enum MyType { // ... } ```
To allow generation of bindings on functions, use ocaml_gen::func
:
```rust,ignore
pub fn your_function(arg1: String) { //... } ```
To allow generation of bindings on custom types, use ocaml_gen::CustomType
:
```rust,ignore
struct MyCustomType { // ... } ```
To generate bindings, you must create a main.rs
file that uses the ocaml_gen
crate functions to layout what the bindings .ml
file will look like.
The first thing to do is to import the types and functions you want to generate bindings for, as well as the ocaml_gen
macros:
rust,ignore
use ocaml_gen::prelude::*;
use your_crate::*;
You can then use decl_module!
to declare modules:
```rust,ignore let env = &mut Env::default(); let w = &mut std::io::stdout();
declmodule!(w, env, "T1", {
declmodule!(w, env, "T2", {
decl_type!(w, env, SomeType);
});
});
declmodule!(w, env, "T3", { decltype!(w, env, SomeOtherType); }); ```
You can rename types and functions by simply adding an arrow:
rust,ignore
decl_type!(w, env, SomeType => "t");
You can also declare generic types by first declaring the generic type parameters (that you must reuse for all generic types):
```rust,ignore declfakegeneric!(T1, 0); // danger: declfakegeneric!(T2, 1); // make sure you declfakegeneric!(T3, 2); // increment these correctly
decltype!(w, env, TypeWithOneGenericType
You can also create type aliases with the decl_type_alias!
macro but it is highly experimental.
It has a number of issues:
Thing<usize>
to t1
, eventhough t1
was an alias to Thing<String>
(this is the main danger, see this tracking issue)t1
is the alias of Thing<usize>
and t2
is the alias of Thing<String>
)