Crate raml [] [src]

Raml is a library for directly interacting with the C OCaml runtime, in Rust. Consquently, raml is designed for rust shared objects that expose raw C FFI bindings, which are then either statically or dynamically linked against an OCaml binary, which calls into these raw FFI bindings as if they were regular, so-called "C stubs". Similarly, any OCaml runtime functions, such as caml_string_length, will get their definition from the final OCaml binary, with its associated runtime.

The benefit of this approach is that it removes any bridging C code, and allows in essence, a direct interface between Rust and OCaml.

The macro has the format: (name, |params...|, <local variables..>, { // code body }, -> optional return value listed in local variables)

A basic example demonstrates their usage:

#[macro_use] extern crate raml;

// linking against this rust static lib, you can access this function in OCaml via:
// `external beef : int -> int = "ml_beef"`
caml!(ml_beef, |parameter|, <local>, {
    let i = int_val!(parameter);
    let res = 0xbeef * i;
    println!("about to return  0x{:x} to OCaml runtime", res);
    local = val_int!(res);
} -> local);

// this is only here to satisfy docs
fn main() {}

The macro takes care of automatically declaring CAMLparam et. al, as well as CAMLlocal and CAMLreturn.

If you need more fine grained control, caml_body! and others are available.

Some more examples:

#[macro_use] extern crate raml;

// these are two functions that OCaml code can access via `external val` declarations
caml!(ml_send_int, |v, v2|, <l>, {
    let x = int_val!(v);
    l = val_int!(0xbeef);
    println!("send_int  0x{:x}", x);
    // io::stdout().flush();
} -> l);

caml!(ml_send_two, |v, v2|, {
    println!("local root addr: {:p} caml_local_roots: {:#?}, v: {:?}", &raml::memory::caml_local_roots, raml::memory::caml_local_roots, v);
    let x = int_val!(v);
    let len = raml::mlvalues::caml_string_length(v2);
    let ptr = string_val!(v2);
    let slice = ::std::slice::from_raw_parts(ptr, len);
    let string = ::std::str::from_utf8_unchecked(slice);
    println!("got  0x{:x}, {}", x, string);

// this is only here to satisfy docs, you will likely want a staticlib, not a rust executable
fn main() {}

These will be accessible to an OCaml program via external declarations, e.g., for the above we could do something like:

external send_int : int -> int = "ml_send_int"
external send_two : int -> string -> unit = "ml_send_two"

let f x = x land 0x0000ffff

let _ =
  let string = "string thing" in
  let deadbeef = 0xdeadbeef in
  let res = send_int 0xb1b1eb0b in
  Printf.printf "send_int returned: 0x%x\n" res;
  flush stdout;
  send_two deadbeef string;
  send_two (f deadbeef) string



External definitions for allocating values in the OCaml runtime


Callbacks from C to OCaml This is also where you initialize the OCaml runtime system via caml_startup or caml_main


Defines types and macros primarily for interacting with the OCaml GC. In addition, a few extra convenience macros are added, in particular, caml! and caml_body! which are the primary API endpoints of raml.


Contains OCaml types and conversion functions from runtime representations.



Pointer to the first byte


Defines an external Rust function for FFI use by an OCaml program, with automatic CAMLparam, CAMLlocal, and CAMLreturn inserted for you.


Defines an OCaml FFI body, including any locals, as well as a return if provided; it is up to you to define the parameters.


Initializes and registers the given identifier(s) as a local value with the OCaml runtime.


Registers OCaml parameters with the GC


Extracts from the $block an OCaml value at the $ith-field


Converts an OCaml int into a usize


Long_val(x) ((x) >> 1)


Returns an OCaml unit value


Stores the $val at $offset in the $block.


Extracts a machine ptr to the bytes making up an OCaml string


Converts a machine usize into an OCaml int


(((intnat)(x) << 1) + 1)