1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
//! 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:
//!
//! ```rust
//! #[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:
//!
//! ```rust
//! #[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:
//!
//! ```OCaml
//! 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
//! ```
//!


pub mod mlvalues;
pub mod memory;
pub mod alloc;
pub mod callback;